import { useMemo, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { format } from "date-fns"; import { useSelector } from "react-redux"; import { Calendar, MapPin, Users, DollarSign, Edit3, X, Copy, Clock, FileText, UserPlus } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/common/components/ui/card"; import { Button } from "@/common/components/ui/button"; import { Badge } from "@/common/components/ui/badge"; import DashboardLayout from "@/features/layouts/DashboardLayout"; import { useGetOrderById, useUpdateOrder, useListShiftRolesByBusinessAndOrder } from "@/dataconnect-generated/react"; import { OrderStatus } from "@/dataconnect-generated"; import { dataConnect } from "@/features/auth/firebase"; import { useToast } from "@/common/components/ui/use-toast"; import AssignStaffModal from "./components/AssignStaffModal"; import type { RootState } from "@/store/store"; const safeFormatDate = (value?: string | null): string => { if (!value) return "—"; try { const d = new Date(value); if (Number.isNaN(d.getTime())) return "—"; return format(d, "MMM d, yyyy"); } catch { return "—"; } }; const safeFormatDateTime = (value?: string | null): string => { if (!value) return "—"; try { const d = new Date(value); if (Number.isNaN(d.getTime())) return "—"; return format(d, "MMM d, yyyy • h:mm a"); } catch { return "—"; } }; const getStatusBadge = (status: OrderStatus) => { switch (status) { case OrderStatus.FULLY_STAFFED: case OrderStatus.FILLED: return ( Fully Staffed ); case OrderStatus.PARTIAL_STAFFED: return ( Partial Staffed ); case OrderStatus.PENDING: case OrderStatus.POSTED: return ( {status} ); case OrderStatus.CANCELLED: return ( Cancelled ); case OrderStatus.COMPLETED: return ( Completed ); case OrderStatus.DRAFT: default: return ( {status} ); } }; export default function OrderDetail() { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); const { toast } = useToast(); const { user } = useSelector((state: RootState) => state.auth); const [selectedShift, setSelectedShift] = useState(null); const [isAssignModalOpen, setIsAssignModalOpen] = useState(false); const { data, isLoading, } = useGetOrderById( dataConnect, { id: id || "" }, { enabled: !!id, }, ); const order = data?.order; // Fetch real shift roles to get IDs and accurate counts const { data: shiftRolesData, isLoading: isLoadingShifts, refetch: refetchShifts } = useListShiftRolesByBusinessAndOrder( dataConnect, { orderId: id || "", businessId: order?.businessId || "" }, { enabled: !!id && !!order?.businessId, } ); const cancelMutation = useUpdateOrder(dataConnect, { onSuccess: () => { toast({ title: "Order cancelled", description: "The order status has been updated to Cancelled.", }); }, onError: () => { toast({ title: "Failed to cancel order", description: "Please try again or contact support.", variant: "destructive", }); }, }); const canModify = useMemo(() => { if (!order) return false; const status = order.status as OrderStatus; return status !== OrderStatus.CANCELLED && status !== OrderStatus.COMPLETED; }, [order]); const handleCancel = () => { if (!order || !id || !canModify) return; cancelMutation.mutate({ id, status: OrderStatus.CANCELLED, }); }; const handleEdit = () => { if (!order || !id) return; navigate(`/orders/${id}/edit`); }; const handleDuplicate = () => { if (!order || !id) return; // Placeholder: route can later pre-fill a new order from this one navigate(`/orders/create?duplicate=${id}`); }; const shifts: any[] = useMemo(() => { if (shiftRolesData?.shiftRoles && shiftRolesData.shiftRoles.length > 0) { return shiftRolesData.shiftRoles; } return Array.isArray(order?.shifts) ? (order!.shifts as any[]) : []; }, [shiftRolesData, order?.shifts]); const totalRequested = order?.requested ?? 0; const totalAssigned = Array.isArray(order?.assignedStaff) ? order!.assignedStaff.length : 0; if (isLoading) { return (
); } if (!order) { return (

This order may have been deleted or the link is invalid.

); } const isClient = user?.userRole === "client"; const clientName = order.business?.businessName || "Unknown client"; const eventDateLabel = safeFormatDate(order.date as string | null); const locationLabel = order.business?.businessName || "—"; const timelineItems = [ { label: "Order created", value: safeFormatDateTime(order.createdAt as string | null), }, { label: "Event date", value: eventDateLabel, }, { label: "Current status", value: (order.status as string) || "—", }, ]; return ( {getStatusBadge(order.status as OrderStatus)}
} >
{/* Header / Key Info */} Order Overview

Client Name

{clientName}

Event Date

{eventDateLabel}

Location

{locationLabel}

Staffed / Requested

{totalAssigned} / {totalRequested}

{/* Shifts Section */} Shifts {shifts.length === 0 ? (

No shifts defined for this order.

Add shifts when creating or editing the order to see them here.

) : (
{shifts.map((shift: any, index: number) => { const start = safeFormatDateTime(shift.startTime || shift.start || shift.date); const end = safeFormatDateTime(shift.endTime || shift.end); const title = shift.title || shift.positionName || shift.roleName || `Shift #${index + 1}`; const workersNeeded = shift.workersNeeded ?? shift.requested ?? 0; const filled = typeof shift.filled === "number" ? shift.filled : Array.isArray(shift.assignedStaff) ? shift.assignedStaff.length : 0; const vacancies = Math.max(workersNeeded - filled, 0); return (

{title}

{start} {end !== "—" && `→ ${end}`}
Required {workersNeeded || "—"}
Assigned {filled}
Vacancies {vacancies}
{!isClient && canModify && ( )}
); })}
)}
{/* Timeline Section */} Order Status Timeline
{timelineItems.map((item, idx) => (

{item.label}

{item.value}

))}
{/* Financial Summary (optional helper, derived from existing fields) */} Summary

Estimated Total

{typeof order.total === "number" ? `$${order.total.toLocaleString()}` : "—"}

Total Positions

{totalRequested}

Order Type

{(order.orderType as string)?.replace("_", " ") || "—"}

{selectedShift && ( { setIsAssignModalOpen(false); setSelectedShift(null); }} shift={selectedShift} onSuccess={() => { refetchShifts(); }} /> )} ); }