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
2995 lines
169 KiB
JavaScript
2995 lines
169 KiB
JavaScript
|
||
import React, { useState, useEffect } from "react";
|
||
import { base44 } from "@/api/base44Client";
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/components/ui/dialog";
|
||
import {
|
||
DollarSign,
|
||
TrendingUp,
|
||
Award,
|
||
FileText,
|
||
BarChart3,
|
||
Shield,
|
||
Calendar,
|
||
Download,
|
||
Upload,
|
||
CheckCircle2,
|
||
AlertCircle,
|
||
Target,
|
||
Building2,
|
||
Users,
|
||
LineChart,
|
||
PieChart,
|
||
Plus,
|
||
Edit,
|
||
Search,
|
||
ChevronLeft,
|
||
ChevronRight,
|
||
Clock, // Added Clock icon for onboarding tab
|
||
X // Added X icon for closing dialog/panel
|
||
} from "lucide-react";
|
||
import StatsCard from "../components/staff/StatsCard";
|
||
import W9FormViewer from "../components/procurement/W9FormViewer";
|
||
import COIViewer from "../components/procurement/COIViewer";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Label } from "@/components/ui/label";
|
||
import VendorDetailModal from "../components/procurement/VendorDetailModal";
|
||
import VendorHoverCard from "../components/procurement/VendorHoverCard";
|
||
import VendorScoreHoverCard from "../components/procurement/VendorScoreHoverCard"; // Added this import
|
||
import PageHeader from "../components/common/PageHeader";
|
||
import { useToast } from "@/components/ui/use-toast"; // Import useToast
|
||
|
||
export default function ProcurementDashboard() {
|
||
const [selectedYear, setSelectedYear] = useState("2025");
|
||
const [comparisonYear, setComparisonYear] = useState("2024");
|
||
const [selectedRegion, setSelectedRegion] = useState("all");
|
||
const [selectedVendor, setSelectedVendor] = useState("all");
|
||
const [selectedClient, setSelectedClient] = useState("all");
|
||
const [showW9Form, setShowW9Form] = useState(false);
|
||
const [showCOIViewer, setShowCOIViewer] = useState(false);
|
||
|
||
// New states for vendor directory filters and pagination
|
||
const [vendorSearch, setVendorSearch] = useState("");
|
||
const [vendorRegionFilter, setVendorRegionFilter] = useState("all");
|
||
const [vendorSpecialtyFilter, setVendorSpecialtyFilter] = useState("all");
|
||
const [vendorStateFilter, setVendorStateFilter] = useState("all");
|
||
const [vendorSoftwareFilter, setVendorSoftwareFilter] = useState("all");
|
||
const [currentPage, setCurrentPage] = useState(1);
|
||
const [itemsPerPage, setItemsPerPage] = useState(10);
|
||
const [viewMode, setViewMode] = useState("table"); // table or grid - currently only table is implemented
|
||
|
||
// New states for vendor detail modal
|
||
const [selectedVendorForDetail, setSelectedVendorForDetail] = useState(null);
|
||
const [showVendorDetail, setShowVendorDetail] = useState(false);
|
||
|
||
// New states for supplier onboarding tab
|
||
const [selectedSupplier, setSelectedSupplier] = useState(null);
|
||
const [supplierSearch, setSupplierSearch] = useState("");
|
||
const [supplierRegionFilter, setSupplierRegionFilter] = useState("all");
|
||
const [supplierCityFilter, setSupplierCityFilter] = useState("all");
|
||
const [supplierStateFilter, setSupplierStateFilter] = useState("all"); // NEW
|
||
const [supplierStatusFilter, setSupplierStatusFilter] = useState("all"); // NEW
|
||
const [supplierDocumentFilter, setSupplierDocumentFilter] = useState("all"); // NEW
|
||
|
||
const { toast } = useToast(); // Initialize useToast
|
||
|
||
const vendors = [
|
||
{ name: "Legendary Event Staffing", region: "Bay Area", state: "California", specialty: "Full Service Events", software: "Building platform (KROW)", softwareType: "building", employees: 450, fillRate: 97, onTimeRate: 98, csat: 4.7, spend: "$230k" },
|
||
{ name: "Instawork", region: "National", state: "Multiple", specialty: "On-Demand Gig Platform", software: "Full Platform", softwareType: "platform", employees: 5000, fillRate: 95, onTimeRate: 96, csat: 4.5, spend: "$215k" },
|
||
{ name: "Hospitality Staffing Solutions (HSS)", region: "Multi-Region", state: "Multiple", specialty: "Hospitality", software: "Partial Tech", softwareType: "partial", employees: 1250, fillRate: 94, onTimeRate: 95, csat: 4.4, spend: "$198k" },
|
||
{ name: "Bluecrew", region: "National", state: "Multiple", specialty: "W-2 Staffing Platform", software: "Full Platform", softwareType: "platform", employees: 3500, fillRate: 92, onTimeRate: 94, csat: 4.2, spend: "$185k" },
|
||
{ name: "Qwick", region: "Multi-Region", state: "Multiple", specialty: "Hospitality Platform", software: "Full Platform", softwareType: "platform", employees: 2800, fillRate: 91, onTimeRate: 93, csat: 4.1, spend: "$172k" },
|
||
{ name: "NorCal Staffing", region: "Northern California", state: "California", specialty: "Event-based staffing", software: "Traditional", softwareType: "traditional", employees: 280, fillRate: 89, onTimeRate: 91, csat: 3.9, spend: "$156k" },
|
||
{ name: "Jeff Duerson Staffing", region: "Bay Area", state: "California", specialty: "Catering/Events", software: "Traditional", softwareType: "traditional", employees: 175, fillRate: 88, onTimeRate: 90, csat: 3.8, spend: "$142k" },
|
||
{ name: "The Party Staff", region: "Bay Area", state: "California", specialty: "Event Staffing", software: "Internal System", softwareType: "traditional", employees: 320, fillRate: 87, onTimeRate: 89, csat: 3.7, spend: "$138k" },
|
||
{ name: "Flagship Culinary Services", region: "Bay Area", state: "California", specialty: "Culinary", software: "Internal System", softwareType: "partial", employees: 380, fillRate: 86, onTimeRate: 88, csat: 3.6, spend: "$125k" },
|
||
{ name: "Elite Hospitality Staffing", region: "Bay Area", state: "California", specialty: "Hotels/Events", software: "Traditional", softwareType: "traditional", employees: 290, fillRate: 85, onTimeRate: 87, csat: 3.5, spend: "$118k" },
|
||
{ name: "Kitchen & Cater Staffing", region: "Local", state: "California", specialty: "Catering", software: "Traditional", softwareType: "traditional", employees: 125, fillRate: 83, onTimeRate: 85, csat: 3.4, spend: "$95k" },
|
||
];
|
||
|
||
const onboardingSuppliers = [
|
||
// Bay Area - California
|
||
{
|
||
name: "Legendary Event Staffing",
|
||
ein: "45-8892013",
|
||
region: "Bay Area",
|
||
city: "San Francisco",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "Jane Smith", uploadDate: "01/15/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/10/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Jane Smith", uploadDate: "01/05/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Jane Smith", uploadDate: "01/15/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "06/30/2026", uploadedBy: "System", uploadDate: "12/20/2024" },
|
||
]
|
||
},
|
||
{
|
||
name: "The Party Staff",
|
||
ein: "93-1012832",
|
||
region: "Bay Area",
|
||
city: "Oakland",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "Admin", uploadDate: "01/10/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/05/2025" },
|
||
{ type: "NDA", status: "Missing", expires: "-", uploadedBy: "-", uploadDate: "-" },
|
||
{ type: "Contract", status: "Pending", expires: "-", uploadedBy: "-", uploadDate: "-" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/08/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/30/2026", uploadedBy: "System", uploadDate: "12/15/2024" },
|
||
]
|
||
},
|
||
{
|
||
name: "Elite Hospitality Staffing",
|
||
ein: "72-2281034",
|
||
region: "Bay Area",
|
||
city: "San Francisco",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "08/15/2026", uploadedBy: "ComplianceBot", uploadDate: "01/12/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/08/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/10/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "ComplianceBot", uploadDate: "01/12/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "07/20/2026", uploadedBy: "System", uploadDate: "01/02/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Jeff Duerson Staffing",
|
||
ein: "55-3029841",
|
||
region: "Bay Area",
|
||
city: "San Jose",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "Admin", uploadDate: "01/14/2025" },
|
||
{ type: "COI", status: "Approved", expires: "02/18/2026", uploadedBy: "Admin", uploadDate: "02/18/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/05/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/14/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/10/2026", uploadedBy: "System", uploadDate: "01/01/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Flagship Culinary Services",
|
||
ein: "81-9982734",
|
||
region: "Bay Area",
|
||
city: "Palo Alto",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "System", uploadDate: "01/11/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/08/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/10/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/11/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/09/2026", uploadedBy: "System", uploadDate: "12/28/2024" },
|
||
]
|
||
},
|
||
|
||
// Southern California
|
||
{
|
||
name: "LA Event Professionals",
|
||
ein: "44-1209382",
|
||
region: "Southern California",
|
||
city: "Los Angeles",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "05/11/2026", uploadedBy: "Admin", uploadDate: "01/16/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/09/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/12/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/16/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "11/15/2026", uploadedBy: "System", uploadDate: "01/03/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Hollywood Hospitality",
|
||
ein: "71-2817364",
|
||
region: "Southern California",
|
||
city: "Los Angeles",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "System", uploadDate: "01/13/2025" },
|
||
{ type: "COI", status: "Expiring Soon", expires: "12/20/2025", uploadedBy: "System", uploadDate: "12/20/2024" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/08/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/13/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "06/25/2026", uploadedBy: "System", uploadDate: "12/30/2024" },
|
||
]
|
||
},
|
||
{
|
||
name: "San Diego Event Staff",
|
||
ein: "67-4738291",
|
||
region: "Southern California",
|
||
city: "San Diego",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "Admin", uploadDate: "01/15/2025" },
|
||
{ type: "COI", status: "Missing", expires: "-", uploadedBy: "-", uploadDate: "-" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/10/2025" },
|
||
{ type: "Contract", status: "Pending", expires: "-", uploadedBy: "-", uploadDate: "-" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/15/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "08/30/2026", uploadedBy: "System", uploadDate: "01/05/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "OC Staffing Solutions",
|
||
ein: "92-1982734",
|
||
region: "Southern California",
|
||
city: "Orange County",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "04/14/2026", uploadedBy: "Jane Smith", uploadDate: "01/17/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/10/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Jane Smith", uploadDate: "01/11/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Jane Smith", uploadDate: "01/17/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/20/2026", uploadedBy: "System", uploadDate: "01/02/2025" },
|
||
]
|
||
},
|
||
|
||
// Northern California
|
||
{
|
||
name: "NorCal Staffing",
|
||
ein: "22-3344556",
|
||
region: "Northern California",
|
||
city: "Sacramento",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "06/20/2026", uploadedBy: "Admin", uploadDate: "01/18/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/12/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/15/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/18/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "08/15/2026", uploadedBy: "System", uploadDate: "01/04/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Kitchen & Cater Staffing",
|
||
ein: "33-5566778",
|
||
region: "Northern California",
|
||
city: "Sacramento",
|
||
state: "California",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "07/25/2026", uploadedBy: "System", uploadDate: "01/19/2025" },
|
||
{ type: "COI", status: "Expiring Soon", expires: "11/15/2025", uploadedBy: "System", uploadDate: "11/15/2024" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/12/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/19/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/25/2026", uploadedBy: "System", uploadDate: "01/06/2025" },
|
||
]
|
||
},
|
||
|
||
// National Platforms
|
||
{
|
||
name: "Instawork",
|
||
ein: "18-5629931",
|
||
region: "National",
|
||
city: "Multiple",
|
||
state: "Multiple",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "03/12/2026", uploadedBy: "System", uploadDate: "02/01/2025" },
|
||
{ type: "COI", status: "Expiring Soon", expires: "11/10/2025", uploadedBy: "System", uploadDate: "11/10/2024" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/15/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/20/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "08/15/2026", uploadedBy: "System", uploadDate: "01/05/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Hospitality Staffing Solutions (HSS)",
|
||
ein: "44-6677889",
|
||
region: "National",
|
||
city: "Multiple",
|
||
state: "Multiple",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "05/30/2026", uploadedBy: "Admin", uploadDate: "01/22/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/18/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/20/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/22/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/30/2026", uploadedBy: "System", uploadDate: "01/08/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Bluecrew",
|
||
ein: "55-7788990",
|
||
region: "National",
|
||
city: "Multiple",
|
||
state: "Multiple",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "04/18/2026", uploadedBy: "System", uploadDate: "01/21/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/17/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/19/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/21/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "11/20/2026", uploadedBy: "System", uploadDate: "01/07/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Qwick",
|
||
ein: "66-8899001",
|
||
region: "National",
|
||
city: "Multiple",
|
||
state: "Multiple",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "06/22/2026", uploadedBy: "Admin", uploadDate: "01/23/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/19/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/21/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/23/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "12/15/2026", uploadedBy: "System", uploadDate: "01/09/2025" },
|
||
]
|
||
},
|
||
|
||
// New York
|
||
{
|
||
name: "NYC Event Masters",
|
||
ein: "77-9900112",
|
||
region: "East Coast",
|
||
city: "New York City",
|
||
state: "New York",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "08/30/2026", uploadedBy: "Admin", uploadDate: "01/24/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/20/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/22/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/24/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "07/30/2026", uploadedBy: "System", uploadDate: "01/10/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Manhattan Staffing Group",
|
||
ein: "88-0011223",
|
||
region: "East Coast",
|
||
city: "Manhattan",
|
||
state: "New York",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "09/15/2026", uploadedBy: "System", uploadDate: "01/25/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/21/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/23/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/25/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/15/2026", uploadedBy: "System", uploadDate: "01/11/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Brooklyn Event Pros",
|
||
ein: "99-1122334",
|
||
region: "East Coast",
|
||
city: "Brooklyn",
|
||
state: "New York",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "07/10/2026", uploadedBy: "Admin", uploadDate: "01/26/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/22/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/24/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/26/2025" },
|
||
{ type: "Background Check", status: "Expiring Soon", expires: "11/25/2025", uploadedBy: "System", uploadDate: "11/25/2024" },
|
||
]
|
||
},
|
||
{
|
||
name: "Upstate Event Services",
|
||
ein: "11-2233445",
|
||
region: "East Coast",
|
||
city: "Buffalo",
|
||
state: "New York",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "05/25/2026", uploadedBy: "System", uploadDate: "01/27/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/23/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/25/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/27/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "06/15/2026", uploadedBy: "System", uploadDate: "12/18/2024" },
|
||
]
|
||
},
|
||
|
||
// Texas
|
||
{
|
||
name: "Lone Star Staffing",
|
||
ein: "22-3344556",
|
||
region: "South",
|
||
city: "Austin",
|
||
state: "Texas",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "08/05/2026", uploadedBy: "Admin", uploadDate: "01/28/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/24/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/26/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "01/28/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/10/2026", uploadedBy: "System", uploadDate: "01/12/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Houston Hospitality Hub",
|
||
ein: "33-4455667",
|
||
region: "South",
|
||
city: "Houston",
|
||
state: "Texas",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "04/28/2026", uploadedBy: "System", uploadDate: "01/29/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/25/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/27/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/29/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/20/2026", uploadedBy: "System", uploadDate: "01/13/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Dallas Event Specialists",
|
||
ein: "44-5566778",
|
||
region: "South",
|
||
city: "Dallas",
|
||
state: "Texas",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "06/12/2026", uploadedBy: "Admin", uploadDate: "01/30/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/26/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/28/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Pending", expires: "-", uploadedBy: "-", uploadDate: "-" },
|
||
{ type: "Background Check", status: "Approved", expires: "08/25/2026", uploadedBy: "System", uploadDate: "01/14/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "San Antonio Services",
|
||
ein: "55-6677889",
|
||
region: "South",
|
||
city: "San Antonio",
|
||
state: "Texas",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "07/18/2026", uploadedBy: "System", uploadDate: "01/31/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/27/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/29/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "01/31/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "11/10/2026", uploadedBy: "System", uploadDate: "01/15/2025" },
|
||
]
|
||
},
|
||
|
||
// Illinois
|
||
{
|
||
name: "Chicago Event Staffing",
|
||
ein: "66-7788990",
|
||
region: "Midwest",
|
||
city: "Chicago",
|
||
state: "Illinois",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "05/05/2026", uploadedBy: "Admin", uploadDate: "02/01/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/28/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/30/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/01/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "07/15/2026", uploadedBy: "System", uploadDate: "01/16/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Windy City Hospitality",
|
||
ein: "77-8899001",
|
||
region: "Midwest",
|
||
city: "Chicago",
|
||
state: "Illinois",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "09/20/2026", uploadedBy: "System", uploadDate: "02/02/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/29/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "01/31/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "02/02/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "08/30/2026", uploadedBy: "System", uploadDate: "01/17/2025" },
|
||
]
|
||
},
|
||
|
||
// Florida
|
||
{
|
||
name: "Miami Event Solutions",
|
||
ein: "88-9900112",
|
||
region: "South",
|
||
city: "Miami",
|
||
state: "Florida",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "04/15/2026", uploadedBy: "Admin", uploadDate: "02/03/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/30/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/01/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/03/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/20/2026", uploadedBy: "System", uploadDate: "01/18/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Orlando Hospitality Group",
|
||
ein: "99-0011223",
|
||
region: "South",
|
||
city: "Orlando",
|
||
state: "Florida",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "06/08/2026", uploadedBy: "System", uploadDate: "02/04/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "01/31/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/02/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "02/04/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "11/30/2026", uploadedBy: "System", uploadDate: "01/19/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Tampa Bay Staffing",
|
||
ein: "11-1122334",
|
||
region: "South",
|
||
city: "Tampa",
|
||
state: "Florida",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "05/20/2026", uploadedBy: "Admin", uploadDate: "02/05/2025" },
|
||
{ type: "COI", status: "Expiring Soon", expires: "11/30/2025", uploadedBy: "System", uploadDate: "11/30/2024" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/03/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/05/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/05/2026", uploadedBy: "System", uploadDate: "01/20/2025" },
|
||
]
|
||
},
|
||
|
||
// Washington
|
||
{
|
||
name: "Seattle Event Pros",
|
||
ein: "22-2233445",
|
||
region: "West",
|
||
city: "Seattle",
|
||
state: "Washington",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "08/12/2026", uploadedBy: "System", uploadDate: "02/06/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/01/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/04/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "02/06/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "12/10/2026", uploadedBy: "System", uploadDate: "01/21/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Pacific Northwest Staffing",
|
||
ein: "33-3344556",
|
||
region: "West",
|
||
city: "Seattle",
|
||
state: "Washington",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "07/22/2026", uploadedBy: "Admin", uploadDate: "02/07/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/02/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/05/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/07/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "11/05/2026", uploadedBy: "System", uploadDate: "01/22/2025" },
|
||
]
|
||
},
|
||
|
||
// Massachusetts
|
||
{
|
||
name: "Boston Event Services",
|
||
ein: "44-4455667",
|
||
region: "East Coast",
|
||
city: "Boston",
|
||
state: "Massachusetts",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "09/08/2026", uploadedBy: "System", uploadDate: "02/08/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/03/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/06/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "02/08/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/25/2026", uploadedBy: "System", uploadDate: "01/23/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "New England Hospitality",
|
||
ein: "55-5566778",
|
||
region: "East Coast",
|
||
city: "Boston",
|
||
state: "Massachusetts",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "05/14/2026", uploadedBy: "Admin", uploadDate: "02/09/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/04/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/07/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/09/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "06/20/2026", uploadedBy: "System", uploadDate: "12/22/2024" },
|
||
]
|
||
},
|
||
|
||
// Georgia
|
||
{
|
||
name: "Atlanta Event Staffing",
|
||
ein: "66-6677889",
|
||
region: "South",
|
||
city: "Atlanta",
|
||
state: "Georgia",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "08/18/2026", uploadedBy: "System", uploadDate: "02/10/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/05/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/08/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "02/10/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "09/15/2026", uploadedBy: "System", uploadDate: "01/24/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Peach State Hospitality",
|
||
ein: "77-7788990",
|
||
region: "South",
|
||
city: "Atlanta",
|
||
state: "Georgia",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "06/25/2026", uploadedBy: "Admin", uploadDate: "02/11/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/06/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/09/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/11/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "08/10/2026", uploadedBy: "System", uploadDate: "01/25/2025" },
|
||
]
|
||
},
|
||
|
||
// Colorado
|
||
{
|
||
name: "Denver Event Solutions",
|
||
ein: "88-8899001",
|
||
region: "West",
|
||
city: "Denver",
|
||
state: "Colorado",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "07/30/2026", uploadedBy: "System", uploadDate: "02/12/2025" },
|
||
{ type: "COI", status: "Approved", expires: "12/31/2025", uploadedBy: "System", uploadDate: "02/07/2025" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/10/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "System", uploadDate: "02/12/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "10/28/2026", uploadedBy: "System", uploadDate: "01/26/2025" },
|
||
]
|
||
},
|
||
{
|
||
name: "Rocky Mountain Staffing",
|
||
ein: "99-9900112",
|
||
region: "West",
|
||
city: "Denver",
|
||
state: "Colorado",
|
||
documents: [
|
||
{ type: "W9", status: "Approved", expires: "04/10/2026", uploadedBy: "Admin", uploadDate: "02/13/2025" },
|
||
{ type: "COI", status: "Expiring Soon", expires: "12/05/2025", uploadedBy: "System", uploadDate: "12/05/2024" },
|
||
{ type: "NDA", status: "Approved", expires: "12/31/2026", uploadedBy: "Admin", uploadDate: "02/11/2025" },
|
||
{ type: "Contract", status: "Approved", expires: "12/31/2025", uploadedBy: "Admin", uploadDate: "01/01/2025" },
|
||
{ type: "Banking Info", status: "Approved", expires: "-", uploadedBy: "Admin", uploadDate: "02/13/2025" },
|
||
{ type: "Background Check", status: "Approved", expires: "07/05/2026", uploadedBy: "System", uploadDate: "12/28/2024" },
|
||
]
|
||
},
|
||
];
|
||
|
||
// Get top 5 vendors sorted by fill rate
|
||
const topVendors = [...vendors]
|
||
.sort((a, b) => b.fillRate - a.fillRate)
|
||
.slice(0, 5);
|
||
|
||
const { data: events } = useQuery({
|
||
queryKey: ['events'],
|
||
queryFn: () => base44.entities.Event.list(),
|
||
initialData: [],
|
||
});
|
||
|
||
const totalSpend = 2300000;
|
||
const fillRate = 97;
|
||
const vendorScore = "A+";
|
||
const compliance = 98;
|
||
|
||
// Derive unique filter options for the new filters
|
||
const uniqueRegions = [...new Set(vendors.map(v => v.region))];
|
||
const uniqueSpecialties = [...new Set(vendors.map(v => v.specialty))];
|
||
const uniqueStates = [...new Set(vendors.map(v => v.state))];
|
||
|
||
// Derive unique filter options for onboarding suppliers
|
||
const uniqueSupplierRegions = [...new Set(onboardingSuppliers.map(s => s.region))];
|
||
const uniqueSupplierCities = [...new Set(onboardingSuppliers.map(s => s.city))];
|
||
const uniqueSupplierStates = [...new Set(onboardingSuppliers.map(s => s.state))];
|
||
const uniqueDocumentTypes = [...new Set(onboardingSuppliers.flatMap(s => s.documents.map(d => d.type)))];
|
||
|
||
// Apply filters to vendors
|
||
const filteredVendors = vendors.filter(vendor => {
|
||
const matchesSearch = !vendorSearch ||
|
||
vendor.name.toLowerCase().includes(vendorSearch.toLowerCase()) ||
|
||
vendor.specialty.toLowerCase().includes(vendorSearch.toLowerCase());
|
||
|
||
const matchesRegion = vendorRegionFilter === "all" || vendor.region === vendorRegionFilter;
|
||
const matchesSpecialty = vendorSpecialtyFilter === "all" || vendor.specialty === vendorSpecialtyFilter;
|
||
const matchesState = vendorStateFilter === "all" || vendor.state === vendorStateFilter;
|
||
const matchesSoftware = vendorSoftwareFilter === "all" || vendor.softwareType === vendorSoftwareFilter;
|
||
|
||
return matchesSearch && matchesRegion && matchesSpecialty && matchesState && matchesSoftware;
|
||
});
|
||
|
||
// Apply filters to onboarding suppliers
|
||
const filteredOnboardingSuppliers = onboardingSuppliers.filter(supplier => {
|
||
// Search filter
|
||
const matchesSearch = !supplierSearch ||
|
||
supplier.name.toLowerCase().includes(supplierSearch.toLowerCase()) ||
|
||
supplier.ein.includes(supplierSearch);
|
||
|
||
// Location filters
|
||
const matchesRegion = supplierRegionFilter === "all" || supplier.region === supplierRegionFilter;
|
||
const matchesCity = supplierCityFilter === "all" || supplier.city === supplierCityFilter;
|
||
const matchesState = supplierStateFilter === "all" || supplier.state === supplierStateFilter;
|
||
|
||
// FIXED: Combined status and document filter
|
||
// When both are active, find documents that match BOTH criteria
|
||
let matchesStatusAndDocument = true;
|
||
if (supplierStatusFilter !== "all" || supplierDocumentFilter !== "all") {
|
||
matchesStatusAndDocument = supplier.documents.some(doc => {
|
||
const matchesStatus = supplierStatusFilter === "all" || doc.status === supplierStatusFilter;
|
||
const matchesDocument = supplierDocumentFilter === "all" || doc.type === supplierDocumentFilter;
|
||
return matchesStatus && matchesDocument;
|
||
});
|
||
}
|
||
|
||
return matchesSearch && matchesRegion && matchesCity && matchesState && matchesStatusAndDocument;
|
||
});
|
||
|
||
// Recalculate summary counts for onboarding tab based on filtered suppliers
|
||
const fullyCompliantCount = filteredOnboardingSuppliers.filter(s => s.documents.every(d => d.status === "Approved")).length;
|
||
const pendingReviewCount = filteredOnboardingSuppliers.filter(s => s.documents.some(d => d.status === "Expiring Soon" || d.status === "Pending") && s.documents.every(d => d.status !== "Missing")).length;
|
||
const actionRequiredCount = filteredOnboardingSuppliers.filter(s => s.documents.some(d => d.status === "Missing")).length;
|
||
|
||
// Pagination logic for vendors
|
||
const totalPages = Math.ceil(filteredVendors.length / itemsPerPage);
|
||
const startIndex = (currentPage - 1) * itemsPerPage;
|
||
const endIndex = startIndex + itemsPerPage;
|
||
const paginatedVendors = filteredVendors.slice(startIndex, endIndex);
|
||
|
||
// Reset to page 1 when filters change
|
||
useEffect(() => {
|
||
setCurrentPage(1);
|
||
}, [vendorSearch, vendorRegionFilter, vendorSpecialtyFilter, vendorStateFilter, vendorSoftwareFilter, itemsPerPage]);
|
||
|
||
const handleVendorClick = (vendor) => {
|
||
setSelectedVendorForDetail(vendor);
|
||
setShowVendorDetail(true);
|
||
};
|
||
|
||
const handleEditVendor = (vendor) => {
|
||
setShowVendorDetail(false);
|
||
// Add actual edit functionality here, e.g., open an edit form
|
||
console.log("Edit vendor:", vendor.name);
|
||
// Example: Router.push(`/admin/vendors/edit/${vendor.id}`);
|
||
};
|
||
|
||
|
||
return (
|
||
<div className="p-4 md:p-8 bg-slate-50 min-h-screen">
|
||
<div className="max-w-7xl mx-auto">
|
||
<PageHeader
|
||
title="Procurement Dashboard"
|
||
subtitle="Vendor management, compliance tracking, and cost analytics"
|
||
>
|
||
<div className="flex gap-3">
|
||
<Button variant="outline" className="border-slate-300 hover:bg-slate-100 hover:text-[#1C323E]">
|
||
<Download className="w-4 h-4 mr-2" />
|
||
Export Report
|
||
</Button>
|
||
<Button className="bg-[#0A39DF] hover:bg-[#0A39DF]/90 text-white">
|
||
<Upload className="w-4 h-4 mr-2" />
|
||
Upload Documents
|
||
</Button>
|
||
</div>
|
||
</PageHeader>
|
||
|
||
{/* Key Metrics */}
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||
<StatsCard
|
||
title="Total Spend"
|
||
value={`$${(totalSpend / 1000000).toFixed(1)}M`}
|
||
icon={DollarSign}
|
||
gradient="bg-gradient-to-br from-[#0A39DF] to-[#1C323E]"
|
||
change="+$180K this month"
|
||
/>
|
||
<StatsCard
|
||
title="Fill Rate"
|
||
value={`${fillRate}%`}
|
||
icon={Target}
|
||
gradient="bg-gradient-to-br from-emerald-500 to-emerald-700"
|
||
change="+2.5% vs last month"
|
||
/>
|
||
<StatsCard
|
||
title="Vendor Score"
|
||
value={vendorScore}
|
||
icon={Award}
|
||
gradient="bg-gradient-to-br from-slate-600 to-slate-800"
|
||
/>
|
||
<StatsCard
|
||
title="Compliance"
|
||
value={`${compliance}%`}
|
||
icon={Shield}
|
||
gradient="bg-gradient-to-br from-purple-500 to-purple-700"
|
||
change="All certifications valid"
|
||
/>
|
||
</div>
|
||
|
||
{/* Main Tabs */}
|
||
<Tabs defaultValue="overview" className="mb-8">
|
||
<div className="bg-white rounded-xl shadow-md border border-slate-200 p-2 mb-6 overflow-x-auto">
|
||
<TabsList className="w-full h-auto bg-transparent flex-wrap justify-start gap-2">
|
||
<TabsTrigger
|
||
value="overview"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<BarChart3 className="w-4 h-4 mr-2" />
|
||
Overview
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="onboarding"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<Building2 className="w-4 h-4 mr-2" />
|
||
Supplier Onboarding
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="contracts"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<FileText className="w-4 h-4 mr-2" />
|
||
Contracts & Rates
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="po"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<FileText className="w-4 h-4 mr-2" />
|
||
Purchase Orders
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="invoices"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<CheckCircle2 className="w-4 h-4 mr-2" />
|
||
Invoice Matching
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="analytics"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<TrendingUp className="w-4 h-4 mr-2" />
|
||
Spend Analytics
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="audit"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<Shield className="w-4 h-4 mr-2" />
|
||
Audit Trail
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="compliance"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<Shield className="w-4 h-4 mr-2" />
|
||
Compliance & Documents
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="vendors"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<Award className="w-4 h-4 mr-2" />
|
||
Vendor Scorecards
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="trends"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<LineChart className="w-4 h-4 mr-2" />
|
||
Trends & SLA
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="reports"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<BarChart3 className="w-4 h-4 mr-2" />
|
||
Reports & Analytics
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="forecasting"
|
||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#0A39DF] data-[state=active]:to-[#1C323E] data-[state=active]:text-white data-[state=active]:shadow-lg hover:bg-slate-50 transition-all duration-200 rounded-lg px-4 py-2.5 text-sm font-medium"
|
||
>
|
||
<Calendar className="w-4 h-4 mr-2" />
|
||
Forecasting
|
||
</TabsTrigger>
|
||
</TabsList>
|
||
</div>
|
||
|
||
{/* Overview Tab */}
|
||
<TabsContent value="overview">
|
||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
{/* Vendor Efficiency Scorecard */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Award className="w-5 h-5 text-[#0A39DF]" />
|
||
Vendor Efficiency Scorecard
|
||
</CardTitle>
|
||
<p className="text-xs text-slate-500">Top 5 vendors by performance • Hover for details • Click to view full profile</p>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b border-slate-200">
|
||
<th className="text-left py-2 font-semibold">Vendor</th>
|
||
<th className="text-center py-2 font-semibold">Fill %</th>
|
||
<th className="text-center py-2 font-semibold">On-time %</th>
|
||
<th className="text-center py-2 font-semibold">CSAT</th>
|
||
<th className="text-right py-2 font-semibold">Spend</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{topVendors.map((vendor, idx) => (
|
||
<VendorScoreHoverCard key={idx} vendor={vendor}>
|
||
<tr
|
||
className="border-b border-slate-100 hover:bg-blue-50 transition-colors cursor-pointer"
|
||
onClick={() => handleVendorClick(vendor)}
|
||
>
|
||
<td className="py-3 font-medium text-[#1C323E] hover:text-[#0A39DF] transition-colors">
|
||
{vendor.name}
|
||
</td>
|
||
<td className={`text-center font-semibold ${
|
||
vendor.fillRate >= 95 ? 'text-green-600' :
|
||
vendor.fillRate >= 90 ? 'text-blue-600' : 'text-amber-600'
|
||
}`}>
|
||
{vendor.fillRate}%
|
||
</td>
|
||
<td className={`text-center font-semibold ${
|
||
vendor.onTimeRate >= 95 ? 'text-green-600' :
|
||
vendor.onTimeRate >= 90 ? 'text-blue-600' : 'text-amber-600'
|
||
}`}>
|
||
{vendor.onTimeRate}%
|
||
</td>
|
||
<td className="text-center font-medium">{vendor.csat}</td>
|
||
<td className="text-right font-semibold text-[#0A39DF]">{vendor.spend}</td>
|
||
</tr>
|
||
</VendorScoreHoverCard>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div className="mt-4 p-3 bg-blue-50 rounded-lg border border-blue-200">
|
||
<p className="text-xs text-slate-700">
|
||
<span className="font-semibold text-[#0A39DF]">Top Performer:</span> {topVendors[0]?.name} with {topVendors[0]?.fillRate}% fill rate
|
||
</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Spend vs Outcome */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<TrendingUp className="w-5 h-5 text-[#0A39DF]" />
|
||
Spend vs Outcome
|
||
</CardTitle>
|
||
<p className="text-xs text-slate-500">Cost efficiency analysis</p>
|
||
</CardHeader>
|
||
<CardContent className="p-6 space-y-4">
|
||
{topVendors.slice(0, 3).map((vendor, idx) => (
|
||
<div key={idx}>
|
||
<div className="flex justify-between items-center mb-2">
|
||
<span className="text-sm font-medium truncate mr-2">{vendor.name}</span>
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-xs font-semibold">{vendor.fillRate}%</span>
|
||
<span className="text-xs text-slate-500">Reliability</span>
|
||
</div>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-3">
|
||
<div
|
||
className={`h-3 rounded-full ${
|
||
vendor.fillRate >= 95 ? 'bg-gradient-to-r from-green-500 to-green-600' :
|
||
vendor.fillRate >= 90 ? 'bg-gradient-to-r from-blue-500 to-blue-600' :
|
||
'bg-gradient-to-r from-amber-500 to-amber-600'
|
||
}`}
|
||
style={{ width: `${vendor.fillRate}%` }}
|
||
/>
|
||
</div>
|
||
<p className="text-xs text-slate-600 mt-1">Spend: {vendor.spend}</p>
|
||
</div>
|
||
))}
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Compliance Snapshot */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<div className="flex justify-between items-center">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Shield className="w-5 h-5 text-[#0A39DF]" />
|
||
Compliance Snapshot
|
||
</CardTitle>
|
||
<p className="text-xs text-slate-500">Audit readiness across controls</p>
|
||
</div>
|
||
<Badge className="bg-blue-100 text-blue-700">Auto-sync</Badge>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<p className="text-xs text-slate-600 mb-1">COI</p>
|
||
<div className="flex items-center gap-2">
|
||
<CheckCircle2 className="w-4 h-4 text-green-600" />
|
||
<span className="font-semibold text-green-700">100% valid</span>
|
||
</div>
|
||
</div>
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<p className="text-xs text-slate-600 mb-1">Background Checks</p>
|
||
<div className="flex items-center gap-2">
|
||
<CheckCircle2 className="w-4 h-4 text-green-600" />
|
||
<span className="font-semibold text-green-700">100% valid</span>
|
||
</div>
|
||
</div>
|
||
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
|
||
<p className="text-xs text-slate-600 mb-1">Alcohol Training</p>
|
||
<div className="flex items-center gap-2">
|
||
<AlertCircle className="w-4 h-4 text-amber-600" />
|
||
<span className="font-semibold text-amber-700">Expiring soon</span>
|
||
</div>
|
||
</div>
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<p className="text-xs text-slate-600 mb-1">ServSafe</p>
|
||
<div className="flex items-center gap-2">
|
||
<CheckCircle2 className="w-4 h-4 text-green-600" />
|
||
<span className="font-semibold text-green-700">100% valid</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Supplier Onboarding & Risk Management Tab */}
|
||
<TabsContent value="onboarding">
|
||
<div className="grid grid-cols-12 gap-6">
|
||
{/* Left Side: Supplier Table */}
|
||
<div className={selectedSupplier ? "col-span-8" : "col-span-12"}>
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-blue-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Building2 className="w-5 h-5 text-[#0A39DF]" />
|
||
Supplier Onboarding & Risk Management
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">Collects vendor W-9s, COIs, banking, background-check attestations</p>
|
||
</div>
|
||
<Button className="bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
<Plus className="w-4 h-4 mr-2" />
|
||
Add New Vendor
|
||
</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
{/* Summary Cards */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2 flex items-center gap-2">
|
||
<CheckCircle2 className="w-5 h-5 text-green-600" />
|
||
Fully Compliant
|
||
</h4>
|
||
<p className="text-3xl font-bold text-green-700">
|
||
{fullyCompliantCount}
|
||
</p>
|
||
<p className="text-xs text-slate-600 mt-1">All documents valid</p>
|
||
</div>
|
||
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2 flex items-center gap-2">
|
||
<Clock className="w-5 h-5 text-amber-600" />
|
||
Pending Review
|
||
</h4>
|
||
<p className="text-3xl font-bold text-amber-700">
|
||
{pendingReviewCount}
|
||
</p>
|
||
<p className="text-xs text-slate-600 mt-1">Awaiting approval or expiring soon</p>
|
||
</div>
|
||
<div className="p-4 bg-red-50 rounded-lg border border-red-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2 flex items-center gap-2">
|
||
<AlertCircle className="w-5 h-5 text-red-600" />
|
||
Action Required
|
||
</h4>
|
||
<p className="text-3xl font-bold text-red-700">
|
||
{actionRequiredCount}
|
||
</p>
|
||
<p className="text-xs text-slate-600 mt-1">Missing documents</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Search and Filters */}
|
||
<div className="mb-6 space-y-4">
|
||
<div className="relative">
|
||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400" />
|
||
<Input
|
||
placeholder="Search by supplier name or EIN..."
|
||
value={supplierSearch}
|
||
onChange={(e) => setSupplierSearch(e.target.value)}
|
||
className="pl-10 h-11 border-slate-300"
|
||
/>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 gap-4">
|
||
<div>
|
||
<Label htmlFor="supplier-region" className="text-xs font-medium text-slate-700 mb-1.5 block">Region</Label>
|
||
<Select value={supplierRegionFilter} onValueChange={setSupplierRegionFilter}>
|
||
<SelectTrigger id="supplier-region" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Regions</SelectItem>
|
||
{uniqueSupplierRegions.map(region => (
|
||
<SelectItem key={region} value={region}>{region}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="supplier-state" className="text-xs font-medium text-slate-700 mb-1.5 block">State</Label>
|
||
<Select value={supplierStateFilter} onValueChange={setSupplierStateFilter}>
|
||
<SelectTrigger id="supplier-state" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All States</SelectItem>
|
||
{uniqueSupplierStates.map(state => (
|
||
<SelectItem key={state} value={state}>{state}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="supplier-city" className="text-xs font-medium text-slate-700 mb-1.5 block">City</Label>
|
||
<Select value={supplierCityFilter} onValueChange={setSupplierCityFilter}>
|
||
<SelectTrigger id="supplier-city" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Cities</SelectItem>
|
||
{uniqueSupplierCities.map(city => (
|
||
<SelectItem key={city} value={city}>{city}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="supplier-status" className="text-xs font-medium text-slate-700 mb-1.5 block">Status</Label>
|
||
<Select value={supplierStatusFilter} onValueChange={setSupplierStatusFilter}>
|
||
<SelectTrigger id="supplier-status" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Statuses</SelectItem>
|
||
<SelectItem value="Approved">Approved</SelectItem>
|
||
<SelectItem value="Expiring Soon">Expiring Soon</SelectItem>
|
||
<SelectItem value="Missing">Missing</SelectItem>
|
||
<SelectItem value="Pending">Pending</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="supplier-document-type" className="text-xs font-medium text-slate-700 mb-1.5 block">Document</Label>
|
||
<Select value={supplierDocumentFilter} onValueChange={setSupplierDocumentFilter}>
|
||
<SelectTrigger id="supplier-document-type" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Documents</SelectItem>
|
||
{uniqueDocumentTypes.map(docType => (
|
||
<SelectItem key={docType} value={docType}>{docType}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="flex items-end">
|
||
<Button
|
||
variant="outline"
|
||
onClick={() => {
|
||
setSupplierSearch("");
|
||
setSupplierRegionFilter("all");
|
||
setSupplierCityFilter("all");
|
||
setSupplierStateFilter("all");
|
||
setSupplierStatusFilter("all");
|
||
setSupplierDocumentFilter("all");
|
||
}}
|
||
className="w-full border-slate-300"
|
||
>
|
||
Clear Filters
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
{(supplierSearch || supplierRegionFilter !== "all" || supplierCityFilter !== "all" || supplierStateFilter !== "all" || supplierStatusFilter !== "all" || supplierDocumentFilter !== "all") && (
|
||
<div className="flex items-center gap-2 flex-wrap mt-4 p-4 bg-gradient-to-r from-slate-50 to-blue-50/30 rounded-lg border border-slate-200">
|
||
<span className="text-sm font-semibold text-[#1C323E]">Active filters:</span>
|
||
{supplierSearch && (
|
||
<Badge variant="outline" className="bg-white text-[#1C323E] border-[#0A39DF] hover:bg-[#0A39DF]/5 transition-colors gap-2">
|
||
<span className="font-medium">Search:</span> {supplierSearch}
|
||
<button onClick={() => setSupplierSearch("")} className="hover:text-[#0A39DF] font-bold">×</button>
|
||
</Badge>
|
||
)}
|
||
{supplierRegionFilter !== "all" && (
|
||
<Badge variant="outline" className="bg-white text-[#1C323E] border-[#0A39DF] hover:bg-[#0A39DF]/5 transition-colors gap-2">
|
||
<span className="font-medium">Region:</span> {supplierRegionFilter}
|
||
<button onClick={() => setSupplierRegionFilter("all")} className="hover:text-[#0A39DF] font-bold">×</button>
|
||
</Badge>
|
||
)}
|
||
{supplierStateFilter !== "all" && (
|
||
<Badge variant="outline" className="bg-white text-[#1C323E] border-[#0A39DF] hover:bg-[#0A39DF]/5 transition-colors gap-2">
|
||
<span className="font-medium">State:</span> {supplierStateFilter}
|
||
<button onClick={() => setSupplierStateFilter("all")} className="hover:text-[#0A39DF] font-bold">×</button>
|
||
</Badge>
|
||
)}
|
||
{supplierCityFilter !== "all" && (
|
||
<Badge variant="outline" className="bg-white text-[#1C323E] border-[#0A39DF] hover:bg-[#0A39DF]/5 transition-colors gap-2">
|
||
<span className="font-medium">City:</span> {supplierCityFilter}
|
||
<button onClick={() => setSupplierCityFilter("all")} className="hover:text-[#0A39DF] font-bold">×</button>
|
||
</Badge>
|
||
)}
|
||
{supplierStatusFilter !== "all" && (
|
||
<Badge variant="outline" className="bg-white text-[#1C323E] border-[#0A39DF] hover:bg-[#0A39DF]/5 transition-colors gap-2">
|
||
<span className="font-medium">Status:</span> {supplierStatusFilter}
|
||
<button onClick={() => setSupplierStatusFilter("all")} className="hover:text-[#0A39DF] font-bold">×</button>
|
||
</Badge>
|
||
)}
|
||
{supplierDocumentFilter !== "all" && (
|
||
<Badge variant="outline" className="bg-white text-[#1C323E] border-[#0A39DF] hover:bg-[#0A39DF]/5 transition-colors gap-2">
|
||
<span className="font-medium">Document:</span> {supplierDocumentFilter}
|
||
<button onClick={() => setSupplierDocumentFilter("all")} className="hover:text-[#0A39DF] font-bold">×</button>
|
||
</Badge>
|
||
)}
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={() => {
|
||
setSupplierSearch("");
|
||
setSupplierRegionFilter("all");
|
||
setSupplierCityFilter("all");
|
||
setSupplierStateFilter("all");
|
||
setSupplierStatusFilter("all");
|
||
setSupplierDocumentFilter("all");
|
||
}}
|
||
className="text-red-600 hover:text-red-700 hover:bg-red-50 font-medium ml-2"
|
||
>
|
||
Clear all
|
||
</Button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Suppliers Table */}
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b-2 border-slate-300">
|
||
<th className="text-left py-3 px-2 font-semibold">Supplier</th>
|
||
<th className="text-left py-3 px-2 font-semibold">EIN</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Region</th>
|
||
<th className="text-left py-3 px-2 font-semibold">State</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Documents</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Compliance</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Action</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{filteredOnboardingSuppliers.length > 0 ? (
|
||
filteredOnboardingSuppliers.map((supplier, idx) => {
|
||
const totalDocs = supplier.documents.length;
|
||
const approvedDocs = supplier.documents.filter(d => d.status === "Approved").length;
|
||
const expiringDocs = supplier.documents.filter(d => d.status === "Expiring Soon").length;
|
||
const missingDocs = supplier.documents.filter(d => d.status === "Missing" || d.status === "Pending").length;
|
||
|
||
const compliancePercentage = totalDocs > 0 ? Math.round((approvedDocs / totalDocs) * 100) : 0;
|
||
const overallStatus = missingDocs > 0 ? "Action Required" : expiringDocs > 0 ? "Expiring Soon" : "Fully Compliant";
|
||
|
||
return (
|
||
<tr
|
||
key={idx}
|
||
onClick={() => setSelectedSupplier(supplier)}
|
||
className="border-b border-slate-100 hover:bg-blue-50 transition-colors cursor-pointer"
|
||
>
|
||
<td className="py-4 px-2 font-semibold text-[#1C323E]">{supplier.name}</td>
|
||
<td className="py-4 px-2 text-slate-600 font-mono text-xs">{supplier.ein}</td>
|
||
<td className="py-4 px-2 text-slate-600">{supplier.region}</td>
|
||
<td className="py-4 px-2 text-slate-600">{supplier.state}</td>
|
||
<td className="py-4 px-2 text-center">
|
||
<div className="flex items-center justify-center gap-2">
|
||
<span className="font-semibold text-[#0A39DF]">{approvedDocs}/{totalDocs}</span>
|
||
<span className="text-xs text-slate-500">Complete</span>
|
||
</div>
|
||
</td>
|
||
<td className="py-4 px-2 text-center">
|
||
<div className="flex flex-col items-center gap-1">
|
||
<Badge className={
|
||
overallStatus === "Fully Compliant" ? "bg-green-100 text-green-700" :
|
||
overallStatus === "Expiring Soon" ? "bg-amber-100 text-amber-700" :
|
||
"bg-red-100 text-red-700"
|
||
}>
|
||
{overallStatus}
|
||
</Badge>
|
||
<span className="text-xs font-semibold text-slate-600">{compliancePercentage}%</span>
|
||
</div>
|
||
</td>
|
||
<td className="py-4 px-2 text-center">
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
setSelectedSupplier(supplier);
|
||
}}
|
||
>
|
||
<FileText className="w-4 h-4 mr-1" />
|
||
View All
|
||
</Button>
|
||
</td>
|
||
</tr>
|
||
);
|
||
})
|
||
) : (
|
||
<tr>
|
||
<td colSpan="7" className="py-12 text-center">
|
||
<Building2 className="w-12 h-12 mx-auto text-slate-300 mb-3" />
|
||
<p className="text-slate-600 font-medium">No suppliers found</p>
|
||
<p className="text-sm text-slate-500 mt-1">Try adjusting your search or filters</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pain Point Solved</h4>
|
||
<p className="text-sm text-slate-700">✓ Ensures legal & insurance compliance across all vendors</p>
|
||
<p className="text-sm text-slate-700 mt-1">✓ Centralizes all vendor documentation in one place</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* Right Side: Detail Panel */}
|
||
{selectedSupplier && (
|
||
<div className="col-span-4">
|
||
<Card className="border-slate-200 shadow-2xl sticky top-4">
|
||
<CardHeader className="bg-gradient-to-br from-blue-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base">{selectedSupplier.name}</CardTitle>
|
||
<p className="text-xs text-slate-500 mt-1">{selectedSupplier.region} • {selectedSupplier.city}</p>
|
||
</div>
|
||
<Button variant="ghost" size="icon" onClick={() => setSelectedSupplier(null)}>
|
||
<X className="w-5 h-5 text-slate-500" />
|
||
</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6 space-y-6">
|
||
{/* Supplier Details */}
|
||
<div className="space-y-3 text-sm pb-6 border-b border-slate-200">
|
||
<div className="flex justify-between">
|
||
<span className="text-slate-600 font-medium">EIN:</span>
|
||
<span className="font-mono font-semibold text-[#1C323E]">{selectedSupplier.ein}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-slate-600 font-medium">State:</span>
|
||
<Badge variant="outline" className="font-semibold">
|
||
{selectedSupplier.state}
|
||
</Badge>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-slate-600 font-medium">Region:</span>
|
||
<span className="font-semibold">{selectedSupplier.region}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-slate-600 font-medium">Location:</span>
|
||
<span className="font-semibold">{selectedSupplier.city}</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* All Documents List */}
|
||
<div>
|
||
<h4 className="font-semibold text-slate-700 mb-3 flex items-center gap-2">
|
||
<FileText className="w-4 h-4 text-[#0A39DF]" />
|
||
All Documents ({selectedSupplier.documents.length})
|
||
</h4>
|
||
<div className="space-y-2">
|
||
{selectedSupplier.documents.map((doc, idx) => (
|
||
<div
|
||
key={idx}
|
||
className="p-3 bg-slate-50 rounded-lg border border-slate-200 hover:border-[#0A39DF] hover:shadow-sm transition-all cursor-pointer"
|
||
>
|
||
<div className="flex items-center justify-between mb-2">
|
||
<div className="flex items-center gap-2">
|
||
<FileText className="w-4 h-4 text-[#0A39DF]" />
|
||
<span className="font-semibold text-[#1C323E]">{doc.type}</span>
|
||
</div>
|
||
<Badge className={
|
||
doc.status === "Approved" ? "bg-green-100 text-green-700 text-xs" :
|
||
doc.status === "Expiring Soon" ? "bg-amber-100 text-amber-700 text-xs" :
|
||
doc.status === "Pending" ? "bg-blue-100 text-blue-700 text-xs" :
|
||
"bg-red-100 text-red-700 text-xs"
|
||
}>
|
||
{doc.status}
|
||
</Badge>
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-2 text-xs text-slate-600">
|
||
<div>
|
||
<span className="text-slate-500">Uploaded:</span> {doc.uploadDate}
|
||
</div>
|
||
<div>
|
||
<span className="text-slate-500">By:</span> {doc.uploadedBy}
|
||
</div>
|
||
{doc.expires !== "-" && (
|
||
<div className="col-span-2">
|
||
<span className="text-slate-500">Expires:</span>
|
||
<span className={doc.status === "Expiring Soon" ? "text-amber-600 font-semibold ml-1" : "ml-1"}>
|
||
{doc.expires}
|
||
</span>
|
||
</div>
|
||
)}
|
||
</div>
|
||
{(doc.status !== "Missing" && doc.status !== "Pending") && (
|
||
<div className="mt-2 flex gap-2">
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
className="flex-1 text-xs h-8"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
toast({
|
||
title: "Opening Document",
|
||
description: `Viewing ${doc.type} for ${selectedSupplier.name}`,
|
||
});
|
||
window.open('#', '_blank'); // Placeholder for actual document view
|
||
}}
|
||
>
|
||
<FileText className="w-3 h-3 mr-1" />
|
||
View
|
||
</Button>
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
className="flex-1 text-xs h-8"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
toast({
|
||
title: "Downloading",
|
||
description: `Downloading ${doc.type}...`,
|
||
});
|
||
}}
|
||
>
|
||
<Download className="w-3 h-3 mr-1" />
|
||
Download
|
||
</Button>
|
||
</div>
|
||
)}
|
||
{(doc.status === "Missing" || doc.status === "Pending") && (
|
||
<Button
|
||
variant="destructive"
|
||
size="sm"
|
||
className="w-full mt-2 text-xs h-8"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
toast({
|
||
title: "Request Sent",
|
||
description: `Upload request sent to ${selectedSupplier.name} for ${doc.type}`,
|
||
});
|
||
}}
|
||
>
|
||
<AlertCircle className="w-3 h-3 mr-1" />
|
||
Request Upload
|
||
</Button>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Risk Rating */}
|
||
<div className="border-t border-slate-200 pt-6">
|
||
<h4 className="font-semibold text-slate-700 mb-2">Compliance Health</h4>
|
||
<div className="flex items-center gap-3 mb-2">
|
||
<Badge className={
|
||
selectedSupplier.documents.filter(d => d.status === "Approved").length === selectedSupplier.documents.length
|
||
? "bg-green-100 text-green-700 text-lg font-bold px-4 py-1"
|
||
: selectedSupplier.documents.filter(d => d.status === "Missing" || d.status === "Pending").length > 0
|
||
? "bg-red-100 text-red-700 text-lg font-bold px-4 py-1"
|
||
: "bg-amber-100 text-amber-700 text-lg font-bold px-4 py-1"
|
||
}>
|
||
{selectedSupplier.documents.filter(d => d.status === "Approved").length === selectedSupplier.documents.length
|
||
? "Excellent"
|
||
: selectedSupplier.documents.filter(d => d.status === "Missing" || d.status === "Pending").length > 0
|
||
? "Action Required"
|
||
: "Good"}
|
||
</Badge>
|
||
<span className="text-2xl font-bold text-[#0A39DF]">
|
||
{selectedSupplier.documents.length > 0 ? Math.round((selectedSupplier.documents.filter(d => d.status === "Approved").length / selectedSupplier.documents.length) * 100) : 0}%
|
||
</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2 mb-3">
|
||
<div
|
||
className={`h-2 rounded-full ${
|
||
selectedSupplier.documents.filter(d => d.status === "Approved").length === selectedSupplier.documents.length
|
||
? "bg-gradient-to-r from-green-500 to-green-600"
|
||
: selectedSupplier.documents.filter(d => d.status === "Missing" || d.status === "Pending").length > 0
|
||
? "bg-gradient-to-r from-red-500 to-red-600"
|
||
: "bg-gradient-to-r from-amber-500 to-amber-600"
|
||
}`}
|
||
style={{ width: `${selectedSupplier.documents.length > 0 ? Math.round((selectedSupplier.documents.filter(d => d.status === "Approved").length / selectedSupplier.documents.length) * 100) : 0}%` }}
|
||
/>
|
||
</div>
|
||
<div className="text-xs text-slate-600 space-y-1">
|
||
<p>Documents Complete: <span className="font-semibold">{selectedSupplier.documents.filter(d => d.status === "Approved").length}/{selectedSupplier.documents.length}</span></p>
|
||
<p>Expiring Soon: <span className="font-semibold text-amber-600">{selectedSupplier.documents.filter(d => d.status === "Expiring Soon").length}</span></p>
|
||
<p>Missing/Pending: <span className="font-semibold text-red-600">{selectedSupplier.documents.filter(d => d.status === "Missing" || d.status === "Pending").length}</span></p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Action Buttons */}
|
||
<div className="space-y-3 border-t border-slate-200 pt-6">
|
||
<Button
|
||
className="w-full bg-[#0A39DF] hover:bg-[#0A39DF]/90 text-white"
|
||
onClick={() => {
|
||
toast({
|
||
title: "Generating Report",
|
||
description: `Creating compliance report for ${selectedSupplier.name}...`,
|
||
});
|
||
}}
|
||
>
|
||
<FileText className="w-4 h-4 mr-2" />
|
||
Generate Compliance Report
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
className="w-full border-slate-300"
|
||
onClick={() => {
|
||
toast({
|
||
title: "Downloading",
|
||
description: `Downloading all documents for ${selectedSupplier.name}...`,
|
||
});
|
||
}}
|
||
>
|
||
<Download className="w-4 h-4 mr-2" />
|
||
Download All Documents
|
||
</Button>
|
||
{selectedSupplier.documents.some(d => d.status === "Missing" || d.status === "Pending") && (
|
||
<Button
|
||
variant="destructive"
|
||
className="w-full"
|
||
onClick={() => {
|
||
const missingDocs = selectedSupplier.documents.filter(d => d.status === "Missing" || d.status === "Pending");
|
||
toast({
|
||
title: "Request Sent",
|
||
description: `Document request sent to ${selectedSupplier.name} for ${missingDocs.length} missing document(s)`,
|
||
});
|
||
}}
|
||
>
|
||
<AlertCircle className="w-4 h-4 mr-2" />
|
||
Send Document Request
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Contract Repository & Rate Controls Tab */}
|
||
<TabsContent value="contracts">
|
||
<div className="grid grid-cols-1 gap-6">
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-purple-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<FileText className="w-5 h-5 text-[#0A39DF]" />
|
||
Contract Repository & Rate Controls
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">Stores agreements, rate cards, and ensures invoice matches rate</p>
|
||
</div>
|
||
<Button className="bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
<Plus className="w-4 h-4 mr-2" />
|
||
Upload Contract
|
||
</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Active Contracts</h4>
|
||
<p className="text-3xl font-bold text-blue-700">11</p>
|
||
<p className="text-xs text-slate-600 mt-1">Across all vendors</p>
|
||
</div>
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Rate Cards</h4>
|
||
<p className="text-3xl font-bold text-green-700">11</p>
|
||
<p className="text-xs text-slate-600 mt-1">Up to date</p>
|
||
</div>
|
||
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Expiring Soon</h4>
|
||
<p className="text-3xl font-bold text-amber-700">2</p>
|
||
<p className="text-xs text-slate-600 mt-1">Within 60 days</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b-2 border-slate-300">
|
||
<th className="text-left py-3 px-2 font-semibold">Vendor</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Contract Type</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Start Date</th>
|
||
<th className="text-left py-3 px-2 font-semibold">End Date</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Rate Card</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Status</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Actions</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ vendor: "Legendary Event Staffing", type: "Master Service Agreement", start: "01/01/2024", end: "12/31/2025", rate: "Active", status: "Active" },
|
||
{ vendor: "Instawork", type: "Platform Agreement", start: "03/15/2024", end: "03/14/2026", rate: "Active", status: "Active" },
|
||
{ vendor: "NorCal Staffing", type: "Service Agreement", start: "06/01/2024", end: "05/31/2025", rate: "Active", status: "Expiring Soon" },
|
||
].map((contract, idx) => (
|
||
<tr key={idx} className="border-b border-slate-100 hover:bg-slate-50">
|
||
<td className="py-4 px-2 font-semibold">{contract.vendor}</td>
|
||
<td className="py-4 px-2">{contract.type}</td>
|
||
<td className="py-4 px-2">{contract.start}</td>
|
||
<td className="py-4 px-2">{contract.end}</td>
|
||
<td className="py-4 px-2 text-center">
|
||
<Badge className="bg-green-100 text-green-700">{contract.rate}</Badge>
|
||
</td>
|
||
<td className="py-4 px-2 text-center">
|
||
<Badge className={contract.status === "Active" ? "bg-green-100 text-green-700" : "bg-amber-100 text-amber-700"}>
|
||
{contract.status}
|
||
</Badge>
|
||
</td>
|
||
<td className="py-4 px-2">
|
||
<div className="flex items-center justify-center gap-2">
|
||
<Button variant="ghost" size="sm">
|
||
<Download className="w-4 h-4" />
|
||
</Button>
|
||
<Button variant="ghost" size="sm">
|
||
<Edit className="w-4 h-4" />
|
||
</Button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pain Point Solved</h4>
|
||
<p className="text-sm text-slate-700">✓ Prevents overbilling and non-approved pricing</p>
|
||
<p className="text-sm text-slate-700 mt-1">✓ Ensures all invoices match agreed-upon rates</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Purchase Orders & Approvals Tab */}
|
||
<TabsContent value="po">
|
||
<div className="grid grid-cols-1 gap-6">
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-green-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<FileText className="w-5 h-5 text-[#0A39DF]" />
|
||
Purchase Orders (POs) & Approvals
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">Issues and tracks approved orders from Compass units</p>
|
||
</div>
|
||
<Button className="bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
<Plus className="w-4 h-4 mr-2" />
|
||
Create PO
|
||
</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6">
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Total POs</h4>
|
||
<p className="text-3xl font-bold text-blue-700">156</p>
|
||
<p className="text-xs text-slate-600 mt-1">This month</p>
|
||
</div>
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Approved</h4>
|
||
<p className="text-3xl font-bold text-green-700">142</p>
|
||
<p className="text-xs text-slate-600 mt-1">91% approval rate</p>
|
||
</div>
|
||
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pending</h4>
|
||
<p className="text-3xl font-bold text-amber-700">12</p>
|
||
<p className="text-xs text-slate-600 mt-1">Awaiting approval</p>
|
||
</div>
|
||
<div className="p-4 bg-red-50 rounded-lg border border-red-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Rejected</h4>
|
||
<p className="text-3xl font-bold text-red-700">2</p>
|
||
<p className="text-xs text-slate-600 mt-1">Requires revision</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b-2 border-slate-300">
|
||
<th className="text-left py-3 px-2 font-semibold">PO Number</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Vendor</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Event</th>
|
||
<th className="text-right py-3 px-2 font-semibold">Amount</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Status</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Created</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Actions</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{[
|
||
{ po: "PO-2025-0234", vendor: "Legendary Event Staffing", event: "Google Holiday Party", amount: "$12,450", status: "Approved", created: "01/15/2025" },
|
||
{ po: "PO-2025-0235", vendor: "Instawork", event: "Samsung Tech Summit", amount: "$8,200", status: "Approved", created: "01/15/2025" },
|
||
{ po: "PO-2025-0236", vendor: "NorCal Staffing", event: "Nvidia Conference", amount: "$15,600", status: "Pending", created: "01/16/2025" },
|
||
].map((po, idx) => (
|
||
<tr key={idx} className="border-b border-slate-100 hover:bg-slate-50">
|
||
<td className="py-4 px-2 font-semibold text-[#0A39DF]">{po.po}</td>
|
||
<td className="py-4 px-2">{po.vendor}</td>
|
||
<td className="py-4 px-2">{po.event}</td>
|
||
<td className="py-4 px-2 text-right font-semibold">{po.amount}</td>
|
||
<td className="py-4 px-2 text-center">
|
||
<Badge className={po.status === "Approved" ? "bg-green-100 text-green-700" : "bg-amber-100 text-amber-700"}>
|
||
{po.status}
|
||
</Badge>
|
||
</td>
|
||
<td className="py-4 px-2 text-center">{po.created}</td>
|
||
<td className="py-4 px-2">
|
||
<div className="flex items-center justify-center gap-2">
|
||
<Button variant="ghost" size="sm">
|
||
<Download className="w-4 h-4" />
|
||
</Button>
|
||
<Button variant="ghost" size="sm">
|
||
<Edit className="w-4 h-4" />
|
||
</Button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pain Point Solved</h4>
|
||
<p className="text-sm text-slate-700">✓ Keeps spend pre-approved before payment</p>
|
||
<p className="text-sm text-slate-700 mt-1">✓ Tracks all orders from Compass units in one place</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Invoice Matching (3-way match) Tab */}
|
||
<TabsContent value="invoices">
|
||
<div className="grid grid-cols-1 gap-6">
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-amber-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<CheckCircle2 className="w-5 h-5 text-[#0A39DF]" />
|
||
Invoice Matching (3-way match)
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">Matches PO → Invoice → Receipt</p>
|
||
</div>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Perfect Match</h4>
|
||
<p className="text-3xl font-bold text-green-700">138</p>
|
||
<p className="text-xs text-slate-600 mt-1">All 3 documents match</p>
|
||
</div>
|
||
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Variance</h4>
|
||
<p className="text-3xl font-bold text-amber-700">4</p>
|
||
<p className="text-xs text-slate-600 mt-1">Minor discrepancies</p>
|
||
</div>
|
||
<div className="p-4 bg-red-50 rounded-lg border border-red-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Failed Match</h4>
|
||
<p className="text-3xl font-bold text-red-700">0</p>
|
||
<p className="text-xs text-slate-600 mt-1">Requires investigation</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-4">
|
||
<h4 className="font-semibold text-[#1C323E]">Recent Invoice Matches</h4>
|
||
{[
|
||
{ invoice: "INV-2025-0234", po: "PO-2025-0234", vendor: "Legendary Event Staffing", amount: "$12,450", status: "Matched", variance: "$0.00" },
|
||
{ invoice: "INV-2025-0235", po: "PO-2025-0235", vendor: "Instawork", amount: "$8,200", status: "Matched", variance: "$0.00" },
|
||
{ invoice: "INV-2025-0236", vendor: "NorCal Staffing", amount: "$15,675", status: "Variance", variance: "+$75.00" },
|
||
].map((item, idx) => (
|
||
<div key={idx} className="p-4 bg-slate-50 rounded-lg border border-slate-200">
|
||
<div className="flex items-center justify-between mb-3">
|
||
<div>
|
||
<p className="font-semibold text-[#1C323E]">{item.invoice}</p>
|
||
<p className="text-sm text-slate-600">PO: {item.po} • {item.vendor}</p>
|
||
</div>
|
||
<Badge className={item.status === "Matched" ? "bg-green-100 text-green-700" : "bg-amber-100 text-amber-700"}>
|
||
{item.status}
|
||
</Badge>
|
||
</div>
|
||
<div className="grid grid-cols-3 gap-4 text-sm">
|
||
<div>
|
||
<p className="text-slate-500">Invoice Amount</p>
|
||
<p className="font-semibold">{item.amount}</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-500">Variance</p>
|
||
<p className={`font-semibold ${item.variance !== "$0.00" ? "text-amber-600" : "text-green-600"}`}>
|
||
{item.variance}
|
||
</p>
|
||
</div>
|
||
<div className="flex items-end justify-end gap-2">
|
||
<Button variant="ghost" size="sm">
|
||
View Details
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pain Point Solved</h4>
|
||
<p className="text-sm text-slate-700">✓ Prevents payment errors and fraud</p>
|
||
<p className="text-sm text-slate-700 mt-1">✓ Automated matching saves hours of manual work</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Spend Analytics & Budgeting Tab */}
|
||
<TabsContent value="analytics">
|
||
<div className="grid grid-cols-1 gap-6">
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-indigo-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<BarChart3 className="w-5 h-5 text-[#0A39DF]" />
|
||
Spend Analytics & Budgeting
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">Dashboards by vendor, region, and category</p>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6">
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Total Spend</h4>
|
||
<p className="text-3xl font-bold text-blue-700">$2.3M</p>
|
||
<p className="text-xs text-slate-600 mt-1">YTD 2025</p>
|
||
</div>
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Budget Used</h4>
|
||
<p className="text-3xl font-bold text-green-700">78%</p>
|
||
<p className="text-xs text-slate-600 mt-1">$2.2M remaining</p>
|
||
</div>
|
||
<div className="p-4 bg-purple-50 rounded-lg border border-purple-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Top Vendor</h4>
|
||
<p className="text-lg font-bold text-purple-700">Legendary</p>
|
||
<p className="text-xs text-slate-600 mt-1">$580K spend</p>
|
||
</div>
|
||
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Cost Savings</h4>
|
||
<p className="text-3xl font-bold text-amber-700">$180K</p>
|
||
<p className="text-xs text-slate-600 mt-1">vs last year</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<div>
|
||
<h4 className="font-semibold text-[#1C323E] mb-4">Spend by Vendor</h4>
|
||
<div className="space-y-3">
|
||
{[
|
||
{ vendor: "Legendary Event Staffing", amount: "$580K", percentage: 25 },
|
||
{ vendor: "Instawork", amount: "$420K", percentage: 18 },
|
||
{ vendor: "HSS", amount: "$380K", percentage: 17 },
|
||
{ vendor: "Bluecrew", amount: "$340K", percentage: 15 },
|
||
{ vendor: "Others", amount: "$580K", percentage: 25 },
|
||
].map((item, idx) => (
|
||
<div key={idx}>
|
||
<div className="flex justify-between mb-1">
|
||
<span className="text-sm font-medium">{item.vendor}</span>
|
||
<span className="text-sm font-bold text-[#0A39DF]">{item.amount}</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div
|
||
className="bg-gradient-to-r from-[#0A39DF] to-[#1C323E] h-2 rounded-full"
|
||
style={{ width: `${item.percentage}%` }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<h4 className="font-semibold text-[#1C323E] mb-4">Spend by Region</h4>
|
||
<div className="space-y-3">
|
||
{[
|
||
{ region: "Bay Area", amount: "$920K", percentage: 40 },
|
||
{ region: "Northern California", amount: "$690K", percentage: 30 },
|
||
{ region: "National", amount: "$460K", percentage: 20 },
|
||
{ region: "Multi-Region", amount: "$230K", percentage: 10 },
|
||
].map((item, idx) => (
|
||
<div key={idx}>
|
||
<div className="flex justify-between mb-1">
|
||
<span className="text-sm font-medium">{item.region}</span>
|
||
<span className="text-sm font-bold text-[#0A39DF]">{item.amount}</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div
|
||
className="bg-gradient-to-r from-emerald-500 to-emerald-600 h-2 rounded-full"
|
||
style={{ width: `${item.percentage}%` }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pain Point Solved</h4>
|
||
<p className="text-sm text-slate-700">✓ Helps procurement see trends and negotiate better rates</p>
|
||
<p className="text-sm text-slate-700 mt-1">✓ Real-time visibility into spending across all categories</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Audit Trail & Reporting Tab */}
|
||
<TabsContent value="audit">
|
||
<div className="grid grid-cols-1 gap-6">
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Shield className="w-5 h-5 text-[#0A39DF]" />
|
||
Audit Trail & Reporting
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">Central log for all compliance docs and rate changes</p>
|
||
</div>
|
||
<Button variant="outline">
|
||
<Download className="w-4 h-4 mr-2" />
|
||
Export Audit Report
|
||
</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Total Events</h4>
|
||
<p className="text-3xl font-bold text-blue-700">1,234</p>
|
||
<p className="text-xs text-slate-600 mt-1">Last 30 days</p>
|
||
</div>
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Document Changes</h4>
|
||
<p className="text-3xl font-bold text-green-700">45</p>
|
||
<p className="text-xs text-slate-600 mt-1">Updates logged</p>
|
||
</div>
|
||
<div className="p-4 bg-purple-50 rounded-lg border border-purple-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Rate Changes</h4>
|
||
<p className="text-3xl font-bold text-purple-700">8</p>
|
||
<p className="text-xs text-slate-600 mt-1">This month</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-3">
|
||
<h4 className="font-semibold text-[#1C323E]">Recent Activity</h4>
|
||
{[
|
||
{ action: "Rate Card Updated", vendor: "Legendary Event Staffing", user: "John Smith", date: "01/16/2025 10:30 AM", type: "rate" },
|
||
{ action: "W-9 Uploaded", vendor: "Instawork", user: "Sarah Johnson", date: "01/16/2025 09:15 AM", type: "document" },
|
||
{ action: "Contract Renewed", vendor: "NorCal Staffing", user: "Mike Davis", date: "01/15/2025 03:45 PM", type: "contract" },
|
||
{ action: "COI Updated", vendor: "HSS", user: "Emily Brown", date: "01/15/2025 02:20 PM", type: "document" },
|
||
{ action: "Rate Change Approved", vendor: "Bluecrew", user: "John Smith", date: "01/15/2025 11:30 AM", type: "rate" },
|
||
].map((activity, idx) => (
|
||
<div key={idx} className="flex items-center justify-between p-4 bg-slate-50 rounded-lg border border-slate-200">
|
||
<div className="flex items-center gap-3">
|
||
<div className={`w-10 h-10 rounded-lg flex items-center justify-center ${
|
||
activity.type === "rate" ? "bg-purple-100" :
|
||
activity.type === "document" ? "bg-blue-100" : "bg-green-100"
|
||
}`}>
|
||
{activity.type === "rate" ? <DollarSign className="w-5 h-5 text-purple-600" /> :
|
||
activity.type === "document" ? <FileText className="w-5 h-5 text-blue-600" /> :
|
||
<CheckCircle2 className="w-5 h-5 text-green-600" />}
|
||
</div>
|
||
<div>
|
||
<p className="font-semibold text-[#1C323E]">{activity.action}</p>
|
||
<p className="text-sm text-slate-600">{activity.vendor} • by {activity.user}</p>
|
||
</div>
|
||
</div>
|
||
<div className="text-right">
|
||
<p className="text-xs text-slate-500">{activity.date}</p>
|
||
<Button variant="link" className="text-xs h-auto p-0 mt-1">
|
||
View Details
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Pain Point Solved</h4>
|
||
<p className="text-sm text-slate-700">✓ Supports Compass / Foodbuy audits with complete documentation</p>
|
||
<p className="text-sm text-slate-700 mt-1">✓ Full transparency and traceability of all changes</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Compliance & Documents Tab */}
|
||
<TabsContent value="compliance">
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
{/* Document Management */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<FileText className="w-5 h-5 text-[#0A39DF]" />
|
||
Document Center
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="p-6 space-y-3">
|
||
{[
|
||
{ name: "COI (Certificate of Insurance)", status: "Valid", color: "green", action: () => setShowCOIViewer(true) },
|
||
{ name: "W9 Forms", status: "Valid", color: "green", action: () => setShowW9Form(true) },
|
||
{ name: "Contracts", status: "Active", color: "blue", action: null },
|
||
{ name: "ESG Certification", status: "Valid", color: "green", action: null },
|
||
{ name: "Policies", status: "Updated", color: "blue", action: null },
|
||
{ name: "Forms & Templates", status: "Available", color: "gray", action: null },
|
||
].map((doc, idx) => (
|
||
<div
|
||
key={idx}
|
||
className="flex items-center justify-between p-4 border border-slate-200 rounded-lg hover:border-[#0A39DF] hover:shadow-md transition-all cursor-pointer"
|
||
onClick={doc.action}
|
||
>
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 bg-[#0A39DF]/10 rounded-lg flex items-center justify-center">
|
||
<FileText className="w-5 h-5 text-[#0A39DF]" />
|
||
</div>
|
||
<div>
|
||
<p className="font-semibold text-[#1C323E]">{doc.name}</p>
|
||
<p className="text-xs text-slate-500">Last updated: 2 days ago</p>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-3">
|
||
<Badge className={`bg-${doc.color}-100 text-${doc.color}-700`}>
|
||
{doc.status}
|
||
</Badge>
|
||
<Button variant="ghost" size="icon">
|
||
<Download className="w-4 h-4" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Audit & Reporting Center */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<div className="flex justify-between items-center">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Shield className="w-5 h-5 text-[#0A39DF]" />
|
||
Audit & Reporting Center
|
||
</CardTitle>
|
||
<p className="text-xs text-slate-500">Audit readiness across controls</p>
|
||
</div>
|
||
<Badge className="bg-blue-100 text-blue-700">Auto-sync</Badge>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-2">Compliance Status</h4>
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between">
|
||
<span className="text-sm">Overall Compliance</span>
|
||
<span className="font-bold text-green-600">98%</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-sm">Documents Valid</span>
|
||
<span className="font-bold text-green-600">156/158</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-sm">Expiring Soon</span>
|
||
<span className="font-bold text-amber-600">2</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-4 bg-slate-50 rounded-lg border border-slate-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-3">Recent Audits</h4>
|
||
<div className="space-y-2">
|
||
<div className="flex items-center justify-between text-sm">
|
||
<span>Q4 2024 Compliance Audit</span>
|
||
<Badge className="bg-green-100 text-green-700">Passed</Badge>
|
||
</div>
|
||
<div className="flex items-center justify-between text-sm">
|
||
<span>Vendor Verification</span>
|
||
<Badge className="bg-blue-100 text-blue-700">In Progress</Badge>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<Button className="w-full bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
<Download className="w-4 h-4 mr-2" />
|
||
Generate Audit Report
|
||
</Button>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Vendor Scorecards Tab */}
|
||
<TabsContent value="vendors">
|
||
{/* Vendor List */}
|
||
<Card className="border-slate-200 shadow-lg mb-6">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Building2 className="w-5 h-5 text-[#0A39DF]" />
|
||
Vendor Directory
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-1">
|
||
Showing {startIndex + 1}-{Math.min(endIndex, filteredVendors.length)} of {filteredVendors.length} vendors
|
||
{filteredVendors.length !== vendors.length && ` (filtered from ${vendors.length} total)`}
|
||
</p>
|
||
</div>
|
||
<Button className="bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
<Plus className="w-4 h-4 mr-2" />
|
||
Add Vendor
|
||
</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
{/* Search and Filters */}
|
||
<div className="mb-6 space-y-4">
|
||
{/* Search Bar */}
|
||
<div className="relative">
|
||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400" />
|
||
<Input
|
||
placeholder="Search by vendor name or specialty..."
|
||
value={vendorSearch}
|
||
onChange={(e) => setVendorSearch(e.target.value)}
|
||
className="pl-10 h-11 border-slate-300"
|
||
/>
|
||
</div>
|
||
|
||
{/* Filters Row */}
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
|
||
<div>
|
||
<Label htmlFor="region-filter" className="text-xs font-medium text-slate-700 mb-1.5 block">Region</Label>
|
||
<Select value={vendorRegionFilter} onValueChange={setVendorRegionFilter}>
|
||
<SelectTrigger id="region-filter" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Regions</SelectItem>
|
||
{uniqueRegions.map(region => (
|
||
<SelectItem key={region} value={region}>{region}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="state-filter" className="text-xs font-medium text-slate-700 mb-1.5 block">State</Label>
|
||
<Select value={vendorStateFilter} onValueChange={setVendorStateFilter}>
|
||
<SelectTrigger id="state-filter" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All States</SelectItem>
|
||
{uniqueStates.map(state => (
|
||
<SelectItem key={state} value={state}>{state}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="specialty-filter" className="text-xs font-medium text-slate-700 mb-1.5 block">Specialty</Label>
|
||
<Select value={vendorSpecialtyFilter} onValueChange={setVendorSpecialtyFilter}>
|
||
<SelectTrigger id="specialty-filter" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Specialties</SelectItem>
|
||
{uniqueSpecialties.map(specialty => (
|
||
<SelectItem key={specialty} value={specialty}>{specialty}</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="software-filter" className="text-xs font-medium text-slate-700 mb-1.5 block">Software Type</Label>
|
||
<Select value={vendorSoftwareFilter} onValueChange={setVendorSoftwareFilter}>
|
||
<SelectTrigger id="software-filter" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Types</SelectItem>
|
||
<SelectItem value="platform">Full Platform</SelectItem>
|
||
<SelectItem value="building">Building Platform</SelectItem>
|
||
<SelectItem value="partial">Partial Tech</SelectItem>
|
||
<SelectItem value="traditional">Traditional</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<Label htmlFor="items-per-page" className="text-xs font-medium text-slate-700 mb-1.5 block">Per Page</Label>
|
||
<Select value={itemsPerPage.toString()} onValueChange={(value) => setItemsPerPage(Number(value))}>
|
||
<SelectTrigger id="items-per-page" className="border-slate-300">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="10">10</SelectItem>
|
||
<SelectItem value="25">25</SelectItem>
|
||
<SelectItem value="50">50</SelectItem>
|
||
<SelectItem value="100">100</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Active Filters Display */}
|
||
{(vendorSearch || vendorRegionFilter !== "all" || vendorSpecialtyFilter !== "all" || vendorStateFilter !== "all" || vendorSoftwareFilter !== "all") && (
|
||
<div className="flex items-center gap-2 flex-wrap">
|
||
<span className="text-sm text-slate-600">Active filters:</span>
|
||
{vendorSearch && (
|
||
<Badge variant="outline" className="gap-2">
|
||
Search: {vendorSearch}
|
||
<button onClick={() => setVendorSearch("")} className="hover:text-red-600">×</button>
|
||
</Badge>
|
||
)}
|
||
{vendorRegionFilter !== "all" && (
|
||
<Badge variant="outline" className="gap-2">
|
||
Region: {vendorRegionFilter}
|
||
<button onClick={() => setVendorRegionFilter("all")} className="hover:text-red-600">×</button>
|
||
</Badge>
|
||
)}
|
||
{vendorStateFilter !== "all" && (
|
||
<Badge variant="outline" className="gap-2">
|
||
State: {vendorStateFilter}
|
||
<button onClick={() => setVendorStateFilter("all")} className="hover:text-red-600">×</button>
|
||
</Badge>
|
||
)}
|
||
{vendorSpecialtyFilter !== "all" && (
|
||
<Badge variant="outline" className="gap-2">
|
||
Specialty: {vendorSpecialtyFilter}
|
||
<button onClick={() => setVendorSpecialtyFilter("all")} className="hover:text-red-600">×</button>
|
||
</Badge>
|
||
)}
|
||
{vendorSoftwareFilter !== "all" && (
|
||
<Badge variant="outline" className="gap-2">
|
||
Software: {vendorSoftwareFilter === "platform" ? "Full Platform" : vendorSoftwareFilter === "building" ? "Building Platform" : vendorSoftwareFilter === "partial" ? "Partial Tech" : "Traditional"}
|
||
<button onClick={() => setVendorSoftwareFilter("all")} className="hover:text-red-600">×</button>
|
||
</Badge>
|
||
)}
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={() => {
|
||
setVendorSearch("");
|
||
setVendorRegionFilter("all");
|
||
setVendorSpecialtyFilter("all");
|
||
setVendorStateFilter("all");
|
||
setVendorSoftwareFilter("all");
|
||
}}
|
||
className="text-red-600 hover:text-red-700 hover:bg-red-50"
|
||
>
|
||
Clear all
|
||
</Button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Table */}
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b-2 border-slate-300">
|
||
<th className="text-left py-3 px-2 font-semibold">Vendor Name</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Region</th>
|
||
<th className="text-left py-3 px-2 font-semibold">State</th>
|
||
<th className="text-left py-3 px-2 font-semibold">Specialty</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Total Staff</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Software/Platform</th>
|
||
<th className="text-center py-3 px-2 font-semibold">Actions</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{paginatedVendors.length > 0 ? (
|
||
paginatedVendors.map((vendor, idx) => (
|
||
<VendorHoverCard key={idx} vendor={vendor}>
|
||
<tr className="border-b border-slate-100 hover:bg-slate-50 cursor-pointer transition-colors">
|
||
<td className="py-4 px-2">
|
||
<button
|
||
onClick={() => handleVendorClick(vendor)}
|
||
className="flex items-center gap-3 hover:opacity-80 transition-opacity text-left w-full"
|
||
>
|
||
<div className="w-10 h-10 bg-gradient-to-br from-[#0A39DF] to-[#1C323E] rounded-lg flex items-center justify-center">
|
||
<Building2 className="w-5 h-5 text-white" />
|
||
</div>
|
||
<span className="font-semibold text-[#1C323E] hover:text-[#0A39DF] underline">{vendor.name}</span>
|
||
</button>
|
||
</td>
|
||
<td className="py-4 px-2 text-slate-700">{vendor.region}</td>
|
||
<td className="py-4 px-2 text-slate-700">{vendor.state}</td>
|
||
<td className="py-4 px-2 text-slate-700">{vendor.specialty}</td>
|
||
<td className="py-4 px-2">
|
||
<div className="flex items-center justify-center">
|
||
<Badge variant="outline" className="font-semibold text-[#0A39DF] border-[#0A39DF]">
|
||
<Users className="w-3 h-3 mr-1" />
|
||
{vendor.employees.toLocaleString()}
|
||
</Badge>
|
||
</div>
|
||
</td>
|
||
<td className="py-4 px-2">
|
||
<div className="flex items-center justify-center gap-2">
|
||
{vendor.softwareType === "platform" && (
|
||
<Badge className="bg-green-100 text-green-700 font-medium">
|
||
✅ {vendor.software}
|
||
</Badge>
|
||
)}
|
||
{vendor.softwareType === "building" && (
|
||
<Badge className="bg-blue-100 text-blue-700 font-medium">
|
||
⚙️ {vendor.software}
|
||
</Badge>
|
||
)}
|
||
{vendor.softwareType === "partial" && (
|
||
<Badge className="bg-amber-100 text-amber-700 font-medium">
|
||
⚙️ {vendor.software}
|
||
</Badge>
|
||
)}
|
||
{vendor.softwareType === "traditional" && (
|
||
<Badge className="bg-gray-100 text-gray-700 font-medium">
|
||
❌ {vendor.software}
|
||
</Badge>
|
||
)}
|
||
</div>
|
||
</td>
|
||
<td className="py-4 px-2" onClick={(e) => e.stopPropagation()}>
|
||
<div className="flex items-center justify-center gap-2">
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
handleVendorClick(vendor);
|
||
}}
|
||
className="hover:text-[#0A39DF] hover:bg-[#0A39DF]/10"
|
||
>
|
||
<Users className="w-4 h-4 mr-1" />
|
||
View Details
|
||
</Button>
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
handleEditVendor(vendor);
|
||
}}
|
||
className="hover:text-[#0A39DF] hover:bg-[#0A39DF]/10"
|
||
>
|
||
<Edit className="w-4 h-4 mr-1" />
|
||
Edit
|
||
</Button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</VendorHoverCard>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td colSpan="7" className="py-12 text-center">
|
||
<Building2 className="w-12 h-12 mx-auto text-slate-300 mb-3" />
|
||
<p className="text-slate-600 font-medium">No vendors found</p>
|
||
<p className="text-sm text-slate-500 mt-1">Try adjusting your search or filters</p>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
{/* Pagination */}
|
||
{totalPages > 1 && (
|
||
<div className="flex items-center justify-between mt-6 pt-6 border-t border-slate-200">
|
||
<div className="text-sm text-slate-600">
|
||
Page {currentPage} of {totalPages}
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
|
||
disabled={currentPage === 1}
|
||
className="border-slate-300"
|
||
>
|
||
<ChevronLeft className="w-4 h-4 mr-1" />
|
||
Previous
|
||
</Button>
|
||
|
||
{/* Page Numbers */}
|
||
<div className="flex gap-1">
|
||
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
|
||
let pageNum;
|
||
if (totalPages <= 5) {
|
||
pageNum = i + 1;
|
||
} else if (currentPage <= 3) {
|
||
pageNum = i + 1;
|
||
} else if (currentPage >= totalPages - 2) {
|
||
pageNum = totalPages - 4 + i;
|
||
} else {
|
||
pageNum = currentPage - 2 + i;
|
||
}
|
||
|
||
return (
|
||
<Button
|
||
key={pageNum}
|
||
variant={currentPage === pageNum ? "default" : "outline"}
|
||
size="sm"
|
||
onClick={() => setCurrentPage(pageNum)}
|
||
className={currentPage === pageNum ? "bg-[#0A39DF] hover:bg-[#0A39DF]/90 text-white" : "border-slate-300"}
|
||
>
|
||
{pageNum}
|
||
</Button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => setCurrentPage(prev => Math.min(totalPages, prev + 1))}
|
||
disabled={currentPage === totalPages}
|
||
className="border-slate-300"
|
||
>
|
||
Next
|
||
<ChevronRight className="w-4 h-4 ml-1" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Vendor Scorecards Table */}
|
||
<Card className="border-slate-200 shadow-lg mb-6">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Award className="w-5 h-5 text-[#0A39DF]" />
|
||
Vendor Scorecards - Comprehensive Rating
|
||
</CardTitle>
|
||
<p className="text-sm text-slate-500 mt-2">Rating agencies and suppliers on multiple performance metrics</p>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b-2 border-slate-300">
|
||
<th className="text-left py-3 font-semibold">Vendor</th>
|
||
<th className="text-center py-3 font-semibold">Reliability</th>
|
||
<th className="text-center py-3 font-semibold">Compliance</th>
|
||
<th className="text-center py-3 font-semibold">Performance</th>
|
||
<th className="text-center py-3 font-semibold">Pricing</th>
|
||
<th className="text-center py-3 font-semibold">Service Level</th>
|
||
<th className="text-center py-3 font-semibold">Client Satisfaction</th>
|
||
<th className="text-center py-3 font-semibold">Billing Accuracy</th>
|
||
<th className="text-right py-3 font-semibold">Wages</th>
|
||
<th className="text-right py-3 font-semibold">Vendor Fee %</th>
|
||
<th className="text-right py-3 font-semibold">Allowance Fee</th>
|
||
<th className="text-center py-3 font-semibold">Overall Score</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr className="border-b border-slate-100 hover:bg-slate-50">
|
||
<td className="py-4 font-medium">Legendary</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">98%</Badge>
|
||
</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">100%</Badge>
|
||
</td>
|
||
<td className="text-center font-semibold">4.7/5</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-blue-100 text-blue-700">$23/hr</Badge>
|
||
</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">97%</Badge>
|
||
</td>
|
||
<td className="text-center font-semibold">4.8/5</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">99.5%</Badge>
|
||
</td>
|
||
<td className="text-right font-semibold">$18.50</td>
|
||
<td className="text-right font-semibold text-[#0A39DF]">19.6%</td>
|
||
<td className="text-right font-semibold">$2.00</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-gradient-to-r from-green-600 to-green-700 text-white font-bold">A+</Badge>
|
||
</td>
|
||
</tr>
|
||
<tr className="border-b border-slate-100 hover:bg-slate-50">
|
||
<td className="py-4 font-medium">Competitor B</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">95%</Badge>
|
||
</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">98%</Badge>
|
||
</td>
|
||
<td className="text-center font-semibold">4.2/5</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-blue-100 text-blue-700">$21/hr</Badge>
|
||
</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">94%</Badge>
|
||
</td>
|
||
<td className="text-center font-semibold">4.5/5</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">98%</Badge>
|
||
</td>
|
||
<td className="text-right font-semibold">$17.00</td>
|
||
<td className="text-right font-semibold text-[#0A39DF]">19.0%</td>
|
||
<td className="text-right font-semibold">$1.50</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-gradient-to-r from-blue-600 to-blue-700 text-white font-bold">A</Badge>
|
||
</td>
|
||
</tr>
|
||
<tr className="border-b border-slate-100 hover:bg-slate-50">
|
||
<td className="py-4 font-medium">Competitor A</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-amber-100 text-amber-700">91%</Badge>
|
||
</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-green-100 text-green-700">96%</Badge>
|
||
</td>
|
||
<td className="text-center font-semibold">3.9/5</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-amber-100 text-amber-700">$26/hr</Badge>
|
||
</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-amber-100 text-amber-700">90%</Badge>
|
||
</td>
|
||
<td className="text-center font-semibold">4.0/5</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-amber-100 text-amber-700">95%</Badge>
|
||
</td>
|
||
<td className="text-right font-semibold">$19.50</td>
|
||
<td className="text-right font-semibold text-[#0A39DF]">25.0%</td>
|
||
<td className="text-right font-semibold">$2.50</td>
|
||
<td className="text-center">
|
||
<Badge className="bg-gradient-to-r from-amber-600 to-amber-700 text-white font-bold">B+</Badge>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
|
||
{/* Trends & SLA Tab */}
|
||
<TabsContent value="trends">
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
{/* Staffing Rate Evolution */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<TrendingUp className="w-5 h-5 text-[#0A39DF]" />
|
||
Evolution of Staffing Rates
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="space-y-4">
|
||
<div>
|
||
<div className="flex justify-between mb-2">
|
||
<span className="text-sm font-medium">Q1 2024</span>
|
||
<span className="text-sm font-bold">$21.50/hr</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div className="bg-gradient-to-r from-blue-500 to-blue-600 h-2 rounded-full" style={{ width: '75%' }} />
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div className="flex justify-between mb-2">
|
||
<span className="text-sm font-medium">Q2 2024</span>
|
||
<span className="text-sm font-bold">$22.00/hr</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div className="bg-gradient-to-r from-blue-500 to-blue-600 h-2 rounded-full" style={{ width: '80%' }} />
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div className="flex justify-between mb-2">
|
||
<span className="text-sm font-medium">Q3 2024</span>
|
||
<span className="text-sm font-bold">$22.75/hr</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div className="bg-gradient-to-r from-blue-500 to-blue-600 h-2 rounded-full" style={{ width: '85%' }} />
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div className="flex justify-between mb-2">
|
||
<span className="text-sm font-medium">Q4 2024</span>
|
||
<span className="text-sm font-bold text-[#0A39DF]">$23.50/hr</span>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div className="bg-gradient-to-r from-[#0A39DF] to-[#1C323E] h-2 rounded-full" style={{ width: '95%' }} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<p className="text-sm text-slate-700">
|
||
<span className="font-bold text-[#0A39DF]">+9.3%</span> increase year-over-year
|
||
</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* SLA Compliance */}
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Shield className="w-5 h-5 text-[#0A39DF]" />
|
||
SLA Compliance Metrics
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-2 gap-4">
|
||
{[
|
||
{ name: "I9", compliance: 100, color: "green" },
|
||
{ name: "BGC", compliance: 98, color: "green" },
|
||
{ name: "SOW", compliance: 95, color: "green" },
|
||
{ name: "RBS", compliance: 92, color: "amber" },
|
||
{ name: "DS", compliance: 97, color: "green" },
|
||
].map((item, idx) => (
|
||
<div key={idx} className="p-4 bg-slate-50 rounded-lg border border-slate-200">
|
||
<div className="flex justify-between items-center mb-2">
|
||
<span className="font-semibold text-[#1C323E]">{item.name}</span>
|
||
<Badge className={`bg-${item.color}-100 text-${item.color}-700`}>
|
||
{item.compliance}%
|
||
</Badge>
|
||
</div>
|
||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||
<div
|
||
className={`bg-gradient-to-r from-${item.color}-500 to-${item.color}-600 h-2 rounded-full`}
|
||
style={{ width: `${item.compliance}%` }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Reports & Analytics Tab */}
|
||
<TabsContent value="reports">
|
||
<Card className="border-slate-200 shadow-lg mb-6">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<BarChart3 className="w-5 h-5 text-[#0A39DF]" />
|
||
Customized Reporting
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Year</label>
|
||
<Select value={selectedYear} onValueChange={setSelectedYear}>
|
||
<SelectTrigger>
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="2025">2025</SelectItem>
|
||
<SelectItem value="2024">2024</SelectItem>
|
||
<SelectItem value="2023">2023</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Compare With</label>
|
||
<Select value={comparisonYear} onValueChange={setComparisonYear}>
|
||
<SelectTrigger>
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="2024">2024</SelectItem>
|
||
<SelectItem value="2023">2023</SelectItem>
|
||
<SelectItem value="2022">2022</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Region/State</label>
|
||
<Select value={selectedRegion} onValueChange={setSelectedRegion}>
|
||
<SelectTrigger>
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Regions</SelectItem>
|
||
<SelectItem value="west">West</SelectItem>
|
||
<SelectItem value="east">East</SelectItem>
|
||
<SelectItem value="ca">California</SelectItem>
|
||
<SelectItem value="ny">New York</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Vendor</label>
|
||
<Select value={selectedVendor} onValueChange={setSelectedVendor}>
|
||
<SelectTrigger>
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Vendors</SelectItem>
|
||
<SelectItem value="legendary">Legendary</SelectItem>
|
||
<SelectItem value="compA">Competitor A</SelectItem>
|
||
<SelectItem value="compB">Competitor B</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Location</label>
|
||
<Select>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="All Locations" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Locations</SelectItem>
|
||
<SelectItem value="sf">San Francisco</SelectItem>
|
||
<SelectItem value="la">Los Angeles</SelectItem>
|
||
<SelectItem value="sd">San Diego</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Sector</label>
|
||
<Select>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="All Sectors" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Sectors</SelectItem>
|
||
<SelectItem value="tech">Technology</SelectItem>
|
||
<SelectItem value="hospitality">Hospitality</SelectItem>
|
||
<SelectItem value="retail">Retail</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="text-sm font-medium mb-2 block">Client</label>
|
||
<Select value={selectedClient} onValueChange={setSelectedClient}>
|
||
<SelectTrigger>
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">All Clients</SelectItem>
|
||
<SelectItem value="google">Google</SelectItem>
|
||
<SelectItem value="nvidia">Nvidia</SelectItem>
|
||
<SelectItem value="samsung">Samsung</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="flex items-end">
|
||
<Button className="w-full bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
Generate Report
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
|
||
{/* Forecasting Tab */}
|
||
<TabsContent value="forecasting">
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<TrendingUp className="w-5 h-5 text-[#0A39DF]" />
|
||
Labor Demand & Cost Prediction
|
||
</CardTitle>
|
||
<p className="text-xs text-slate-500 mt-1">By season and client</p>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="space-y-4">
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-3">Q1 2025 Forecast</h4>
|
||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||
<div>
|
||
<p className="text-slate-600">Predicted Demand</p>
|
||
<p className="font-bold text-[#0A39DF]">2,400 shifts</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-600">Estimated Cost</p>
|
||
<p className="font-bold text-[#0A39DF]">$620K</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-600">Peak Period</p>
|
||
<p className="font-bold">Jan 15-31</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-600">Confidence</p>
|
||
<Badge className="bg-green-100 text-green-700">87%</Badge>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-4 bg-slate-50 rounded-lg border border-slate-200">
|
||
<h4 className="font-semibold text-[#1C323E] mb-3">By Client</h4>
|
||
<div className="space-y-3">
|
||
<div className="flex justify-between items-center">
|
||
<span className="text-sm">Google</span>
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-sm font-semibold">950 shifts</span>
|
||
<span className="text-xs text-green-600">↑ 15%</span>
|
||
</div>
|
||
</div>
|
||
<div className="flex justify-between items-center">
|
||
<span className="text-sm">Nvidia</span>
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-sm font-semibold">720 shifts</span>
|
||
<span className="text-xs text-green-600">↑ 8%</span>
|
||
</div>
|
||
</div>
|
||
<div className="flex justify-between items-center">
|
||
<span className="text-sm">Samsung</span>
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-sm font-semibold">580 shifts</span>
|
||
<span className="text-xs text-blue-600">→ 2%</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card className="border-slate-200 shadow-lg">
|
||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<PieChart className="w-5 h-5 text-[#0A39DF]" />
|
||
Scenario Simulations
|
||
</CardTitle>
|
||
<p className="text-xs text-slate-500 mt-1">Vendor consolidation & renegotiation analysis</p>
|
||
</CardHeader>
|
||
<CardContent className="p-6">
|
||
<div className="space-y-4">
|
||
<div className="p-4 bg-green-50 rounded-lg border border-green-200">
|
||
<div className="flex items-start justify-between mb-3">
|
||
<h4 className="font-semibold text-[#1C323E]">Scenario 1: Consolidate to Top 2 Vendors</h4>
|
||
<Badge className="bg-green-600 text-white">Best ROI</Badge>
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-4 text-sm mb-3">
|
||
<div>
|
||
<p className="text-slate-600">Projected Savings</p>
|
||
<p className="font-bold text-green-700">$180K/year</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-600">Risk Level</p>
|
||
<Badge className="bg-amber-100 text-amber-700">Medium</Badge>
|
||
</div>
|
||
</div>
|
||
<p className="text-xs text-slate-600">Reduce vendor management overhead by 40%</p>
|
||
</div>
|
||
|
||
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||
<div className="flex items-start justify-between mb-3">
|
||
<h4 className="font-semibold text-[#1C323E]">Scenario 2: Renegotiate All Contracts</h4>
|
||
<Badge className="bg-blue-600 text-white">High Impact</Badge>
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-4 text-sm mb-3">
|
||
<div>
|
||
<p className="text-slate-600">Projected Savings</p>
|
||
<p className="font-bold text-blue-700">$240K/year</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-600">Risk Level</p>
|
||
<Badge className="bg-green-100 text-green-700">Low</Badge>
|
||
</div>
|
||
</div>
|
||
<p className="text-xs text-slate-600">Leverage current market rates and volume discounts</p>
|
||
</div>
|
||
|
||
<div className="p-4 bg-purple-50 rounded-lg border border-purple-200">
|
||
<div className="flex items-start justify-between mb-3">
|
||
<h4 className="font-semibold text-[#1C323E]">Scenario 3: Build Internal Pool</h4>
|
||
<Badge className="bg-purple-600 text-white">Long-term</Badge>
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-4 text-sm mb-3">
|
||
<div>
|
||
<p className="text-slate-600">Projected Savings</p>
|
||
<p className="font-bold text-purple-700">$420K/year</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-slate-600">Risk Level</p>
|
||
<Badge className="bg-red-100 text-red-700">High</Badge>
|
||
</div>
|
||
</div>
|
||
<p className="text-xs text-slate-600">12-18 month implementation timeline required</p>
|
||
</div>
|
||
</div>
|
||
|
||
<Button className="w-full mt-4 bg-[#0A39DF] hover:bg-[#0A39DF]/90">
|
||
<Download className="w-4 h-4 mr-2" />
|
||
Download Full Scenario Analysis
|
||
</Button>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
</Tabs>
|
||
|
||
{/* Vendor Detail Modal */}
|
||
<VendorDetailModal
|
||
vendor={selectedVendorForDetail}
|
||
open={showVendorDetail}
|
||
onClose={() => setShowVendorDetail(false)}
|
||
onEdit={handleEditVendor}
|
||
/>
|
||
|
||
{/* COI Viewer Dialog */}
|
||
<Dialog open={showCOIViewer} onOpenChange={setShowCOIViewer}>
|
||
<DialogContent className="max-w-6xl max-h-[90vh] overflow-y-auto">
|
||
<DialogHeader>
|
||
<DialogTitle>Certificate of Insurance (COI)</DialogTitle>
|
||
</DialogHeader>
|
||
<COIViewer onClose={() => setShowCOIViewer(false)} />
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{/* W9 Form Dialog */}
|
||
<Dialog open={showW9Form} onOpenChange={setShowW9Form}>
|
||
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||
<DialogHeader>
|
||
<DialogTitle>W-9 Form - Request for Taxpayer Identification Number</DialogTitle>
|
||
</DialogHeader>
|
||
<W9FormViewer onClose={() => setShowW9Form(false)} />
|
||
</DialogContent>
|
||
</Dialog>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|