import React, { useState } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { ChevronLeft, ChevronRight, Plus, Clock, DollarSign, Calendar as CalendarIcon } from "lucide-react"; import { format, startOfWeek, addDays, isSameDay, addWeeks, subWeeks, isToday, parseISO } from "date-fns"; const safeParseDate = (dateString) => { if (!dateString) return null; try { if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(dateString)) { const [year, month, day] = dateString.split('-').map(Number); return new Date(year, month - 1, day); } return parseISO(dateString); } catch { return null; } }; export default function Schedule() { const navigate = useNavigate(); const [currentWeek, setCurrentWeek] = useState(startOfWeek(new Date(), { weekStartsOn: 0 })); const { data: events = [] } = useQuery({ queryKey: ['events'], queryFn: () => base44.entities.Event.list('-date'), initialData: [], }); const weekDays = Array.from({ length: 7 }, (_, i) => addDays(currentWeek, i)); const getEventsForDay = (date) => { return events.filter(event => { const eventDate = safeParseDate(event.date); return eventDate && isSameDay(eventDate, date); }); }; const calculateWeekMetrics = () => { const weekEvents = events.filter(event => { const eventDate = safeParseDate(event.date); if (!eventDate) return false; return weekDays.some(day => isSameDay(eventDate, day)); }); const totalHours = weekEvents.reduce((sum, event) => { const hours = event.shifts?.reduce((shiftSum, shift) => { return shiftSum + (shift.roles?.reduce((roleSum, role) => roleSum + (role.hours || 0), 0) || 0); }, 0) || 0; return sum + hours; }, 0); const totalCost = weekEvents.reduce((sum, event) => sum + (event.total || 0), 0); const totalShifts = weekEvents.reduce((sum, event) => sum + (event.shifts?.length || 0), 0); return { totalHours, totalCost, totalShifts }; }; const metrics = calculateWeekMetrics(); const goToPreviousWeek = () => setCurrentWeek(subWeeks(currentWeek, 1)); const goToNextWeek = () => setCurrentWeek(addWeeks(currentWeek, 1)); const goToToday = () => setCurrentWeek(startOfWeek(new Date(), { weekStartsOn: 0 })); return (
{/* Header */}

Schedule

Plan and manage staff shifts

{/* Metrics Cards */}

Week Total Hours

{metrics.totalHours.toFixed(1)}

Week Labor Cost

${metrics.totalCost.toLocaleString()}

Total Shifts

{metrics.totalShifts}

{/* Week Navigation */}

Week of

{format(currentWeek, 'MMM d, yyyy')}

{/* Weekly Calendar */}
{weekDays.map((day, index) => { const dayEvents = getEventsForDay(day); const isTodayDay = isToday(day); return ( {/* Day Header */}

{format(day, 'EEE')}

{format(day, 'd')}

{format(day, 'MMM')}

{/* Add Shift Button */} {/* Events List */}
{dayEvents.length === 0 ? (

No shifts

) : ( dayEvents.map((event) => { const firstShift = event.shifts?.[0]; const firstRole = firstShift?.roles?.[0]; const firstStaff = event.assigned_staff?.[0]; return (
navigate(createPageUrl(`EventDetail?id=${event.id}`))} className={`p-3 rounded cursor-pointer transition-all ${ isTodayDay ? 'bg-white/20 hover:bg-white/30 border border-white/40' : 'bg-white hover:bg-slate-50 border border-slate-200 shadow-sm' }`} > {/* Status Badges */}
{firstRole?.role && ( {firstRole.role} )} {event.status || 'scheduled'}
{/* Staff Member */} {firstStaff && (

👤 {firstStaff.staff_name}

)} {/* Time */} {firstRole && (firstRole.start_time || firstRole.end_time) && (

{firstRole.start_time || '00:00'} - {firstRole.end_time || '00:00'}

)} {/* Cost */} {event.total > 0 && (

${event.total.toFixed(2)}

)}
); }) )}
); })}
); }