Skip to content

Commit

Permalink
Merge pull request #43 from cabcookie/group-projects
Browse files Browse the repository at this point in the history
# Projekte gruppieren

## Neue Funktionen und Änderungen

- Die Ansicht in der App ist stabilisiert worden und zoomt nicht mehr in Eingabefelder ([#40](#40))
- Projektlisten lassen sich jetzt filtern nach Work In Progress, On Hold und Done ([#41](#41))
- Bei Aktivitäten kann nun das Datum geändert werden.
- In der Navigation kann nun auch zu Projekten und Accounts gewechselt werden. Mit ^+p und ^+a kann man auch direkt hinspringen.
  • Loading branch information
cabcookie authored Apr 29, 2024
2 parents d2296cd + 8533da8 commit da5a7a8
Show file tree
Hide file tree
Showing 16 changed files with 350 additions and 177 deletions.
19 changes: 19 additions & 0 deletions api/useActivity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ const useActivity = (activityId?: string) => {
mutate: mutateActivity,
} = useSWR(`/api/activities/${activityId}`, fetchActivity(activityId));

const updateDate = async (date: Date) => {
if (!activity) return;
const updated: Activity = {
...activity,
finishedOn: date,
updatedAt: new Date(),
};
mutateActivity(updated, false);
const { data, errors } = await client.models.Activity.update({
id: activity.id,
finishedOn: date.toISOString(),
});
if (errors) handleApiErrors(errors, "Error updating date of activity");

mutateActivity(updated);
return data.id;
};

const updateNotes = async (notes: string) => {
if (!activity?.id) return;
const updated: Activity = { ...activity, notes, updatedAt: new Date() };
Expand Down Expand Up @@ -102,6 +120,7 @@ const useActivity = (activityId?: string) => {
errorActivity,
updateNotes,
addProjectToActivity,
updateDate,
};
};

Expand Down
14 changes: 14 additions & 0 deletions components/CategoryTitle.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
}
}

.content {
position: sticky;
top: 5rem;
background-color: var(--color-bg-sheet-transparent);
z-index: 20;
}

@media (max-width: 40em) {
.content {
top: 4rem;
padding-bottom: 1rem;
}
}

.content h1,
.content textarea {
font-size: var(--font-size-xx-large);
Expand Down
23 changes: 18 additions & 5 deletions components/activities/activity.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { FC, useState } from "react";
import { FC, useEffect, useState } from "react";
import { Descendant } from "slate";
import { TransformNotesToMdFunction } from "../ui-elements/notes-writer/notes-writer-helpers";
import { debouncedUpdateNotes } from "../ui-elements/activity-helper";
import useActivity from "@/api/useActivity";
import { toLocaleDateTimeString } from "@/helpers/functional";
import ProjectName from "../ui-elements/tokens/project-name";
import MeetingName from "../ui-elements/tokens/meeting-name";
import NotesWriter from "../ui-elements/notes-writer/NotesWriter";
import ActivityMetaData from "../ui-elements/activity-meta-data";
import DateSelector from "../ui-elements/date-selector";
import SavedState from "../ui-elements/project-notes-form/saved-state";

type ActivityComponentProps = {
activityId: string;
Expand All @@ -26,9 +27,14 @@ const ActivityComponent: FC<ActivityComponentProps> = ({
autoFocus,
createActivity,
}) => {
const { activity, updateNotes } = useActivity(activityId);
const { activity, updateNotes, updateDate } = useActivity(activityId);
const [notesSaved, setNotesSaved] = useState(true);
const [dateSaved, setDateSaved] = useState(true);
const [date, setDate] = useState(activity?.finishedOn || new Date());

useEffect(() => {
setDate(activity?.finishedOn || new Date());
}, [activity]);
const handleNotesUpdate = (
notes: Descendant[],
transformerFn: TransformNotesToMdFunction
Expand All @@ -43,12 +49,19 @@ const ActivityComponent: FC<ActivityComponentProps> = ({
});
};

const handleDateUpdate = async (date: Date) => {
setDateSaved(false);
setDate(date);
const data = await updateDate(date);
if (data) setDateSaved(true);
};

return (
<div style={{ marginBottom: "2rem" }}>
{showDates && (
<h2>
{toLocaleDateTimeString(activity?.finishedOn) ||
"Create new activity"}
<DateSelector date={date} setDate={handleDateUpdate} selectHours />
<SavedState saved={dateSaved} />
</h2>
)}
{showProjects &&
Expand Down
58 changes: 0 additions & 58 deletions components/navigation-menu/ContextSwitcher.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,3 @@
font-weight: bold;
margin-bottom: 0.5rem;
}

.switcher {
--border-radius: 1.2rem;
--border-thick: 1px;
display: flex;
position: relative;
border: var(--border-thick) solid rgb(198, 195, 195);
font-size: var(--font-size-small);
border-radius: var(--border-radius);
width: 100%;
justify-content: space-around;
background: none;
transition: background-color 0.3s ease;
}

@media (max-width: 40em) {
.switcher {
--border-radius: 0.8rem;
font-size: var(--font-size-x-small);
}
}

.context {
--context-padding: 0.1rem;
flex-grow: 1;
text-align: center;
cursor: pointer;
padding-top: var(--context-padding);
padding-bottom: var(--context-padding);
transition: color 0.3s ease;
color: var(--context-color);
position: relative;
text-transform: capitalize;
}

@media (max-width: 40em) {
.context {
--context-padding: 0rem;
}
}

.highlighter {
position: absolute;
height: calc(100% + var(--border-thick) * 2);
top: calc(var(--border-thick) * -1);
left: 0;
border-radius: var(--border-radius);
transition: transform 0.3s ease, background-color 0.3s ease;
}

.context:hover {
color: var(--context-color-hover);
}

.isActive,
.isActive:hover {
color: white;
}
72 changes: 10 additions & 62 deletions components/navigation-menu/ContextSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,20 @@
import {
CSSProperties,
FC,
MutableRefObject,
useEffect,
useRef,
useState,
} from "react";
import { FC, useEffect, useState } from "react";
import styles from "./ContextSwitcher.module.css";
import contextStyles from "../layouts/ContextColors.module.css";
import { Context, useContextContext } from "@/contexts/ContextContext";
import SelectionSlider from "../ui-elements/selection-slider/selection-slider";

export const contexts: Context[] = ["family", "hobby", "work"];

const moveSlider = (
setHighlighterStyle: (style: CSSProperties) => void,
contextRef: MutableRefObject<HTMLDivElement[]>,
context?: Context
) => {
const activeIndex = contexts.findIndex((c) => c === context);
const activeElement = contextRef.current[activeIndex];

if (activeElement) {
const { offsetWidth: width, offsetLeft: left } = activeElement;
const innerOffset = contextRef.current[0].offsetLeft + 2;
setHighlighterStyle({
width: `${width + innerOffset * 2}px`,
transform: `translateX(${left - innerOffset}px)`,
backgroundColor: `var(--${context}-color-main)`,
});
}
};

type ContextSwitcherProps = {
context?: Context;
};

const ContextSwitcher: FC<ContextSwitcherProps> = ({ context }) => {
const [highlighterStyle, setHighlighterStyle] = useState({});
const { setContext } = useContextContext();
const contextRef = useRef<HTMLDivElement[]>([]);

useEffect(
() => moveSlider(setHighlighterStyle, contextRef, context),
[context]
);
const [btnColor, setBtnColor] = useState(`var(--${context}-color-main)`);

useEffect(() => {
const listener = () => moveSlider(setHighlighterStyle, contextRef, context);
window.addEventListener("resize", listener);
return () => window.removeEventListener("resize", listener);
}, [context]);
useEffect(() => setBtnColor(`var(--${context}-color-main)`), [context]);

return (
<div
Expand All @@ -58,29 +23,12 @@ const ContextSwitcher: FC<ContextSwitcherProps> = ({ context }) => {
}`}
>
<div className={styles.title}>Switch Context:</div>
<button className={styles.switcher}>
<div className={styles.highlighter} style={highlighterStyle} />
{contexts.map((val, idx) => (
<div
key={idx}
ref={(el) => {
if (el) contextRef.current[idx] = el;
}}
className={`${styles.context} ${
val === context ? styles.isActive : ""
}`}
style={
{
"--context-color": `var(--${val}-color-text-secondary)`,
"--context-color-hover": `var(--${val}-color-btn)`,
} as CSSProperties
}
onClick={() => setContext(val)}
>
{val}
</div>
))}
</button>
<SelectionSlider
valueList={contexts}
value={context || "family"}
onChange={setContext}
btnColor={btnColor}
/>
</div>
);
};
Expand Down
4 changes: 4 additions & 0 deletions components/navigation-menu/NavigationMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ContextSwitcher from "./ContextSwitcher";
import MainNavigationSection from "./MainNavigationSection";
import styles from "./NavigationMenu.module.css";
import { Context } from "@/contexts/ContextContext";
import OtherNavigationSection from "./OtherNavigationSection";

type NavigationMenuProps = {
context?: Context;
Expand All @@ -18,6 +19,9 @@ const NavigationMenu = forwardRef<HTMLDivElement, NavigationMenuProps>(
<div className={styles.navigationSection}>
<MainNavigationSection context={context} />
</div>
<div className={styles.navigationSection}>
<OtherNavigationSection context={context} />
</div>
</div>
);
}
Expand Down
34 changes: 34 additions & 0 deletions components/navigation-menu/OtherNavigationSection.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.wrapper {
display: flex;
flex-direction: column;
width: 100%;
justify-content: center;
align-items: center;
gap: 0.6rem;
}

.menuItem {
border-radius: 0.4rem;
text-align: center;
padding: 0.6rem;
width: 100%;
border: none;
background-color: var(--color-btn);
box-shadow: none;
color: var(--color-text);
text-decoration: none;
transition: background-color 1s ease, color 1s ease;
font-weight: bold;
}

.menuItem:hover {
filter: brightness(98%);
box-shadow: 2px 2px 8px rgba(89, 88, 88, 0.344);
}

@media (max-width: 24.999em) {
.menuItem {
font-size: var(--font-size-xx-small);
font-weight: normal;
}
}
40 changes: 40 additions & 0 deletions components/navigation-menu/OtherNavigationSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Context } from "@/contexts/ContextContext";
import { FC } from "react";
import styles from "./OtherNavigationSection.module.css";
import contextStyles from "@/components/layouts/ContextColors.module.css";
import Link from "next/link";

type OtherNavigationSectionProps = {
context?: Context;
};

type MenuItem = {
name: string;
link: string;
};

const menuItems: MenuItem[] = [
{ name: "Projects", link: "/projects" },
{ name: "Accounts", link: "/accounts" },
// { name: "People", link: "/people" },
];

const OtherNavigationSection: FC<OtherNavigationSectionProps> = ({
context,
}) => {
return (
<div
className={`${
context ? contextStyles[`${context}ColorScheme`] : styles.noColorScheme
} ${styles.wrapper}`}
>
{menuItems.map(({ name, link }, idx) => (
<Link className={styles.menuItem} key={idx} href={link}>
{name}
</Link>
))}
</div>
);
};

export default OtherNavigationSection;
Loading

0 comments on commit da5a7a8

Please sign in to comment.