Skip to content

Commit

Permalink
Add week view
Browse files Browse the repository at this point in the history
Also fixed a bug in the troi controller that stopped the cache from working
  • Loading branch information
malte-laukoetter committed Dec 12, 2023
1 parent ad590f7 commit a043b3c
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,3 +26,4 @@ scopeconfig:
- scope: node
allowed_patterns:
- uses:\ ([A-z0-9\-]+\/)*[A-z0-9\-]+@[a-fA-F0-9]{40}
- key
220 changes: 220 additions & 0 deletions app/components/WeekView.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex p-4">
<div className="w-full">
<div>
<div className="flex flex-wrap gap-8">
<div className="min-w-[30ch]">
<div className="mb-3 flex items-center">
<button
data-testid="btn-previous-week"
aria-label="calendar backward"
className="-ml-1.5 flex items-center justify-center text-gray-600 hover:text-gray-400"
onClick={() => changeWeek(-1)}
>
<span className="material-symbols-outlined">
{" "}
chevron_left{" "}
</span>
</button>
<div
tabIndex={0}
className="min-w-[9ch] px-2 text-center text-sm text-gray-600 focus:outline-none"
>
Week {getWeekNumberFor(selectedDate)}
</div>
<button
data-testid="btn-next-week"
aria-label="calendar forward"
className="flex items-center justify-center text-gray-600 hover:text-gray-400"
onClick={() => changeWeek(1)}
>
<span className="material-symbols-outlined">
{" "}
chevron_right{" "}
</span>
</button>
<button
data-testid="btn-today"
aria-label="today"
className="min-w-[7ch] text-center font-bold text-blue-600 hover:text-blue-700"
onClick={() => {
onSelectDate(new Date());
}}
>
Today
</button>
</div>
<div
data-testid="date"
tabIndex={0}
className="text-base font-bold text-gray-800 focus:outline-none"
>
{selectedDate.toLocaleDateString("en-gb", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
})}
</div>
</div>

<div className="rounded-t bg-white">
<div className="flex items-center justify-between">
<table className="w-full">
<thead>
<tr>
{weekdays.map((weekday, index) => (
<th key={index}>
<div className="flex w-full justify-center">
<p className="text-center text-base font-medium text-gray-600">
{weekday}
</p>
</div>
</th>
))}
</tr>
</thead>
<tbody>
<tr>
{selectedWeek.map((date, index) => (
<td key={index}>
<div
className="h-full w-full"
data-testid={
[
"btn-mon",
"btn-tue",
"btn-wed",
"btn-thu",
"btn-fri",
][index]
}
onClick={() => onSelectDate(date)}
>
<div className="flex w-full cursor-pointer items-center justify-center rounded-full px-2 py-2 text-base font-medium">
<p
className={getDateClassNames(
index,
selectedDate,
)}
>
{date.getDate()}
</p>
</div>
</div>
</td>
))}
</tr>
<tr>
{timesAndEventsOfSelectedWeek.map((data, index) => (
<td key={index}>
<div
className="flex min-w-[6ch] cursor-pointer justify-center px-2 py-2"
onClick={() => onSelectDate(selectedWeek[index])}
>
{data.events.length &&
getIconForEvent(data.events[0]) ? (
<span
data-testid={
[
"event-mon",
"event-tue",
"event-wed",
"event-thu",
"event-fri",
][index]
}
className="material-symbols-outlined"
>
{getIconForEvent(data.events[0])}
</span>
) : (
<p
data-testid={
[
"hours-mon",
"hours-tue",
"hours-wed",
"hours-thu",
"hours-fri",
][index]
}
className={`text-base font-medium ${
data.hours == 0
? "text-gray-500"
: "text-blue-600"
}`}
>
{convertFloatTimeToHHMM(data.hours)}
</p>
)}
</div>
</td>
))}
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
12 changes: 12 additions & 0 deletions app/components/troi.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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[];
Expand All @@ -30,6 +33,8 @@ export default function Troi(props: Props) {
}, [troiController, initialized, selectedDate]);

const selectedDayEvents = troiController?.getEventsFor(selectedDate);
const timesAndEventsOfSelectedWeek =
troiController?.getTimesAndEventsFor(selectedWeek) ?? [];

return (
<div>
Expand All @@ -44,6 +49,13 @@ export default function Troi(props: Props) {
Read about how to track your time in confluence
</a>
</section>
<section className="z-10 w-full bg-white md:sticky md:top-0">
<WeekView
timesAndEventsOfSelectedWeek={timesAndEventsOfSelectedWeek}
selectedDate={selectedDate}
onSelectDate={setSelectedDate}
/>
</section>

{selectedDayEvents?.map((event) => <InfoBanner event={event} />)}

Expand Down
8 changes: 8 additions & 0 deletions app/routes/projects.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
json,
LinksFunction,
type LoaderFunctionArgs,
type MetaFunction,
} from "@remix-run/node";
Expand All @@ -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,[email protected],100..700,0..1,-50..200",
},
];

export async function loader({ request }: LoaderFunctionArgs) {
const cookieHeader = request.headers.get("Cookie");
const cookie = (await login.parse(cookieHeader)) || {};
Expand Down
6 changes: 3 additions & 3 deletions app/troi/troiController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
);
}

Expand Down

0 comments on commit a043b3c

Please sign in to comment.