import React, { useState, useMemo } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Link, useNavigate } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Tabs, // New import TabsList, // New import TabsTrigger, // New import } from "@/components/ui/tabs"; // New import import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Calendar as CalendarComponent } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, } from "@/components/ui/command"; import { Search, Calendar, MapPin, Users, Eye, Edit, X, Trash2, FileText, // Edit instead of Edit2 Clock, DollarSign, Package, CheckCircle, AlertTriangle, Grid, List, Zap, Plus, Building2, Bell, Edit3, Filter, CalendarIcon, Check, ChevronsUpDown } from "lucide-react"; import { useToast } from "@/components/ui/use-toast"; import { format, parseISO, isValid } from "date-fns"; import OrderDetailModal from "@/components/orders/OrderDetailModal"; const safeParseDate = (dateString) => { if (!dateString) return null; try { const date = typeof dateString === 'string' ? parseISO(dateString) : new Date(dateString); return isValid(date) ? date : null; } catch { return null; } }; const safeFormatDate = (dateString, formatString) => { const date = safeParseDate(dateString); return date ? format(date, formatString) : '—'; }; const convertTo12Hour = (time24) => { if (!time24) return "-"; try { const [hours, minutes] = time24.split(':'); const hour = parseInt(hours); const ampm = hour >= 12 ? 'PM' : 'AM'; const hour12 = hour % 12 || 12; return `${hour12}:${minutes} ${ampm}`; } catch { return time24; } }; const getStatusBadge = (event) => { if (event.is_rapid) { return (
RAPID
); } const statusConfig = { 'Draft': { bg: 'bg-slate-500', icon: FileText }, 'Pending': { bg: 'bg-amber-500', icon: Clock }, 'Partial Staffed': { bg: 'bg-orange-500', icon: AlertTriangle }, 'Fully Staffed': { bg: 'bg-emerald-500', icon: CheckCircle }, 'Active': { bg: 'bg-blue-500', icon: Users }, 'Completed': { bg: 'bg-slate-400', icon: CheckCircle }, 'Canceled': { bg: 'bg-red-500', icon: X }, }; const config = statusConfig[event.status] || { bg: 'bg-slate-400', icon: Clock }; const Icon = config.icon; return (
{event.status}
); }; export default function ClientOrders() { const navigate = useNavigate(); const queryClient = useQueryClient(); const { toast } = useToast(); const [searchTerm, setSearchTerm] = useState(""); const [statusFilter, setStatusFilter] = useState("all"); // Updated values for Tabs const [dateFilter, setDateFilter] = useState("all"); const [specificDate, setSpecificDate] = useState(null); const [tempDate, setTempDate] = useState(null); const [locationFilter, setLocationFilter] = useState("all"); const [managerFilter, setManagerFilter] = useState("all"); const [locationOpen, setLocationOpen] = useState(false); const [managerOpen, setManagerOpen] = useState(false); const [cancelDialogOpen, setCancelDialogOpen] = useState(false); // Changed from cancelDialog.open const [orderToCancel, setOrderToCancel] = useState(null); // Changed from cancelDialog.order const [viewOrderModal, setViewOrderModal] = useState(false); const [selectedOrder, setSelectedOrder] = useState(null); const [calendarOpen, setCalendarOpen] = useState(false); const { data: user } = useQuery({ queryKey: ['current-user-client-orders'], queryFn: () => base44.auth.me(), }); const { data: allEvents = [] } = useQuery({ queryKey: ['all-events-client'], queryFn: () => base44.entities.Event.list('-date'), }); const clientEvents = useMemo(() => { return allEvents.filter(e => e.client_email === user?.email || e.business_name === user?.company_name || e.created_by === user?.email ); }, [allEvents, user]); const cancelOrderMutation = useMutation({ mutationFn: (orderId) => base44.entities.Event.update(orderId, { status: "Canceled" }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['all-events-client'] }); toast({ title: "✅ Order Canceled", description: "Your order has been canceled successfully", }); setCancelDialogOpen(false); // Updated setOrderToCancel(null); // Updated }, onError: () => { toast({ title: "❌ Failed to Cancel", description: "Could not cancel order. Please try again.", variant: "destructive", }); }, }); // Get unique locations and managers for filters const uniqueLocations = useMemo(() => { const locations = new Set(); clientEvents.forEach(e => { if (e.hub) locations.add(e.hub); if (e.event_location) locations.add(e.event_location); }); return Array.from(locations).sort(); }, [clientEvents]); const uniqueManagers = useMemo(() => { const managers = new Set(); clientEvents.forEach(e => { if (e.manager_name) managers.add(e.manager_name); // Also check in shifts for manager names e.shifts?.forEach(shift => { if (shift.manager_name) managers.add(shift.manager_name); }); }); return Array.from(managers).sort(); }, [clientEvents]); const filteredOrders = useMemo(() => { // Renamed from filteredEvents let filtered = clientEvents; if (searchTerm) { const lower = searchTerm.toLowerCase(); filtered = filtered.filter(e => e.event_name?.toLowerCase().includes(lower) || e.business_name?.toLowerCase().includes(lower) || e.hub?.toLowerCase().includes(lower) || e.event_location?.toLowerCase().includes(lower) // Added event_location to search ); } const now = new Date(); // Reset time for comparison to only compare dates now.setHours(0, 0, 0, 0); filtered = filtered.filter(e => { const eventDate = safeParseDate(e.date); const isCompleted = e.status === "Completed"; const isCanceled = e.status === "Canceled"; const isFutureOrPresent = eventDate && eventDate >= now; if (statusFilter === "active") { return !isCompleted && !isCanceled && isFutureOrPresent; } else if (statusFilter === "completed") { return isCompleted; } return true; // For "all" or other statuses }); // Specific date filter (from calendar) if (specificDate) { filtered = filtered.filter(e => { const eventDate = safeParseDate(e.date); if (!eventDate) return false; const selectedDateNormalized = new Date(specificDate); selectedDateNormalized.setHours(0, 0, 0, 0); eventDate.setHours(0, 0, 0, 0); return eventDate.getTime() === selectedDateNormalized.getTime(); }); } // Date range filter else if (dateFilter !== "all") { filtered = filtered.filter(e => { const eventDate = safeParseDate(e.date); if (!eventDate) return false; const now = new Date(); now.setHours(0, 0, 0, 0); if (dateFilter === "today") { return eventDate.toDateString() === now.toDateString(); } else if (dateFilter === "week") { const weekFromNow = new Date(now); weekFromNow.setDate(now.getDate() + 7); return eventDate >= now && eventDate <= weekFromNow; } else if (dateFilter === "month") { const monthFromNow = new Date(now); monthFromNow.setMonth(now.getMonth() + 1); return eventDate >= now && eventDate <= monthFromNow; } else if (dateFilter === "past") { return eventDate < now; } return true; }); } // Location filter if (locationFilter !== "all") { filtered = filtered.filter(e => e.hub === locationFilter || e.event_location === locationFilter ); } // Manager filter if (managerFilter !== "all") { filtered = filtered.filter(e => { if (e.manager_name === managerFilter) return true; // Check shifts for manager return e.shifts?.some(shift => shift.manager_name === managerFilter); }); } return filtered; }, [clientEvents, searchTerm, statusFilter, dateFilter, specificDate, locationFilter, managerFilter]); const activeOrders = clientEvents.filter(e => e.status !== "Completed" && e.status !== "Canceled" ).length; const completedOrders = clientEvents.filter(e => e.status === "Completed").length; const totalSpent = clientEvents .filter(e => e.status === "Completed") .reduce((sum, e) => sum + (e.total || 0), 0); const handleCancelOrder = (order) => { setOrderToCancel(order); // Updated setCancelDialogOpen(true); // Updated }; const handleViewOrder = (order) => { setSelectedOrder(order); setViewOrderModal(true); }; const confirmCancel = () => { if (orderToCancel) { // Updated cancelOrderMutation.mutate(orderToCancel.id); // Updated } }; const canEditOrder = (order) => { const eventDate = safeParseDate(order.date); const now = new Date(); return order.status !== "Completed" && order.status !== "Canceled" && eventDate && eventDate > now; // Ensure eventDate is valid before comparison }; const canCancelOrder = (order) => { return order.status !== "Completed" && order.status !== "Canceled"; }; const getAssignmentStatus = (event) => { const totalRequested = event.shifts?.reduce((accShift, shift) => { return accShift + (shift.roles?.reduce((accRole, role) => accRole + (role.count || 0), 0) || 0); }, 0) || 0; const assigned = event.assigned_staff?.length || 0; const percentage = totalRequested > 0 ? Math.round((assigned / totalRequested) * 100) : 0; let badgeClass = 'bg-slate-100 text-slate-600'; // Default: no staff, or no roles requested if (assigned > 0 && assigned < totalRequested) { badgeClass = 'bg-orange-500 text-white'; // Partial Staffed } else if (assigned >= totalRequested && totalRequested > 0) { badgeClass = 'bg-emerald-500 text-white'; // Fully Staffed } else if (assigned === 0 && totalRequested > 0) { badgeClass = 'bg-red-500 text-white'; // Requested but 0 assigned } else if (assigned > 0 && totalRequested === 0) { badgeClass = 'bg-blue-500 text-white'; // Staff assigned but no roles explicitly requested (e.g., event set up, staff assigned, but roles not detailed or count is 0) } return { badgeClass, assigned, requested: totalRequested, percentage, }; }; const getEventTimes = (event) => { const firstShift = event.shifts?.[0]; const rolesInFirstShift = firstShift?.roles || []; let startTime = null; let endTime = null; if (rolesInFirstShift.length > 0) { startTime = rolesInFirstShift[0].start_time || null; endTime = rolesInFirstShift[0].end_time || null; } return { startTime: startTime ? convertTo12Hour(startTime) : "-", endTime: endTime ? convertTo12Hour(endTime) : "-" }; }; return (
{/* Removed mb-6 */}

My Orders

View and manage all your orders

{/* Removed mb-6 from here as it's now part of space-y-6 */}

TOTAL

{clientEvents.length}

ACTIVE

{activeOrders}

COMPLETED

{completedOrders}

TOTAL SPENT

${Math.round(totalSpent / 1000)}k

setSearchTerm(e.target.value)} className="pl-10 border-slate-300 h-10" />
All Active Completed
Filters:
setTempDate(date)} numberOfMonths={2} initialFocus />
No location found. { setLocationFilter("all"); setLocationOpen(false); }} > All Locations {uniqueLocations.map((location) => ( { setLocationFilter(currentValue); setLocationOpen(false); }} > {location} ))} No manager found. { setManagerFilter("all"); setManagerOpen(false); }} > All Managers {uniqueManagers.map((manager) => ( { setManagerFilter(currentValue); setManagerOpen(false); }} > {manager} ))} {(dateFilter !== "all" || specificDate || locationFilter !== "all" || managerFilter !== "all") && ( )}
{/* Card class updated */} {/* CardContent padding updated */} Business Hub Event Date & Time Status Requested Assigned Invoice Actions {filteredOrders.length === 0 ? (

No orders found

) : ( filteredOrders.map((order) => { const assignedCount = order.assigned_staff?.length || 0; const requestedCount = order.requested || 0; const assignmentProgress = requestedCount > 0 ? Math.round((assignedCount / requestedCount) * 100) : 0; const { startTime, endTime } = getEventTimes(order); return (
{order.business_name || "Primary Location"}
{order.hub || "Main Hub"}

{order.event_name || "Untitled Event"}

{safeFormatDate(order.date, 'MM.dd.yyyy')}

{startTime} - {endTime}

{getStatusBadge(order)} {requestedCount}
{assignedCount}
{assignmentProgress}%
{canEditOrder(order) && ( )} {canCancelOrder(order) && ( )}
); }) )}
setViewOrderModal(false)} order={selectedOrder} onCancel={handleCancelOrder} /> {/* Updated open and onOpenChange */} Cancel Order? Are you sure you want to cancel this order? This action cannot be undone. {orderToCancel && ( // Using orderToCancel

{orderToCancel.event_name}

{orderToCancel.date ? format(new Date(orderToCancel.date), "MMMM d, yyyy") : "—"}
{orderToCancel.hub || orderToCancel.event_location}
)}
); }