import React, { useState, useMemo, useEffect } 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, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Award, TrendingUp, Users, DollarSign, Calendar, Package, Timer, Zap, Send, RefreshCw, Copy, Eye, MoreHorizontal, Star, Trophy, FileText, CheckCircle, ArrowRight, Target, Activity, Clock, Building2, MapPin, Play, Pause, UserCheck } from "lucide-react"; import { format, differenceInHours, parseISO } from "date-fns"; import { useToast } from "@/components/ui/use-toast"; import { motion, AnimatePresence } from "framer-motion"; export default function VendorDashboard() { const navigate = useNavigate(); const queryClient = useQueryClient(); const { toast } = useToast(); const [showRapidModal, setShowRapidModal] = useState(false); const [carouselIndex, setCarouselIndex] = useState(0); const [autoRotate, setAutoRotate] = useState(true); const { data: user } = useQuery({ queryKey: ['current-user-vendor'], queryFn: () => base44.auth.me(), }); const { data: events } = useQuery({ queryKey: ['vendor-events'], queryFn: async () => { const allEvents = await base44.entities.Event.list('-date'); if (!user?.email) return []; return allEvents.filter(e => e.vendor_name === user?.company_name || e.vendor_id === user?.id || e.created_by === user?.email ); }, initialData: [], enabled: !!user }); const { data: staff } = useQuery({ queryKey: ['vendor-staff'], queryFn: async () => { const allStaff = await base44.entities.Staff.list(); if (!user?.company_name) return allStaff.slice(0, 10); return allStaff.filter(s => s.vendor_name === user?.company_name); }, initialData: [], enabled: !!user }); useEffect(() => { if (!autoRotate) return; const interval = setInterval(() => { setCarouselIndex(prev => (prev + 1) % 4); }, 4000); return () => clearInterval(interval); }, [autoRotate]); const todayOrders = events.filter(e => { const eventDate = new Date(e.date); const today = new Date(); return eventDate.toDateString() === today.toDateString(); }); const inProgressOrders = events.filter(e => e.status === "Active" || e.status === "Confirmed" || e.status === "In Progress" ); const completedOrders = events.filter(e => e.status === "Completed"); const totalRevenue = completedOrders.reduce((sum, e) => sum + (e.total || 0), 0); const currentMonth = new Date().getMonth(); const currentYear = new Date().getFullYear(); const thisMonthOrders = events.filter(e => { const eventDate = new Date(e.date); return eventDate.getMonth() === currentMonth && eventDate.getFullYear() === currentYear && (e.status === "Completed" || e.status === "Active"); }); const thisMonthRevenue = thisMonthOrders.reduce((sum, e) => sum + (e.total || 0), 0); const thisMonthPayroll = thisMonthRevenue * 0.88; const activeStaff = staff.filter(s => s.employment_type !== "Medical Leave" && s.action !== "Inactive").length; const staffAssignedToday = todayOrders.reduce((sum, e) => sum + (e.requested || 0), 0); const staffAssignedTodayCompleted = todayOrders.reduce((sum, e) => { const assignedCount = e.assigned_staff?.length || 0; return sum + assignedCount; }, 0); const todayStaffCompletion = staffAssignedToday > 0 ? Math.round((staffAssignedTodayCompleted / staffAssignedToday) * 100) : 0; const rapidOrders = events.filter(e => { const eventDate = new Date(e.date); const now = new Date(); const hoursUntil = differenceInHours(eventDate, now); return hoursUntil > 0 && hoursUntil <= 24 && (e.status === "Active" || e.status === "Confirmed" || e.status === "Pending"); }); const recentOrders = events .filter(e => e.status !== "Completed" && e.status !== "Canceled") .sort((a, b) => new Date(b.date) - new Date(a.date)) .slice(0, 7); const coverageRate = events.reduce((sum, e) => sum + (e.requested || 0), 0) > 0 ? Math.round((events.reduce((sum, e) => sum + (e.assigned_staff?.length || 0), 0) / events.reduce((sum, e) => sum + (e.requested || 0), 0)) * 100) : 0; const todayOrdersTotal = todayOrders.length; const todayOrdersCompleted = todayOrders.filter(e => e.status === "Completed").length; const todayOrdersCompletion = todayOrdersTotal > 0 ? Math.round((todayOrdersCompleted / todayOrdersTotal) * 100) : 0; const inProgressTotal = inProgressOrders.length; const inProgressStaffed = inProgressOrders.filter(e => { const assignedCount = e.assigned_staff?.length || 0; const requestedCount = e.requested || 0; return requestedCount > 0 && assignedCount >= requestedCount; }).length; const inProgressCompletion = inProgressTotal > 0 ? Math.round((inProgressStaffed / inProgressTotal) * 100) : 0; const clientRevenue = completedOrders.reduce((acc, event) => { const client = event.business_name || "Unknown"; if (!acc[client]) { acc[client] = { name: client, revenue: 0, orders: 0 }; } acc[client].revenue += (event.total || 0); acc[client].orders++; return acc; }, {}); const topClients = Object.values(clientRevenue) .sort((a, b) => b.revenue - a.revenue) .slice(0, 3); const topPerformers = staff .filter(s => s.rating > 0) .sort((a, b) => (b.rating || 0) - (a.rating || 0)) .slice(0, 3) .map(s => ({ ...s, shifts: s.total_shifts || Math.floor(Math.random() * 30) + 5 })); const hour = new Date().getHours(); const greeting = hour < 12 ? "Good morning" : hour < 18 ? "Good afternoon" : "Good evening"; const getStatusBadge = (status, isFull) => { if (isFull) { return { label: "Fully Staffed", className: "bg-emerald-500 text-white border-0", dotColor: "bg-emerald-400" }; } const badges = { "Active": { label: "Active", className: "bg-green-500 text-white border-0", dotColor: "bg-green-400" }, "Pending": { label: "Pending", className: "bg-orange-500 text-white border-0", dotColor: "bg-orange-400" }, "Confirmed": { label: "Confirmed", className: "bg-blue-500 text-white border-0", dotColor: "bg-blue-400" }, "Draft": { label: "Draft", className: "bg-slate-400 text-white border-0", dotColor: "bg-slate-300" } }; return badges[status] || badges["Draft"]; }; const handleSendNotification = (order) => { toast({ title: "Notification Sent", description: `Notification sent for order: ${order.event_name}`, }); }; const handleAssignStaff = (order) => { navigate(createPageUrl(`EventDetail?id=${order.id}`)); }; const handleViewOrder = (order) => { navigate(createPageUrl(`EventDetail?id=${order.id}`)); }; const handleCopyOrder = (order) => { navigator.clipboard.writeText(order.id); toast({ title: "Order ID Copied", description: `Order ID ${order.id} copied to clipboard`, }); }; const handleRapidClick = () => { if (rapidOrders.length === 0) { toast({ title: "No Urgent Orders", description: "There are currently no rapid orders.", }); } else if (rapidOrders.length === 1) { navigate(createPageUrl(`EventDetail?id=${rapidOrders[0].id}`)); } else { setShowRapidModal(true); } }; const carouselSlides = [ { title: "This Month", value: `$${Math.round(thisMonthRevenue / 1000)}k`, subtitle: `${thisMonthOrders.length} orders completed`, icon: TrendingUp, color: "from-emerald-500 via-emerald-600 to-emerald-700" }, { title: "Total Revenue", value: `$${Math.round(totalRevenue / 1000)}k`, subtitle: "All time earnings", icon: DollarSign, color: "from-[#0A39DF] via-blue-700 to-[#1C323E]" }, { title: "Active Orders", value: `${inProgressOrders.length}`, subtitle: `${inProgressCompletion}% staffed`, icon: Activity, color: "from-purple-500 via-purple-600 to-purple-700" }, { title: "Avg Fill Time", value: "1h 12m", subtitle: "14m faster than last week", icon: Clock, color: "from-indigo-500 via-indigo-600 to-blue-700" // Changed color } ]; return (

{greeting} here's what matters today

{/* Top 4 KPI Cards */}

Orders Today

{todayOrders.length}

Active

In Progress

{inProgressOrders.length}

{inProgressCompletion}% Coverage Rate

Order Type

{rapidOrders.length > 0 && ( {rapidOrders.length} Urgent )}

RAPID

Click to view

{/* Changed bg-amber-50 to bg-indigo-50 */} {/* Changed text-amber-600 to text-indigo-600 */}

Staff Assigned

Today {/* Changed bg-amber-100 to bg-indigo-100 and text-amber-700 to text-indigo-700 */}

{staffAssignedToday}

{staffAssignedTodayCompleted}/{staffAssignedToday} filled

{/* Main Content Grid */}
{/* Orders Table (2 cols) */}
{recentOrders.length > 0 ? ( recentOrders.map((order, index) => { const assignedCount = order.assigned_staff?.length || 0; const requestedCount = order.requested || 0; const isFull = assignedCount >= requestedCount && requestedCount > 0; const statusConfig = getStatusBadge(order.status, isFull); return ( ); }) ) : ( )}
Business Hub Event Name Status Date Requested Assigned Invoice Actions
{order.business_name || "Sports Arena LLC"}
{order.hub || "Downtown"} {order.event_name}
{statusConfig.label}
{order.date ? format(new Date(order.date), "MM/dd/yy") : "-"} {requestedCount} 0 ? 'bg-blue-100 text-blue-700' : 'bg-slate-100 text-slate-600' }`}> {assignedCount}
handleViewOrder(order)}> View Details handleCopyOrder(order)}> Copy ID

No orders to display

Your recent orders will appear here

{/* Bottom Stats Row */}
Top Clients
{topClients.length > 0 ? ( topClients.map((client, idx) => (
{idx + 1}

{client.name}

+{client.orders}% growth

${(client.revenue / 1000).toFixed(0)}k

)) ) : (

No client data

)}
Top Performers
{topPerformers.length > 0 ? ( topPerformers.map((member, idx) => (
{idx + 1}

{member.employee_name}

{member.shifts} shifts

{(member.rating || 0).toFixed(1)}
)) ) : (

No staff data

)}
Gold Vendors

Legendary Staffing

Premier vendor

98

Score

Epic Workforce

Gold tier

96

Score

{/* Right Sidebar */}
{/* Enhanced Carousel Card */}
{carouselSlides.map((_, index) => (
{React.createElement(carouselSlides[carouselIndex].icon, { className: "w-6 h-6 text-white/80" })}

{carouselSlides[carouselIndex].title}

{carouselSlides[carouselIndex].value}

{carouselSlides[carouselIndex].subtitle}

{/* Quick Action Buttons */}

All Orders

View & manage

My Staff

Manage staff

{/* Rapid Orders Modal */}
Urgent Orders

{rapidOrders.length} order{rapidOrders.length !== 1 ? 's' : ''} need immediate attention

{rapidOrders.map((order) => { const eventDate = new Date(order.date); const now = new Date(); const hoursUntil = Math.round(differenceInHours(eventDate, now)); const assignedCount = order.assigned_staff?.length || 0; const requestedCount = order.requested || 0; return (
{ setShowRapidModal(false); navigate(createPageUrl(`EventDetail?id=${order.id}`)); }} >
{hoursUntil}h away {order.business_name || "Client"}

{order.event_name}

{format(eventDate, "MMM d, h:mm a")} {order.hub || "No hub"}

Staff Assignment

0 ? (assignedCount / requestedCount) * 100 : 0}%` }} />
{assignedCount}/{requestedCount}
); })}
); }