adding gui for the application

This commit is contained in:
2026-09-18 11:11:59 -04:00
parent ff7aa065e3
commit 256e87c8c8
47 changed files with 4398 additions and 12055 deletions
+131
View File
@@ -0,0 +1,131 @@
import { useEffect, useMemo, useState } from "react";
import { getWeekSchedule } from "@api/scheduleApi";
import { getUsers } from "@api/usersApi";
import { PageHeader } from "@components/PageHeader";
import type { BackendPreference } from "@/types/backend";
import type { Schedule } from "@/types/schedule";
import type { DayOfWeek, Employee } from "@/types/users";
import styles from "./SchedulePage.module.scss";
type SchedulePageProps = {
backendPreference: BackendPreference;
};
const weekDays: DayOfWeek[] = [
"sunday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
];
function formatDay(day: DayOfWeek): string {
return day.charAt(0).toUpperCase() + day.slice(1);
}
function formatTime(value: string | null): string {
if (!value) {
return "Not registered";
}
return new Date(value).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
}
export function SchedulePage({ backendPreference }: SchedulePageProps) {
const [schedules, setSchedules] = useState<Schedule[]>([]);
const [users, setUsers] = useState<Employee[]>([]);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
const schedulesByDay = useMemo(() => {
return schedules.reduce<Record<DayOfWeek, Schedule[]>>(
(accumulator, schedule) => {
accumulator[schedule.day_of_week] = [...accumulator[schedule.day_of_week], schedule];
return accumulator;
},
{
sunday: [],
monday: [],
tuesday: [],
wednesday: [],
thursday: [],
friday: [],
saturday: [],
},
);
}, [schedules]);
useEffect(() => {
let isMounted = true;
async function loadSchedule() {
setError("");
setIsLoading(true);
try {
const [scheduleResponse, usersResponse] = await Promise.all([
getWeekSchedule(backendPreference),
getUsers(backendPreference),
]);
if (isMounted) {
setSchedules(scheduleResponse.schedules);
setUsers(usersResponse);
}
} catch (loadError) {
if (isMounted) {
setError(loadError instanceof Error ? loadError.message : "Unable to load schedule");
}
} finally {
if (isMounted) {
setIsLoading(false);
}
}
}
void loadSchedule();
return () => {
isMounted = false;
};
}, [backendPreference]);
return (
<>
<PageHeader
title="Schedule"
description="Weekly scheduler calendar starts on Sunday and ends on Saturday so you can see who is working each day."
/>
{error ? <p className={styles.error}>{error}</p> : null}
{isLoading ? <p className={styles.muted}>Loading schedule...</p> : null}
<section className={styles.calendar} aria-label="Weekly schedule from Sunday to Saturday">
{weekDays.map((day) => (
<article className={styles.dayCard} key={day}>
<h3>{formatDay(day)}</h3>
<div className={styles.shiftList}>
{schedulesByDay[day].length > 0 ? (
schedulesByDay[day].map((schedule) => {
const user = users.find((item) => item.id === schedule.user_id);
return (
<div className={styles.shift} key={schedule.id}>
<strong>
{user ? `${user.name} ${user.last_name}` : `User #${schedule.user_id}`}
</strong>
<span>
{formatTime(schedule.enter_time)} - {formatTime(schedule.out_time)}
</span>
</div>
);
})
) : (
<p className={styles.muted}>No shifts scheduled</p>
)}
</div>
</article>
))}
</section>
</>
);
}