adding gui for the application
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user