feat(scripts/prepare-export.js): replace require with import statements feat(scripts/prepare-export.js): use fileURLToPath to define __dirname feat(scripts/prepare-export.js): refactor patch application for clarity feat(scripts/prepare-export.js): add global import fix for components feat(scripts/prepare-export.js): fix component imports using regex feat(scripts/prepare-export.js): add main function to execute patches feat(scripts/prepare-export.js): mock base44 client for local development feat(scripts/prepare-export.js): add company logo field to business modal feat(scripts/prepare-export.js): add AI order assistant component feat(scripts/prepare-export.js): enhance event form with new features feat(scripts/prepare-export.js): add event form wizard component feat(scripts/prepare-export.js): add safe date formatter to message thread feat(DocumentViewer.jsx): Implement signature capture and acknowledgment feature feat(DocumentViewer.jsx): Add signature pad for capturing digital signatures feat(DocumentViewer.jsx): Enable saving signature to user profile feat(DocumentViewer.jsx): Implement acknowledgment functionality with signature and notes feat(DocumentViewer.jsx): Add UI elements for signer name input and signature pad feat(DocumentViewer.jsx): Implement signature adoption from saved profile feat(DocumentViewer.jsx): Improve UI and UX for document review process feat(UpcomingOrdersCard.jsx): Create new component to display upcoming orders feat(UpcomingOrdersCard.jsx): Implement progress bar and status indicators feat(UpcomingOrdersCard.jsx): Add ETA calculation and display feat(UpcomingOrdersCard.jsx): Improve UI and UX for upcoming order display feat(ActivityLog.jsx): Implement safe date formatting to handle invalid dates feat(ClientDashboard.jsx): Implement client dashboard with key metrics and quick actions feat(ClientDashboard.jsx): Add analytics cards for cost, labor, and sales feat(ClientDashboard.jsx): Implement quick reorder functionality feat(ClientDashboard.jsx): Add spending trend chart feat(ClientDashboard.jsx): Improve UI and UX for client dashboard feat(ClientOrders.jsx): Implement client orders page with filtering and quick actions feat(ClientOrders.jsx): Add status badges and event details feat(ClientOrders.jsx): Improve UI and UX for client orders page feat(CreateEvent.jsx): Implement event creation page with AI assistant and form wizard feat(CreateEvent.jsx): Add AI assistant for extracting event data feat(CreateEvent.jsx): Implement form wizard for event creation feat(CreateEvent.jsx): Improve UI and UX for event creation page feat(EditBusiness.jsx): Add company logo URL input to edit business page feat(EditBusiness.jsx): Improve UI and UX for edit business page feat(EventDetail.jsx): Implement safe date formatting to handle invalid dates feat(PartnerManagement.jsx): enhance partner management page with consolidated business directory and operator metrics feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from business entities feat(PartnerManagement.jsx): add consolidated business directory from feat(ProcurementDashboard.jsx): add supplier onboarding tab with filtering and detail panel feat(ProcurementDashboard.jsx): implement supplier onboarding tab with filtering and detail panel feat(ProcurementDashboard.jsx): add document status badges and actions in supplier detail panel feat(ProcurementDashboard.jsx): add compliance health indicator to supplier detail panel feat(ProcurementDashboard.jsx): add document request functionality with toast notifications feat(ProcurementDashboard.jsx): add clear filters button and active filters display feat(ProcurementDashboard.jsx): improve supplier table UI and add empty state feat(ProcurementDashboard.jsx): add document type filter to supplier onboarding tab feat(ProcurementDashboard.jsx): add state filter to supplier onboarding tab feat(ProcurementDashboard.jsx): add document status and type filtering to onboarding tab feat(ProcurementDashboard.jsx): add summary counts for onboarding tab based on filtered suppliers feat(ProcurementDashboard.jsx): add document status and type filtering to onboarding tab feat(ProcurementDashboard.jsx): add document status and type filtering to onboarding tab feat(Reports.jsx): add safe date formatting to handle invalid dates feat(SmartVendorOnboarding.jsx): implement NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA signing step with signature capture feat(SmartVendorOnboarding.jsx): add NDA feat(VendorDashboard.jsx): overhaul vendor dashboard with new UI/UX feat(VendorDashboard.jsx): add AI insights and rapid orders sections feat(VendorDashboard.jsx): implement sales vs payroll chart and client analysis feat(VendorDashboard.jsx): enhance top performers and gold vendors sections feat(VendorDashboard.jsx): improve quick actions and today's metrics feat(VendorDashboard.jsx): integrate total revenue card and staff assignment feat(VendorOrders.jsx): enhance vendor orders page with rapid request support feat(VendorOrders.jsx): add rapid request badge and filter feat(WorkforceShifts.jsx): add safe date formatting to handle invalid dates
979 lines
39 KiB
JavaScript
979 lines
39 KiB
JavaScript
import React, { useState } from "react";
|
|
import { base44 } from "@/api/base44Client";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { Link, useNavigate } from "react-router-dom";
|
|
import { createPageUrl } from "@/utils";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Plus, Search, Calendar as CalendarIcon, Eye, Edit, Copy, X, RefreshCw } from "lucide-react";
|
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import StatusCard from "../components/events/StatusCard";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { format, isSameDay, parseISO, isWithinInterval, startOfDay, endOfDay, isValid } from "date-fns";
|
|
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
|
import EventHoverCard from "../components/events/EventHoverCard";
|
|
import QuickAssignPopover from "../components/events/QuickAssignPopover";
|
|
import { Calendar } from "@/components/ui/calendar";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
import { useToast } from "@/components/ui/use-toast";
|
|
import PageHeader from "../components/common/PageHeader";
|
|
|
|
const statusColors = {
|
|
Draft: "bg-gray-100 text-gray-800",
|
|
Active: "bg-green-100 text-green-800",
|
|
Pending: "bg-purple-100 text-purple-800",
|
|
Confirmed: "bg-blue-100 text-blue-800",
|
|
Assigned: "bg-yellow-100 text-yellow-800",
|
|
Completed: "bg-slate-100 text-slate-800",
|
|
Canceled: "bg-red-100 text-red-800",
|
|
Cancelled: "bg-red-100 text-red-800"
|
|
};
|
|
|
|
// Date range presets
|
|
const datePresets = [
|
|
{
|
|
label: "Today",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
return { from: startOfDay(today), to: endOfDay(today) };
|
|
}
|
|
},
|
|
{
|
|
label: "This week",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.setDate(today.getDate() - today.getDay())));
|
|
const end = endOfDay(new Date(today.setDate(today.getDate() - today.getDay() + 6)));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "This month",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.getFullYear(), today.getMonth(), 1));
|
|
const end = endOfDay(new Date(today.getFullYear(), today.getMonth() + 1, 0));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "This quarter",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const quarter = Math.floor(today.getMonth() / 3);
|
|
const start = startOfDay(new Date(today.getFullYear(), quarter * 3, 1));
|
|
const end = endOfDay(new Date(today.getFullYear(), quarter * 3 + 3, 0));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "This year",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.getFullYear(), 0, 1));
|
|
const end = endOfDay(new Date(today.getFullYear(), 11, 31));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "Last week",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const lastWeekStart = new Date(today);
|
|
lastWeekStart.setDate(today.getDate() - today.getDay() - 7);
|
|
const lastWeekEnd = new Date(today);
|
|
lastWeekEnd.setDate(today.getDate() - today.getDay() - 1);
|
|
return { from: startOfDay(lastWeekStart), to: endOfDay(lastWeekEnd) };
|
|
}
|
|
},
|
|
{
|
|
label: "Last month",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.getFullYear(), today.getMonth() - 1, 1));
|
|
const end = endOfDay(new Date(today.getFullYear(), today.getMonth(), 0));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "Last quarter",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const quarter = Math.floor(today.getMonth() / 3);
|
|
const prevQuarterMonth = quarter * 3 - 3;
|
|
const year = prevQuarterMonth < 0 ? today.getFullYear() - 1 : today.getFullYear();
|
|
const adjustedMonth = prevQuarterMonth < 0 ? prevQuarterMonth + 12 : prevQuarterMonth;
|
|
const start = startOfDay(new Date(year, adjustedMonth, 1));
|
|
const end = endOfDay(new Date(year, adjustedMonth + 3, 0));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "Last year",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.getFullYear() - 1, 0, 1));
|
|
const end = endOfDay(new Date(today.getFullYear() - 1, 11, 31));
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "Last 30 days",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.setDate(today.getDate() - 30)));
|
|
const end = endOfDay(new Date());
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "Last 90 days",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.setDate(today.getDate() - 90)));
|
|
const end = endOfDay(new Date());
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "Last 365 days",
|
|
getValue: () => {
|
|
const today = new Date();
|
|
const start = startOfDay(new Date(today.setDate(today.getDate() - 365)));
|
|
const end = endOfDay(new Date());
|
|
return { from: start, to: end };
|
|
}
|
|
},
|
|
{
|
|
label: "All time",
|
|
getValue: () => null
|
|
},
|
|
];
|
|
|
|
// Helper function to safely parse dates
|
|
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;
|
|
}
|
|
};
|
|
|
|
// Helper function to safely format dates
|
|
const safeFormatDate = (dateString, formatStr) => {
|
|
const date = safeParseDate(dateString);
|
|
if (!date) return "-";
|
|
try {
|
|
return format(date, formatStr);
|
|
} catch {
|
|
return "-";
|
|
}
|
|
};
|
|
|
|
// Safely format date range for presets
|
|
const safeFormatDateRange = (date, formatStr) => {
|
|
if (!date) return "";
|
|
try {
|
|
const validDate = date instanceof Date ? date : new Date(date);
|
|
if (!isValid(validDate)) return "";
|
|
return format(validDate, formatStr);
|
|
} catch {
|
|
return "";
|
|
}
|
|
};
|
|
|
|
export default function Events() {
|
|
const navigate = useNavigate();
|
|
const [activeTab, setActiveTab] = useState("all");
|
|
const [searchTerm, setSearchTerm] = useState("");
|
|
const [selectedDates, setSelectedDates] = useState([]);
|
|
const [dateRange, setDateRange] = useState(null);
|
|
const [selectionMode, setSelectionMode] = useState("multiple");
|
|
const [calendarOpen, setCalendarOpen] = useState(false);
|
|
const [showAlert, setShowAlert] = useState(true);
|
|
const { toast } = useToast();
|
|
const [selectedPreset, setSelectedPreset] = useState(null);
|
|
const [compareMode, setCompareMode] = useState(false);
|
|
|
|
const { data: events, isLoading } = useQuery({
|
|
queryKey: ['events'],
|
|
queryFn: () => base44.entities.Event.list('-date'),
|
|
initialData: [],
|
|
});
|
|
|
|
const getStatusCounts = () => {
|
|
const total = events.length;
|
|
const active = events.filter(e => e.status === "Active").length;
|
|
const pending = events.filter(e => e.status === "Pending" || e.status === "Assigned").length;
|
|
const confirmed = events.filter(e => e.status === "Confirmed").length;
|
|
const completed = events.filter(e => e.status === "Completed").length;
|
|
|
|
return {
|
|
active: { count: active, percentage: total ? Math.round((active / total) * 100) : 0 },
|
|
pending: { count: pending, percentage: total ? Math.round((pending / total) * 100) : 0 },
|
|
confirmed: { count: confirmed, percentage: total ? Math.round((confirmed / total) * 100) : 0 },
|
|
completed: { count: completed, percentage: total ? Math.round((completed / total) * 100) : 0 },
|
|
};
|
|
};
|
|
|
|
const getFilteredEvents = () => {
|
|
let filtered = events;
|
|
|
|
if (selectionMode === "range" && dateRange?.from) {
|
|
filtered = filtered.filter(e => {
|
|
const eventDate = safeParseDate(e.date);
|
|
if (!eventDate) return false;
|
|
|
|
if (dateRange.to) {
|
|
try {
|
|
return isWithinInterval(eventDate, {
|
|
start: startOfDay(dateRange.from),
|
|
end: endOfDay(dateRange.to)
|
|
});
|
|
} catch {
|
|
return false;
|
|
}
|
|
} else {
|
|
try {
|
|
return isSameDay(eventDate, dateRange.from);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
} else if (selectionMode === "multiple" && selectedDates.length > 0) {
|
|
filtered = filtered.filter(e => {
|
|
const eventDate = safeParseDate(e.date);
|
|
if (!eventDate) return false;
|
|
return selectedDates.some(selectedDate => {
|
|
try {
|
|
return isSameDay(eventDate, selectedDate);
|
|
} catch {
|
|
return false;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
if (activeTab === "last_minute") {
|
|
filtered = filtered.filter(e => e.event_type === "Last Minute Request");
|
|
} else if (activeTab === "upcoming") {
|
|
filtered = filtered.filter(e => {
|
|
const eventDate = safeParseDate(e.date);
|
|
return eventDate && eventDate > new Date();
|
|
});
|
|
} else if (activeTab === "active") {
|
|
filtered = filtered.filter(e => e.status === "Active");
|
|
} else if (activeTab === "canceled") {
|
|
filtered = filtered.filter(e => e.status === "Canceled" || e.status === "Cancelled");
|
|
} else if (activeTab === "past") {
|
|
filtered = filtered.filter(e => e.status === "Completed");
|
|
}
|
|
|
|
if (searchTerm) {
|
|
filtered = filtered.filter(e =>
|
|
e.event_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
e.hub?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
e.business_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
e.id?.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
}
|
|
|
|
return filtered;
|
|
};
|
|
|
|
const statusCounts = getStatusCounts();
|
|
const filteredEvents = getFilteredEvents();
|
|
|
|
const getTabCount = (tab) => {
|
|
if (tab === "all") return events.length;
|
|
if (tab === "last_minute") return events.filter(e => e.event_type === "Last Minute Request").length;
|
|
if (tab === "upcoming") {
|
|
return events.filter(e => {
|
|
const eventDate = safeParseDate(e.date);
|
|
return eventDate && eventDate > new Date();
|
|
}).length;
|
|
}
|
|
if (tab === "active") return events.filter(e => e.status === "Active").length;
|
|
if (tab === "canceled") return events.filter(e => e.status === "Canceled" || e.status === "Cancelled").length;
|
|
if (tab === "past") return events.filter(e => e.status === "Completed").length;
|
|
return 0;
|
|
};
|
|
|
|
const handleDateSelect = (date) => {
|
|
if (selectionMode === "multiple") {
|
|
setSelectedDates(prev => {
|
|
const exists = prev.some(d => {
|
|
try {
|
|
return isSameDay(d, date);
|
|
} catch {
|
|
return false;
|
|
}
|
|
});
|
|
if (exists) {
|
|
return prev.filter(d => {
|
|
try {
|
|
return !isSameDay(d, date);
|
|
} catch {
|
|
return true;
|
|
}
|
|
});
|
|
} else {
|
|
return [...prev, date];
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleRangeSelect = (range) => {
|
|
setDateRange(range);
|
|
};
|
|
|
|
const clearDates = () => {
|
|
setSelectedDates([]);
|
|
setDateRange(null);
|
|
setSelectedPreset(null);
|
|
setShowAlert(true);
|
|
};
|
|
|
|
const getDateSelectionText = () => {
|
|
try {
|
|
if (selectedPreset) {
|
|
if (selectedPreset === "All time") return "All time";
|
|
const preset = datePresets.find(p => p.label === selectedPreset);
|
|
if (preset) {
|
|
const range = preset.getValue();
|
|
if (range?.from && range?.to) {
|
|
return `${safeFormatDateRange(range.from, 'MMM d')} - ${safeFormatDateRange(range.to, 'MMM d, yyyy')}`;
|
|
} else if (range?.from) {
|
|
return safeFormatDateRange(range.from, 'MMM d, yyyy');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selectionMode === "range" && dateRange?.from) {
|
|
if (dateRange.to) {
|
|
return `${safeFormatDateRange(dateRange.from, 'MMM d')} - ${safeFormatDateRange(dateRange.to, 'MMM d, yyyy')}`;
|
|
}
|
|
return safeFormatDateRange(dateRange.from, 'MMM d, yyyy');
|
|
} else if (selectionMode === "multiple" && selectedDates.length > 0) {
|
|
if (selectedDates.length === 1) {
|
|
return safeFormatDateRange(selectedDates[0], 'MMM d, yyyy');
|
|
}
|
|
return `${selectedDates.length} dates selected`;
|
|
}
|
|
} catch {
|
|
return "Select dates";
|
|
}
|
|
return "Select dates";
|
|
};
|
|
|
|
const getEventCountForDate = (date) => {
|
|
return events.filter(e => {
|
|
const eventDate = safeParseDate(e.date);
|
|
if (!eventDate) return false;
|
|
try {
|
|
return isSameDay(eventDate, date);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}).length;
|
|
};
|
|
|
|
const handlePresetSelect = (preset) => {
|
|
setSelectedPreset(preset.label);
|
|
setCalendarOpen(false);
|
|
if (preset.label === "All time") {
|
|
setDateRange(null);
|
|
setSelectedDates([]);
|
|
setSelectionMode("range");
|
|
} else {
|
|
const range = preset.getValue();
|
|
setDateRange(range);
|
|
setSelectedDates([]);
|
|
setSelectionMode("range");
|
|
}
|
|
setShowAlert(true);
|
|
};
|
|
|
|
const getPresetDateRange = (preset) => {
|
|
if (preset.label === "All time") return "All dates";
|
|
const range = preset.getValue();
|
|
if (!range?.from) return "";
|
|
try {
|
|
if (range.to) {
|
|
return `${safeFormatDateRange(range.from, 'd MMM')} - ${safeFormatDateRange(range.to, 'd MMM, yyyy')}`;
|
|
}
|
|
return safeFormatDateRange(range.from, 'd MMM, yyyy');
|
|
} catch {
|
|
return "";
|
|
}
|
|
};
|
|
|
|
React.useEffect(() => {
|
|
if (showAlert && (filteredEvents.length > 0 && (selectedDates.length > 0 || dateRange?.from || selectedPreset === "All time"))) {
|
|
const timer = setTimeout(() => {
|
|
setShowAlert(false);
|
|
}, 5000);
|
|
return () => clearTimeout(timer);
|
|
}
|
|
}, [showAlert, filteredEvents.length, selectedDates.length, dateRange, selectedPreset]);
|
|
|
|
const handleReorder = (event) => {
|
|
const reorderData = {
|
|
event_name: event.event_name,
|
|
business_id: event.business_id,
|
|
business_name: event.business_name,
|
|
hub: event.hub,
|
|
event_location: event.event_location,
|
|
event_type: event.event_type,
|
|
requested: event.requested,
|
|
client_name: event.client_name,
|
|
client_email: event.client_email,
|
|
client_phone: event.client_phone,
|
|
client_address: event.client_address,
|
|
notes: event.notes,
|
|
};
|
|
|
|
sessionStorage.setItem('reorderData', JSON.stringify(reorderData));
|
|
|
|
toast({
|
|
title: "Reordering Event",
|
|
description: `Creating new order based on "${event.event_name}"`,
|
|
});
|
|
|
|
navigate(createPageUrl("CreateEvent") + "?reorder=true");
|
|
};
|
|
|
|
return (
|
|
<div className="p-4 md:p-8 bg-slate-50 min-h-screen">
|
|
<style>{`
|
|
/* 🎨 CALENDAR STYLING - Based on Reference Design */
|
|
|
|
/* Base day cell styling */
|
|
.rdp-day {
|
|
font-size: 0.875rem !important;
|
|
min-width: 36px !important;
|
|
height: 36px !important;
|
|
border-radius: 50% !important;
|
|
transition: all 0.2s ease !important;
|
|
font-weight: 500 !important;
|
|
position: relative !important;
|
|
}
|
|
|
|
/* Regular unselected dates */
|
|
.rdp-day button {
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
border-radius: 50% !important;
|
|
}
|
|
|
|
/* Selected range start date - Solid blue filled circle */
|
|
.rdp-day_range_start {
|
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
|
|
color: white !important;
|
|
font-weight: 700 !important;
|
|
border-radius: 50% !important;
|
|
box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important;
|
|
}
|
|
|
|
/* Selected range end date - Solid blue filled circle */
|
|
.rdp-day_range_end {
|
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
|
|
color: white !important;
|
|
font-weight: 700 !important;
|
|
border-radius: 50% !important;
|
|
box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important;
|
|
}
|
|
|
|
/* Single selected date - Solid blue filled circle */
|
|
.rdp-day_selected:not(.rdp-day_range_start):not(.rdp-day_range_end) {
|
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
|
|
color: white !important;
|
|
font-weight: 700 !important;
|
|
border-radius: 50% !important;
|
|
box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important;
|
|
}
|
|
|
|
/* Range middle dates - Light lavender/blue background */
|
|
.rdp-day_range_middle {
|
|
background-color: #e0e7ff !important;
|
|
color: #4f46e5 !important;
|
|
font-weight: 600 !important;
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
/* When start and end are the same day */
|
|
.rdp-day_range_start.rdp-day_range_end {
|
|
border-radius: 50% !important;
|
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
|
|
}
|
|
|
|
/* Hover effect - Light blue background */
|
|
.rdp-day:hover:not(.rdp-day_selected):not(.rdp-day_disabled):not(.rdp-day_range_start):not(.rdp-day_range_end):not(.rdp-day_range_middle) {
|
|
background-color: #eff6ff !important;
|
|
color: #2563eb !important;
|
|
border-radius: 50% !important;
|
|
}
|
|
|
|
/* Today indicator - Pink/magenta dot at bottom */
|
|
.rdp-day_today:not(.rdp-day_selected):not(.rdp-day_range_start):not(.rdp-day_range_end)::after {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
bottom: 4px !important;
|
|
left: 50% !important;
|
|
transform: translateX(-50%) !important;
|
|
width: 4px !important;
|
|
height: 4px !important;
|
|
background-color: #ec4899 !important;
|
|
border-radius: 50% !important;
|
|
}
|
|
|
|
/* Today with selection - adjust styling */
|
|
.rdp-day_today.rdp-day_selected,
|
|
.rdp-day_today.rdp-day_range_start,
|
|
.rdp-day_today.rdp-day_range_end {
|
|
color: white !important;
|
|
}
|
|
|
|
/* Disabled/outside dates - gray and muted */
|
|
.rdp-day_outside {
|
|
color: #cbd5e1 !important;
|
|
opacity: 0.5 !important;
|
|
}
|
|
|
|
.rdp-day_disabled {
|
|
opacity: 0.3 !important;
|
|
cursor: not-allowed !important;
|
|
}
|
|
|
|
/* Keep selected dates always visible */
|
|
.rdp-day_selected,
|
|
.rdp-day_range_start,
|
|
.rdp-day_range_end,
|
|
.rdp-day_range_middle {
|
|
opacity: 1 !important;
|
|
visibility: visible !important;
|
|
z-index: 5 !important;
|
|
}
|
|
|
|
/* Calendar header - weekday names */
|
|
.rdp-head_cell {
|
|
color: #64748b !important;
|
|
font-weight: 600 !important;
|
|
font-size: 0.75rem !important;
|
|
text-transform: uppercase !important;
|
|
padding: 8px 0 !important;
|
|
}
|
|
|
|
/* Month/Year navigation */
|
|
.rdp-caption_label {
|
|
font-size: 1rem !important;
|
|
font-weight: 700 !important;
|
|
color: #0f172a !important;
|
|
}
|
|
|
|
/* Navigation arrows */
|
|
.rdp-nav_button {
|
|
width: 32px !important;
|
|
height: 32px !important;
|
|
border-radius: 6px !important;
|
|
transition: all 0.2s ease !important;
|
|
}
|
|
|
|
.rdp-nav_button:hover {
|
|
background-color: #eff6ff !important;
|
|
color: #2563eb !important;
|
|
}
|
|
|
|
/* Event indicator dots */
|
|
.rdp-day.has-events:not(.rdp-day_selected):not(.rdp-day_range_start):not(.rdp-day_range_end)::before {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
top: 4px !important;
|
|
right: 4px !important;
|
|
width: 4px !important;
|
|
height: 4px !important;
|
|
background-color: #2563eb !important;
|
|
border-radius: 50% !important;
|
|
}
|
|
|
|
/* Selected dates with events - white dot */
|
|
.rdp-day_selected.has-events::before,
|
|
.rdp-day_range_start.has-events::before,
|
|
.rdp-day_range_end.has-events::before {
|
|
background-color: white !important;
|
|
}
|
|
|
|
/* Middle range dates with events - blue dot */
|
|
.rdp-day_range_middle.has-events::before {
|
|
background-color: #4f46e5 !important;
|
|
}
|
|
|
|
/* Calendar spacing */
|
|
.rdp-months {
|
|
gap: 2rem !important;
|
|
}
|
|
|
|
.rdp-month {
|
|
padding: 0.75rem !important;
|
|
}
|
|
|
|
.rdp-table {
|
|
border-spacing: 0 !important;
|
|
margin-top: 1rem !important;
|
|
}
|
|
|
|
/* Cell spacing */
|
|
.rdp-cell {
|
|
padding: 2px !important;
|
|
}
|
|
`}</style>
|
|
|
|
<div className="max-w-7xl mx-auto">
|
|
<PageHeader
|
|
title="Events Management"
|
|
subtitle={`Managing ${events.length} ${events.length === 1 ? 'event' : 'events'} • ${statusCounts.active.count} active`}
|
|
showUnpublished={true}
|
|
actions={
|
|
<Link to={createPageUrl("CreateEvent")}>
|
|
<Button className="bg-gradient-to-r from-[#2563eb] to-[#1C323E] hover:from-[#2563eb]/90 hover:to-[#1C323E]/90 text-white shadow-lg">
|
|
<Plus className="w-5 h-5 mr-2" />
|
|
Create Event
|
|
</Button>
|
|
</Link>
|
|
}
|
|
/>
|
|
|
|
{/* Enhanced Date Selection Section */}
|
|
<div className="bg-white rounded-xl p-6 mb-6 border border-slate-200 shadow-sm">
|
|
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
|
|
<div className="flex items-center gap-4">
|
|
<h3 className="font-semibold text-[#1C323E] text-lg">Select Event Dates</h3>
|
|
<div className="flex items-center gap-2 bg-slate-50 p-1 rounded-lg border border-slate-200">
|
|
<Button
|
|
size="sm"
|
|
variant={selectionMode === "multiple" ? "default" : "ghost"}
|
|
onClick={() => {
|
|
setSelectionMode("multiple");
|
|
setDateRange(null);
|
|
setSelectedPreset(null);
|
|
}}
|
|
className={selectionMode === "multiple" ? "bg-[#2563eb] hover:bg-[#2563eb]/90 text-white" : "text-slate-600 hover:text-slate-900 hover:bg-white"}
|
|
>
|
|
Multiple
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
variant={selectionMode === "range" ? "default" : "ghost"}
|
|
onClick={() => {
|
|
setSelectionMode("range");
|
|
setSelectedDates([]);
|
|
setSelectedPreset(null);
|
|
}}
|
|
className={selectionMode === "range" ? "bg-[#2563eb] hover:bg-[#2563eb]/90 text-white" : "text-slate-600 hover:text-slate-900 hover:bg-white"}
|
|
>
|
|
Range
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
variant="ghost"
|
|
onClick={clearDates}
|
|
className="text-red-600 hover:text-red-700 hover:bg-red-50"
|
|
>
|
|
Clear All
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<Popover open={calendarOpen} onOpenChange={setCalendarOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
className="border-[#2563eb] text-[#2563eb] hover:bg-[#2563eb]/5 hover:border-[#2563eb] font-medium min-w-[200px]"
|
|
>
|
|
<CalendarIcon className="w-4 h-4 mr-2" />
|
|
{getDateSelectionText()}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-auto p-0" align="end">
|
|
<div className="bg-white rounded-lg shadow-xl border border-slate-200 flex">
|
|
{/* Date Presets Sidebar */}
|
|
<div className="w-64 border-r border-slate-200 bg-slate-50 p-4 rounded-l-lg">
|
|
<h4 className="font-semibold text-sm text-slate-700 mb-3 uppercase tracking-wide">DATE RANGE</h4>
|
|
<div className="space-y-1">
|
|
{datePresets.map((preset) => (
|
|
<button
|
|
key={preset.label}
|
|
type="button"
|
|
onClick={() => handlePresetSelect(preset)}
|
|
className={`w-full text-left px-3 py-2 rounded-lg transition-all text-sm ${
|
|
selectedPreset === preset.label
|
|
? 'bg-[#2563eb] text-white font-medium shadow-sm'
|
|
: 'hover:bg-white text-slate-700 hover:shadow-sm'
|
|
}`}
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<span>{preset.label}</span>
|
|
</div>
|
|
{selectedPreset === preset.label && preset.label !== "All time" && (
|
|
<div className="text-xs mt-1 opacity-90">
|
|
{getPresetDateRange(preset)}
|
|
</div>
|
|
)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Compare Toggle */}
|
|
<div className="mt-6 pt-4 border-t border-slate-200">
|
|
<button
|
|
type="button"
|
|
onClick={() => setCompareMode(!compareMode)}
|
|
className={`w-full flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-all ${
|
|
compareMode
|
|
? 'bg-purple-100 text-purple-700 font-medium'
|
|
: 'text-slate-600 hover:bg-white'
|
|
}`}
|
|
>
|
|
<RefreshCw className="w-4 h-4" />
|
|
Compare
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Calendar Section */}
|
|
<div className="p-4">
|
|
<div className="mb-3">
|
|
<p className="font-semibold text-slate-900 text-sm">
|
|
{selectionMode === "range" ? "Select Date Range" : "Select Multiple Dates"}
|
|
</p>
|
|
<p className="text-xs text-slate-500 mt-1">
|
|
{selectionMode === "range"
|
|
? "Click start date, then end date"
|
|
: "Click dates to select/deselect"}
|
|
</p>
|
|
</div>
|
|
<Calendar
|
|
mode={selectionMode === "range" ? "range" : "multiple"}
|
|
selected={selectionMode === "range" ? dateRange : selectedDates}
|
|
onSelect={selectionMode === "range" ? handleRangeSelect : handleDateSelect}
|
|
numberOfMonths={2}
|
|
modifiers={{
|
|
hasEvents: (date) => getEventCountForDate(date) > 0
|
|
}}
|
|
modifiersClassNames={{
|
|
hasEvents: 'has-events'
|
|
}}
|
|
className="rounded-md border-0"
|
|
/>
|
|
<div className="flex items-center justify-between mt-4 pt-4 border-t border-slate-200">
|
|
<p className="text-xs text-slate-500">
|
|
Dates with <span className="font-semibold text-[#2563eb]">dot indicators</span> have events
|
|
</p>
|
|
<div className="flex gap-2">
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
onClick={() => {
|
|
setCalendarOpen(false);
|
|
clearDates();
|
|
}}
|
|
className="border-slate-300"
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
onClick={() => setCalendarOpen(false)}
|
|
className="bg-[#2563eb] hover:bg-[#2563eb]/90"
|
|
>
|
|
Confirm
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</div>
|
|
|
|
{(selectedDates.length > 0 || dateRange?.from || selectedPreset === "All time") && showAlert && filteredEvents.length > 0 && (
|
|
<Alert className="bg-[#2563eb]/5 border-[#2563eb]/20 relative mt-4">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="absolute top-2 right-2 h-6 w-6 text-[#2563eb] hover:bg-[#2563eb]/10"
|
|
onClick={() => setShowAlert(false)}
|
|
>
|
|
<X className="w-4 h-4" />
|
|
</Button>
|
|
<CalendarIcon className="h-4 w-4 text-[#2563eb]" />
|
|
<AlertDescription className="text-[#2563eb] font-medium pr-8">
|
|
{filteredEvents.length} event{filteredEvents.length !== 1 ? 's' : ''} found for selected date{selectionMode === "multiple" && selectedDates.length > 1 ? 's' : ''}
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</div>
|
|
|
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="mb-6">
|
|
<TabsList className="bg-white border border-slate-200 h-auto p-1 shadow-sm">
|
|
<TabsTrigger value="all" className="data-[state=active]:bg-[#2563eb] data-[state=active]:text-white">
|
|
Total Events <span className="ml-2 px-2 py-0.5 rounded-full bg-slate-100 data-[state=active]:bg-white/20 text-slate-700 data-[state=active]:text-white text-xs font-medium">{getTabCount("all")}</span>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="last_minute" className="data-[state=active]:bg-[#2563eb] data-[state=active]:text-white">
|
|
Last Minute <span className="ml-2 px-2 py-0.5 rounded-full bg-slate-100 data-[state=active]:bg-white/20 text-slate-700 data-[state=active]:text-white text-xs font-medium">{getTabCount("last_minute")}</span>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="upcoming" className="data-[state=active]:bg-[#2563eb] data-[state=active]:text-white">
|
|
Upcoming <span className="ml-2 px-2 py-0.5 rounded-full bg-slate-100 data-[state=active]:bg-white/20 text-slate-700 data-[state=active]:text-white text-xs font-medium">{getTabCount("upcoming")}</span>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="active" className="data-[state=active]:bg-[#2563eb] data-[state=active]:text-white">
|
|
Active <span className="ml-2 px-2 py-0.5 rounded-full bg-slate-100 data-[state=active]:bg-white/20 text-slate-700 data-[state=active]:text-white text-xs font-medium">{getTabCount("active")}</span>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="canceled" className="data-[state=active]:bg-[#2563eb] data-[state=active]:text-white">
|
|
Canceled <span className="ml-2 px-2 py-0.5 rounded-full bg-slate-100 data-[state=active]:bg-white/20 text-slate-700 data-[state=active]:text-white text-xs font-medium">{getTabCount("canceled")}</span>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="past" className="data-[state=active]:bg-[#2563eb] data-[state=active]:text-white">
|
|
Past <span className="ml-2 px-2 py-0.5 rounded-full bg-slate-100 data-[state=active]:bg-white/20 text-slate-700 data-[state=active]:text-white text-xs font-medium">{getTabCount("past")}</span>
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
</Tabs>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
<StatusCard status="Active" count={statusCounts.active.count} percentage={statusCounts.active.percentage} color="blue" />
|
|
<StatusCard status="Pending/Assigned" count={statusCounts.pending.count} percentage={statusCounts.pending.percentage} color="yellow" />
|
|
<StatusCard status="Confirmed" count={statusCounts.confirmed.count} percentage={statusCounts.confirmed.percentage} color="green" />
|
|
<StatusCard status="Completed" count={statusCounts.completed.count} percentage={statusCounts.completed.percentage} color="gray" />
|
|
</div>
|
|
|
|
<div className="bg-white rounded-xl p-4 mb-6 flex items-center gap-4 border border-slate-200 shadow-sm">
|
|
<div className="relative flex-1">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
|
|
<Input
|
|
placeholder="Search by ID, company, event name..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="pl-10 border-slate-300"
|
|
/>
|
|
</div>
|
|
<Avatar className="w-10 h-10 bg-slate-200">
|
|
<AvatarFallback className="bg-slate-200 text-slate-700 font-bold">M</AvatarFallback>
|
|
</Avatar>
|
|
</div>
|
|
|
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow className="bg-slate-100 hover:bg-slate-100">
|
|
<TableHead className="font-semibold text-slate-700">ID</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">Company Name</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">Hub</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">Status</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">Event Date</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">Event Name</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">PO</TableHead>
|
|
<TableHead className="font-semibold text-slate-700 text-center">Requested</TableHead>
|
|
<TableHead className="font-semibold text-slate-700 text-center">Assigned</TableHead>
|
|
<TableHead className="font-semibold text-slate-700 text-center" style={{width: "200px"}}>Actions</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{filteredEvents.length === 0 ? (
|
|
<TableRow>
|
|
<TableCell colSpan={10} className="text-center py-12 text-slate-500">
|
|
<CalendarIcon className="w-12 h-12 mx-auto mb-3 text-slate-300" />
|
|
<p className="font-medium">No events found</p>
|
|
<p className="text-sm mt-1">Try selecting different dates or adjusting your filters</p>
|
|
</TableCell>
|
|
</TableRow>
|
|
) : (
|
|
filteredEvents.map((event) => {
|
|
const assignedCount = event.assigned_staff?.length || 0;
|
|
const confirmedCount = event.assigned_staff?.filter(s => s.confirmed).length || 0;
|
|
|
|
return (
|
|
<EventHoverCard key={event.id} event={event}>
|
|
<TableRow className="hover:bg-slate-50 cursor-pointer transition-colors">
|
|
<TableCell className="font-medium text-slate-700">{event.id?.slice(-4).toUpperCase()}</TableCell>
|
|
<TableCell className="font-medium">{event.business_name || "Company Name"}</TableCell>
|
|
<TableCell>{event.hub || "-"}</TableCell>
|
|
<TableCell>
|
|
<Badge className={`${statusColors[event.status]} font-medium px-3 py-1`}>
|
|
{event.status}
|
|
</Badge>
|
|
{event.status === "Assigned" && confirmedCount > 0 && (
|
|
<Badge variant="outline" className="ml-1 text-xs border-green-500 text-green-700">
|
|
{confirmedCount}/{assignedCount} ✓
|
|
</Badge>
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="font-bold text-slate-700 text-base">
|
|
{safeFormatDate(event.date, "MM/dd/yyyy")}
|
|
</TableCell>
|
|
<TableCell className="font-medium">{event.event_name}</TableCell>
|
|
<TableCell>{event.po || event.po_number || "-"}</TableCell>
|
|
<TableCell className="text-center font-semibold">{event.requested || 0}</TableCell>
|
|
<TableCell className="text-center">
|
|
<QuickAssignPopover event={event}>
|
|
<button className={`hover:text-[#2563eb] font-semibold ${
|
|
assignedCount >= event.requested && event.requested > 0 ? 'text-green-600' : 'text-orange-600'
|
|
}`}>
|
|
{assignedCount}
|
|
</button>
|
|
</QuickAssignPopover>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center justify-center gap-1">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
navigate(createPageUrl(`EventDetail?id=${event.id}`));
|
|
}}
|
|
className="hover:text-[#2563eb] hover:bg-[#2563eb]/10"
|
|
title="View Details"
|
|
>
|
|
<Eye className="w-4 h-4" />
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
navigate(createPageUrl(`EditEvent?id=${event.id}`));
|
|
}}
|
|
className="hover:text-[#2563eb] hover:bg-[#2563eb]/10"
|
|
title="Edit Event"
|
|
>
|
|
<Edit className="w-4 h-4" />
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
handleReorder(event);
|
|
}}
|
|
className="bg-green-600 hover:bg-green-700 text-white px-3 py-1 h-8 text-xs font-semibold"
|
|
>
|
|
<RefreshCw className="w-3 h-3 mr-1" />
|
|
Reorder
|
|
</Button>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
</EventHoverCard>
|
|
);
|
|
})
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |