chore: update

This commit is contained in:
TakahashiNg
2026-05-14 03:05:54 +00:00
parent 427642e08f
commit 18c5c8e266
8 changed files with 35 additions and 37 deletions
@@ -44,9 +44,7 @@ export default function MobileShiftView({
onShiftClick, onShiftClick,
}: MobileShiftViewProps) { }: MobileShiftViewProps) {
const { currentDate, shifts, goToNextMonth, goToPrevMonth } = useShift(); const { currentDate, shifts, goToNextMonth, goToPrevMonth } = useShift();
const [selectedDate, setSelectedDate] = useState<string>( const [selectedDate, setSelectedDate] = useState<Date>(new Date(2026, 3, 10));
formatDateISO(new Date(2026, 3, 10)),
);
const calendarDays = useMemo(() => { const calendarDays = useMemo(() => {
const year = currentDate.getFullYear(); const year = currentDate.getFullYear();
@@ -67,8 +65,7 @@ export default function MobileShiftView({
}, [currentDate]); }, [currentDate]);
const getDotColors = (date: Date): string[] => { const getDotColors = (date: Date): string[] => {
const dateStr = formatDateISO(date); const dayShifts = shifts.filter((s) => s.date.getDate() === date.getDate());
const dayShifts = shifts.filter((s) => s.date === dateStr);
const dots: string[] = []; const dots: string[] = [];
// if (dayShifts.some((s) => s.status === "available")) // if (dayShifts.some((s) => s.status === "available"))
// dots.push("bg-amber-400"); // dots.push("bg-amber-400");
@@ -81,7 +78,7 @@ export default function MobileShiftView({
}; };
const selectedShifts = useMemo(() => { const selectedShifts = useMemo(() => {
return shifts.filter((s) => s.date === selectedDate); return shifts.filter((s) => s.date.getDate() === selectedDate.getDate());
}, [shifts, selectedDate]); }, [shifts, selectedDate]);
const selectedDateObj = new Date(selectedDate + "T00:00:00"); const selectedDateObj = new Date(selectedDate + "T00:00:00");
@@ -133,16 +130,15 @@ export default function MobileShiftView({
return <div key={`empty-${i}`} className="p-1" />; return <div key={`empty-${i}`} className="p-1" />;
} }
const dateStr = formatDateISO(date);
const today = isToday(date); const today = isToday(date);
const selected = dateStr === selectedDate; const selected = date === selectedDate;
const dots = getDotColors(date); const dots = getDotColors(date);
return ( return (
<button <button
type="button" type="button"
key={i} key={i}
onClick={() => setSelectedDate(dateStr)} onClick={() => setSelectedDate(date)}
className={`flex cursor-pointer flex-col items-center border-none bg-transparent p-1 transition ${ className={`flex cursor-pointer flex-col items-center border-none bg-transparent p-1 transition ${
selected ? "rounded-lg bg-(--color-primary)/10" : "" selected ? "rounded-lg bg-(--color-primary)/10" : ""
}`} }`}
@@ -7,7 +7,7 @@ import type { MonthlyCalendarProps } from "./ShiftSchedule.types";
const DAY_HEADERS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; const DAY_HEADERS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
function formatDateISO(d: Date): string { export function formatDateISO(d: Date): string {
const y = d.getFullYear(); const y = d.getFullYear();
const m = (d.getMonth() + 1).toString().padStart(2, "0"); const m = (d.getMonth() + 1).toString().padStart(2, "0");
const day = d.getDate().toString().padStart(2, "0"); const day = d.getDate().toString().padStart(2, "0");
@@ -60,8 +60,7 @@ export default function MonthlyCalendar({
}, [currentDate]); }, [currentDate]);
const getShiftSummary = (date: Date) => { const getShiftSummary = (date: Date) => {
const dateStr = formatDateISO(date); const dayShifts = shifts.filter((s) => s.date.getDate() === date.getDate());
const dayShifts = shifts.filter((s) => s.date === dateStr);
// const available = dayShifts.filter((s) => s.status === "available").length; // const available = dayShifts.filter((s) => s.status === "available").length;
// const registered = dayShifts.filter( // const registered = dayShifts.filter(
// (s) => s.status === "registered", // (s) => s.status === "registered",
@@ -104,7 +103,7 @@ export default function MonthlyCalendar({
<button <button
type="button" type="button"
key={i} key={i}
onClick={() => onDateSelect?.(formatDateISO(date))} onClick={() => onDateSelect?.(date)}
className={`min-h-25 cursor-pointer border-r border-b border-(--color-border-light) bg-transparent p-2 text-left transition hover:bg-gray-50 ${ className={`min-h-25 cursor-pointer border-r border-b border-(--color-border-light) bg-transparent p-2 text-left transition hover:bg-gray-50 ${
today ? "bg-(--color-primary)/5" : "" today ? "bg-(--color-primary)/5" : ""
}`} }`}
@@ -4,6 +4,7 @@ import { DEPARTMENTS } from "@/lib/constants";
import { useShift } from "@/lib/shift-context"; import { useShift } from "@/lib/shift-context";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { formatDateISO } from "./MonthlyCalendar";
import type { ShiftCreateModalProps } from "./ShiftSchedule.types"; import type { ShiftCreateModalProps } from "./ShiftSchedule.types";
export default function ShiftCreateModal({ export default function ShiftCreateModal({
@@ -13,7 +14,7 @@ export default function ShiftCreateModal({
}: ShiftCreateModalProps) { }: ShiftCreateModalProps) {
const { createShift } = useShift(); const { createShift } = useShift();
const [date, setDate] = useState(defaultDate ?? "2026-04-10"); const [date, setDate] = useState<Date>(new Date(defaultDate ?? "2026-04-10"));
const [startTime, setStartTime] = useState("08:00"); const [startTime, setStartTime] = useState("08:00");
const [endTime, setEndTime] = useState("12:00"); const [endTime, setEndTime] = useState("12:00");
const [department, setDepartment] = useState("bar"); const [department, setDepartment] = useState("bar");
@@ -23,7 +24,7 @@ export default function ShiftCreateModal({
useEffect(() => { useEffect(() => {
if (isOpen) { if (isOpen) {
setDate(defaultDate ?? "2026-04-10"); setDate(new Date(defaultDate ?? "2026-04-10"));
} }
}, [defaultDate, isOpen]); }, [defaultDate, isOpen]);
@@ -97,8 +98,8 @@ export default function ShiftCreateModal({
<input <input
title="Date" title="Date"
type="date" type="date"
value={date} value={formatDateISO(date)}
onChange={(e) => setDate(e.target.value)} onChange={(e) => setDate(new Date(e.target.value))}
className="text-foreground w-full rounded-xl border border-(--color-border-light) px-3 py-2.5 text-sm transition outline-none focus:border-(--color-primary) focus:ring-1 focus:ring-(--color-primary)" className="text-foreground w-full rounded-xl border border-(--color-border-light) px-3 py-2.5 text-sm transition outline-none focus:border-(--color-primary) focus:ring-1 focus:ring-(--color-primary)"
/> />
</div> </div>
@@ -2,13 +2,13 @@ import type { ShiftEntity } from "@/lib/types";
export interface WeeklyScheduleProps { export interface WeeklyScheduleProps {
onShiftClick: (shift: ShiftEntity) => void; onShiftClick: (shift: ShiftEntity) => void;
onCreateShift?: (date: string) => void; onCreateShift?: (date: Date) => void;
mobileCalendarHeader?: boolean; mobileCalendarHeader?: boolean;
} }
export interface MonthlyCalendarProps { export interface MonthlyCalendarProps {
onShiftClick: (shift: ShiftEntity) => void; onShiftClick: (shift: ShiftEntity) => void;
onDateSelect?: (date: string) => void; onDateSelect?: (date: Date) => void;
} }
export interface MobileShiftViewProps { export interface MobileShiftViewProps {
@@ -59,7 +59,7 @@ export default function WeeklySchedule({
} = useShift(); } = useShift();
const weekDates = getWeekDates(); const weekDates = getWeekDates();
const [selectedDate, setSelectedDate] = useState<string>( const [selectedDate, setSelectedDate] = useState<Date>(
weekDates[0] ?? currentDate, weekDates[0] ?? currentDate,
); );
@@ -75,7 +75,7 @@ export default function WeeklySchedule({
// dots.push("bg-purple-400"); // dots.push("bg-purple-400");
// if (dayShifts.some((s) => s.status === "absent")) // if (dayShifts.some((s) => s.status === "absent"))
// dots.push("bg-rose-400"); // dots.push("bg-rose-400");
map[date] = dots.slice(0, 3); map[date.toISOString()] = dots.slice(0, 3);
}); });
return map; return map;
}, [weekDates, getShiftsForDate]); }, [weekDates, getShiftsForDate]);
@@ -113,7 +113,7 @@ export default function WeeklySchedule({
<div className="grid grid-cols-7 gap-1"> <div className="grid grid-cols-7 gap-1">
{weekDates.map((date, i) => { {weekDates.map((date, i) => {
const active = date === selectedDateStr; const active = date === selectedDateStr;
const dots = statusDotsByDate[date] ?? []; const dots = statusDotsByDate[date.toISOString()] ?? [];
return ( return (
<button <button
key={i} key={i}
@@ -222,7 +222,7 @@ export default function WeeklySchedule({
> >
<span className="block uppercase">{DAY_LABELS[i]}</span> <span className="block uppercase">{DAY_LABELS[i]}</span>
<span className="mt-0.5 block text-[11px] font-normal"> <span className="mt-0.5 block text-[11px] font-normal">
{date} {date.toISOString()}
</span> </span>
</th> </th>
))} ))}
+6 -6
View File
@@ -155,29 +155,29 @@ function generateMockShifts(): ShiftEntity[] {
if (shiftCounter % 7 === 0) { if (shiftCounter % 7 === 0) {
registered.push(staffPool[(staffIdx + 1) % staffPool.length]); registered.push(staffPool[(staffIdx + 1) % staffPool.length]);
} }
status = "registered"; // status = "registered";
// Some past shifts have leave/absent // Some past shifts have leave/absent
if (shiftCounter % 11 === 0) status = "approved_leave"; // if (shiftCounter % 11 === 0) status = "approved_leave";
if (shiftCounter % 13 === 0) status = "absent"; // if (shiftCounter % 13 === 0) status = "absent";
} }
// Current week (April 6-12): mix of registered and available // Current week (April 6-12): mix of registered and available
else if (day >= 10 && day <= 12) { else if (day >= 10 && day <= 12) {
if (shiftCounter % 3 === 0) { if (shiftCounter % 3 === 0) {
registered.push(staffPool[shiftCounter % staffPool.length]); registered.push(staffPool[shiftCounter % staffPool.length]);
status = "registered"; // status = "registered";
} }
} }
// Future shifts: mostly available, some registered // Future shifts: mostly available, some registered
else { else {
if (shiftCounter % 5 === 0) { if (shiftCounter % 5 === 0) {
registered.push(staffPool[shiftCounter % staffPool.length]); registered.push(staffPool[shiftCounter % staffPool.length]);
status = "registered"; // status = "registered";
} }
} }
shifts.push({ shifts.push({
id: "shiftId", id: "shiftId",
date: dateStr, date: new Date(dateStr),
startTime: slot.start, startTime: slot.start,
endTime: slot.end, endTime: slot.end,
// durationHours: slot.hours, // durationHours: slot.hours,
+9 -7
View File
@@ -50,9 +50,9 @@ interface ShiftContextType {
// Helpers // Helpers
getShiftsForDate: (date: Date) => ShiftEntity[]; getShiftsForDate: (date: Date) => ShiftEntity[];
getShiftsForWeek: (weekStart: Date) => ShiftEntity[]; getShiftsForWeek: (weekStart: Date) => ShiftEntity[];
getWeekDates: () => string[]; getWeekDates: () => Date[];
hasConflict: ( hasConflict: (
date: string, date: Date,
startTime: string, startTime: string,
endTime: string, endTime: string,
staffId: string, staffId: string,
@@ -195,12 +195,12 @@ export function ShiftProvider({ children }: { children: ReactNode }) {
// ── Query helpers ─────────────────────────────────────────────────────── // ── Query helpers ───────────────────────────────────────────────────────
const getWeekDates = useCallback((): string[] => { const getWeekDates = useCallback((): Date[] => {
const monday = getMonday(currentDate); const monday = getMonday(currentDate);
return Array.from({ length: 7 }, (_, i) => { return Array.from({ length: 7 }, (_, i) => {
const d = new Date(monday); const d = new Date(monday);
d.setDate(monday.getDate() + i); d.setDate(monday.getDate() + i);
return d.toISOString(); return d;
}); });
}, [currentDate]); }, [currentDate]);
@@ -218,7 +218,7 @@ export function ShiftProvider({ children }: { children: ReactNode }) {
const dates = Array.from({ length: 7 }, (_, i) => { const dates = Array.from({ length: 7 }, (_, i) => {
const d = new Date(weekStart); const d = new Date(weekStart);
d.setDate(weekStart.getDate() + i); d.setDate(weekStart.getDate() + i);
return d.toISOString(); return d;
}); });
return shifts.filter((s) => dates.includes(s.date)); return shifts.filter((s) => dates.includes(s.date));
}, },
@@ -227,7 +227,7 @@ export function ShiftProvider({ children }: { children: ReactNode }) {
const hasConflict = useCallback( const hasConflict = useCallback(
( (
date: string, date: Date,
startTime: string, startTime: string,
endTime: string, endTime: string,
staffId: string, staffId: string,
@@ -247,7 +247,9 @@ export function ShiftProvider({ children }: { children: ReactNode }) {
const getWeeklyBudget = useCallback((): number => { const getWeeklyBudget = useCallback((): number => {
const weekDates = getWeekDates(); const weekDates = getWeekDates();
return shifts return shifts
.filter((s) => weekDates.includes(s.date) && s.registeredStaff!.length > 0) .filter(
(s) => weekDates.includes(s.date) && s.registeredStaff!.length > 0,
)
.reduce((sum, s) => sum + s.wage * s.registeredStaff!.length, 0); .reduce((sum, s) => sum + s.wage * s.registeredStaff!.length, 0);
}, [shifts, getWeekDates]); }, [shifts, getWeekDates]);
+1 -1
View File
@@ -96,7 +96,7 @@ export interface ShiftRegistrationEntity {
export interface ShiftEntity { export interface ShiftEntity {
id: string; id: string;
date: string; date: Date;
startTime: string; startTime: string;
endTime: string; endTime: string;
wage: number; wage: number;