From a043b3cf515ee5c1901c42d55e88d6b9c618c99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Lauk=C3=B6tter?= Date: Tue, 12 Dec 2023 10:18:00 +0100 Subject: [PATCH] Add week view Also fixed a bug in the troi controller that stopped the cache from working --- .talismanrc | 3 +- app/components/WeekView.tsx | 220 +++++++++++++++++++++++++++++++++ app/components/troi.client.tsx | 12 ++ app/routes/projects.tsx | 8 ++ app/troi/troiController.ts | 6 +- 5 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 app/components/WeekView.tsx diff --git a/.talismanrc b/.talismanrc index bd6ed741..1021f183 100644 --- a/.talismanrc +++ b/.talismanrc @@ -14,7 +14,7 @@ fileignoreconfig: - filename: app/routes/login.tsx allowed_patterns: [password] - filename: app/components/troi.client.tsx - allowed_patterns: [password, /wiki/spaces/DIGITALSER/pages/\d+] + allowed_patterns: [password, /wiki/spaces/\w+/pages/\d+] - filename: app/routes/projects.tsx allowed_patterns: [password] - filename: app/troi/useTroi.hook.tsx @@ -26,3 +26,4 @@ scopeconfig: - scope: node allowed_patterns: - uses:\ ([A-z0-9\-]+\/)*[A-z0-9\-]+@[a-fA-F0-9]{40} + - key diff --git a/app/components/WeekView.tsx b/app/components/WeekView.tsx new file mode 100644 index 00000000..075f45fd --- /dev/null +++ b/app/components/WeekView.tsx @@ -0,0 +1,220 @@ +import { getItemForEventType } from "~/utils/calendarEventUtils"; +import { + addDaysToDate, + datesEqual, + getWeekDaysFor, + getWeekNumberFor, +} from "~/utils/dateUtils"; +import { convertFloatTimeToHHMM } from "~/utils/timeConverter"; +import { TransformedCalendarEvent } from "~/utils/transformCalendarEvents"; + +interface Props { + timesAndEventsOfSelectedWeek: { + hours: number; + events: TransformedCalendarEvent[]; + }[]; + selectedDate: Date; + onSelectDate: (newDate: Date) => unknown; +} + +export function WeekView({ + timesAndEventsOfSelectedWeek, + selectedDate, + onSelectDate, +}: Props) { + const weekdays = ["M", "T", "W", "T", "F"]; + const selectedWeek = getWeekDaysFor(selectedDate); + + function changeWeek(direction: -1 | 1) { + onSelectDate(addDaysToDate(selectedDate, 7 * direction)); + } + + function getDateClassNames(index: number, selectedDate: Date) { + let dateClasses = "flex h-8 w-8 items-center justify-center rounded-full "; + let date = selectedWeek[index]; + + if (datesEqual(date, new Date())) { + dateClasses += "outline-none ring-2 ring-black ring-offset-2 "; + } + + if (datesEqual(date, selectedDate)) { + dateClasses += "bg-blue-600 text-white hover:bg-blue-700 "; + } else { + dateClasses += "text-black hover:bg-[#B8BDC3] "; + } + + return dateClasses; + } + + function getIconForEvent(event: TransformedCalendarEvent) { + if (event === undefined) { + return undefined; + } + + return getItemForEventType(event.type); + } + + return ( +
+
+
+
+
+
+ +
+ Week {getWeekNumberFor(selectedDate)} +
+ + +
+
+ {selectedDate.toLocaleDateString("en-gb", { + weekday: "long", + year: "numeric", + month: "long", + day: "numeric", + })} +
+
+ +
+
+ + + + {weekdays.map((weekday, index) => ( + + ))} + + + + + {selectedWeek.map((date, index) => ( + + ))} + + + {timesAndEventsOfSelectedWeek.map((data, index) => ( + + ))} + + +
+
+

+ {weekday} +

+
+
+
onSelectDate(date)} + > +
+

+ {date.getDate()} +

+
+
+
+
onSelectDate(selectedWeek[index])} + > + {data.events.length && + getIconForEvent(data.events[0]) ? ( + + {getIconForEvent(data.events[0])} + + ) : ( +

+ {convertFloatTimeToHHMM(data.hours)} +

+ )} +
+
+
+
+
+
+
+
+ ); +} diff --git a/app/components/troi.client.tsx b/app/components/troi.client.tsx index db161c6c..3cec6664 100644 --- a/app/components/troi.client.tsx +++ b/app/components/troi.client.tsx @@ -3,6 +3,8 @@ import { LoadingOverlay } from "./LoadingOverlay"; import { useEffect, useState } from "react"; import { TimeEntry } from "troi-library"; import { InfoBanner } from "./InfoBanner"; +import { getWeekDaysFor } from "~/utils/dateUtils"; +import { WeekView } from "./WeekView"; interface Props { username: string; @@ -16,6 +18,7 @@ export default function Troi(props: Props) { ); const [selectedDate, setSelectedDate] = useState(() => new Date()); + const selectedWeek = getWeekDaysFor(selectedDate); const [entriesForSelectedDate, setEntriesForSelectedDate] = useState<{ [projectId: number]: TimeEntry[]; @@ -30,6 +33,8 @@ export default function Troi(props: Props) { }, [troiController, initialized, selectedDate]); const selectedDayEvents = troiController?.getEventsFor(selectedDate); + const timesAndEventsOfSelectedWeek = + troiController?.getTimesAndEventsFor(selectedWeek) ?? []; return (
@@ -44,6 +49,13 @@ export default function Troi(props: Props) { Read about how to track your time in confluence +
+ +
{selectedDayEvents?.map((event) => )} diff --git a/app/routes/projects.tsx b/app/routes/projects.tsx index 7c8833f5..9135ef66 100644 --- a/app/routes/projects.tsx +++ b/app/routes/projects.tsx @@ -1,5 +1,6 @@ import { json, + LinksFunction, type LoaderFunctionArgs, type MetaFunction, } from "@remix-run/node"; @@ -23,6 +24,13 @@ export const meta: MetaFunction = () => { ]; }; +export const links: LinksFunction = () => [ + { + rel: "stylesheet", + href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200", + }, +]; + export async function loader({ request }: LoaderFunctionArgs) { const cookieHeader = request.headers.get("Cookie"); const cookie = (await login.parse(cookieHeader)) || {}; diff --git a/app/troi/troiController.ts b/app/troi/troiController.ts index 818fbed6..2e574471 100644 --- a/app/troi/troiController.ts +++ b/app/troi/troiController.ts @@ -169,12 +169,12 @@ export default class TroiController { this._cacheBottomBorder = new Date( Math.min( - new Date(this._cacheBottomBorder).getDate(), - startDate.getDate(), + new Date(this._cacheBottomBorder).getTime(), + startDate.getTime(), ), ); this._cacheTopBorder = new Date( - Math.max(new Date(this._cacheTopBorder).getDate(), endDate.getDate()), + Math.max(new Date(this._cacheTopBorder).getTime(), endDate.getTime()), ); }