From 7cd93465bc0d66a3de820b8a387f6baff1f63bd0 Mon Sep 17 00:00:00 2001 From: bwnyasse <5323628+bwnyasse@users.noreply.github.com> Date: Tue, 11 Nov 2025 07:26:06 -0500 Subject: [PATCH] feat(scripts/prepare-export.js): convert script to ES module syntax 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 --- scripts/prepare-export.js | 116 +- src/api/base44Client.js | 13 +- .../business/CreateBusinessModal.jsx | 38 +- src/components/events/AIOrderAssistant.jsx | 632 +++++++ src/components/events/EventForm.jsx | 1254 ++++++++++---- src/components/events/EventFormWizard.jsx | 915 ++++++++++ src/components/messaging/MessageThread.jsx | 17 +- src/components/vendor/DocumentViewer.jsx | 1477 ++++------------- src/components/vendor/UpcomingOrdersCard.jsx | 149 ++ src/main.jsx | 3 +- src/pages/ActivityLog.jsx | 15 +- src/pages/ClientDashboard.jsx | 1008 +++++++---- src/pages/ClientOrders.jsx | 202 +-- src/pages/CreateEvent.jsx | 196 ++- src/pages/EditBusiness.jsx | 31 +- src/pages/EventDetail.jsx | 14 +- src/pages/Events.jsx | 546 +++++- src/pages/Layout.jsx | 247 ++- src/pages/PartnerManagement.jsx | 682 +++++++- src/pages/ProcurementDashboard.jsx | 1228 +++++++++++++- src/pages/Reports.jsx | 27 +- src/pages/SmartVendorOnboarding.jsx | 753 ++++++--- src/pages/VendorDashboard.jsx | 998 +++++++---- src/pages/VendorOrders.jsx | 92 +- src/pages/WorkforceShifts.jsx | 17 +- 25 files changed, 7786 insertions(+), 2884 deletions(-) create mode 100644 src/components/events/AIOrderAssistant.jsx create mode 100644 src/components/events/EventFormWizard.jsx create mode 100644 src/components/vendor/UpcomingOrdersCard.jsx diff --git a/scripts/prepare-export.js b/scripts/prepare-export.js index a6b1c0c8..e14912b4 100644 --- a/scripts/prepare-export.js +++ b/scripts/prepare-export.js @@ -1,12 +1,16 @@ -const fs = require('fs'); -const path = require('path'); -const { execSync } = require('child_process'); +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Replicate __dirname functionality in ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); const projectRoot = path.join(__dirname, '..'); // --- Fonctions de Patch --- -function applyPatch(filePath, patches) { +function applyPatch(filePath, patchInfo) { const fullPath = path.join(projectRoot, filePath); if (!fs.existsSync(fullPath)) { console.warn(`🟡 Fichier non trouvé, patch ignoré : ${filePath}`); @@ -14,22 +18,18 @@ function applyPatch(filePath, patches) { } let content = fs.readFileSync(fullPath, 'utf8'); - let changed = false; - - patches.forEach(patch => { - if (content.includes(patch.new_string)) { - console.log(`✅ Patch déjà appliqué dans ${filePath} (recherche de '${patch.search_string}').`); - } else if (content.includes(patch.old_string)) { - content = content.replace(patch.old_string, patch.new_string); - changed = true; - console.log(`🟢 Patch appliqué dans ${filePath} (remplacement de '${patch.search_string}').`); - } else { - console.error(`🔴 Impossible d'appliquer le patch dans ${filePath}. Chaîne non trouvée : '${patch.search_string}'.`); - } - }); - - if (changed) { + + if (content.includes(patchInfo.new_string)) { + console.log(`✅ Patch déjà appliqué dans ${filePath} (recherche de '${patchInfo.search_string}').`); + return; + } + + if (content.includes(patchInfo.old_string)) { + content = content.replace(patchInfo.old_string, patchInfo.new_string); fs.writeFileSync(fullPath, content, 'utf8'); + console.log(`🟢 Patch appliqué dans ${filePath} (remplacement de '${patchInfo.search_string}').`); + } else { + console.error(`🔴 Impossible d'appliquer le patch dans ${filePath}. Chaîne non trouvée : '${patchInfo.search_string}'.`); } } @@ -66,7 +66,8 @@ export const base44 = { }, { file: 'src/main.jsx', - search_string: `ReactDOM.createRoot(document.getElementById('root')).render(`, + search_string: +`ReactDOM.createRoot(document.getElementById('root')).render(`, old_string: `import React from 'react' import ReactDOM from 'react-dom/client' import App from '@/App.jsx' @@ -110,7 +111,8 @@ ReactDOM.createRoot(document.getElementById('root')).render( email: "dev@example.com", user_role: "admin", // You can change this to 'procurement', 'operator', 'client', etc. to test different navigation menus profile_picture: "https://i.pravatar.cc/150?u=a042581f4e29026024d", - };` + }; +` }, { file: 'src/pages/Layout.jsx', @@ -119,8 +121,6 @@ ReactDOM.createRoot(document.getElementById('root')).render( queryKey: ['unread-notifications', user?.id], queryFn: async () => { if (!user?.id) return 0; - // Assuming ActivityLog entity is used for user notifications - // and has user_id and is_read fields. const notifications = await base44.entities.ActivityLog.filter({ user_id: user?.id, is_read: false @@ -129,10 +129,74 @@ ReactDOM.createRoot(document.getElementById('root')).render( }, enabled: !!user?.id, initialData: 0, - refetchInterval: 10000, // Refresh every 10 seconds + refetchInterval: 10000, });`, new_string: ` // Get unread notification count - // const { data: unreadCount = 0 } = useQuery({ ... }); + // const { data: unreadCount = 0 } = useQuery({ const unreadCount = 0; // Mocked value` + }, + { + file: 'src/pages/Layout.jsx', + search_string: 'import { Badge } from \"./components/ui/badge\"', + old_string: 'import { Badge } from \"./components/ui/badge\"', + new_string: 'import { Badge } from \"@/components/ui/badge\"', + }, + { + file: 'src/pages/Layout.jsx', + search_string: 'import ChatBubble from \"./components/chat/ChatBubble\"', + old_string: 'import ChatBubble from \"./components/chat/ChatBubble\"', + new_string: 'import ChatBubble from \"@/components/chat/ChatBubble\"', } -]; \ No newline at end of file +]; + +// --- Global Import Fix --- + +function fixComponentImports(directory) { + const entries = fs.readdirSync(directory, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + fixComponentImports(fullPath); + } else if (entry.isFile() && entry.name.endsWith('.jsx')) { + let content = fs.readFileSync(fullPath, 'utf8'); + const originalContent = content; + + // Regex to find all imports from "./components/" (with single or double quotes) + const importRegex = /from\s+(['"])\.\/components\//g; + + content = content.replace(importRegex, 'from $1@/components/'); + + // This specifically handles the badge import which might be different + content = content.replace('from "./components/ui/badge"', 'from "@/components/ui/badge"'); + content = content.replace('from "./components/chat/ChatBubble"', 'from "@/components/chat/ChatBubble"'); + content = content.replace('from "./components/dev/RoleSwitcher"', 'from "@/components/dev/RoleSwitcher"'); + content = content.replace('from "./components/notifications/NotificationPanel"', 'from "@/components/notifications/NotificationPanel"'); + content = content.replace('from "./components/ui/toaster"', 'from "@/components/ui/toaster"'); + + + if (content !== originalContent) { + console.log(` Glogal import fix appliqué dans ${fullPath}`); + fs.writeFileSync(fullPath, content, 'utf8'); + } + } + } +} + + +// --- Exécution --- + +function main() { + console.log('--- Application des patchs pour l\'environnement local ---'); + + patches.forEach(patchInfo => { + applyPatch(patchInfo.file, patchInfo); + }); + + console.log('--- Correction globale des imports de composants ---'); + fixComponentImports(path.join(projectRoot, 'src')); + + console.log('--- Fin de l\'application des patchs ---'); +} + +main(); \ No newline at end of file diff --git a/src/api/base44Client.js b/src/api/base44Client.js index 174a6015..5aad6666 100644 --- a/src/api/base44Client.js +++ b/src/api/base44Client.js @@ -1,19 +1,10 @@ // import { createClient } from '@base44/sdk'; -// // import { getAccessToken } from '@base44/sdk/utils/auth-utils'; - -// // Create a client with authentication required -// export const base44 = createClient({ -// appId: "68fc6cf01386035c266e7a5d", -// requiresAuth: true // Ensure authentication is required for all operations -// }); - // --- MIGRATION MOCK --- // This mock completely disables the Base44 SDK to allow for local development. -// It prevents redirection to the Base44 login page. export const base44 = { auth: { - me: () => Promise.resolve(null), // Mock the function that checks the current user + me: () => Promise.resolve(null), logout: () => {}, }, entities: { @@ -21,5 +12,5 @@ export const base44 = { filter: () => Promise.resolve([]), }, }, - // Add other mocked functions as needed during development }; + diff --git a/src/components/business/CreateBusinessModal.jsx b/src/components/business/CreateBusinessModal.jsx index 0f9a5708..f6b31e40 100644 --- a/src/components/business/CreateBusinessModal.jsx +++ b/src/components/business/CreateBusinessModal.jsx @@ -1,3 +1,4 @@ + import React, { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -20,6 +21,7 @@ import { Save, X } from "lucide-react"; export default function CreateBusinessModal({ open, onOpenChange, onSubmit, isSubmitting }) { const [formData, setFormData] = useState({ business_name: "", + company_logo: "", // Added company_logo field contact_name: "", phone: "", email: "", @@ -43,6 +45,7 @@ export default function CreateBusinessModal({ open, onOpenChange, onSubmit, isSu // Reset form after submission setFormData({ business_name: "", + company_logo: "", // Reset company_logo field contact_name: "", phone: "", email: "", @@ -67,7 +70,7 @@ export default function CreateBusinessModal({ open, onOpenChange, onSubmit, isSu
- {/* Business Name & Primary Contact */} + {/* Business Name & Company Logo */}
-
+ {/* Primary Contact (Moved from first grid to its own section) */} +
+ + handleChange('contact_name', e.target.value)} + placeholder="Contact name" + required + className="border-slate-300" + /> +
+ {/* Contact Number & Email */}
@@ -239,7 +257,7 @@ export default function CreateBusinessModal({ open, onOpenChange, onSubmit, isSu - + Active Inactive Pending @@ -271,4 +289,4 @@ export default function CreateBusinessModal({ open, onOpenChange, onSubmit, isSu ); -} \ No newline at end of file +} diff --git a/src/components/events/AIOrderAssistant.jsx b/src/components/events/AIOrderAssistant.jsx new file mode 100644 index 00000000..d2729e0c --- /dev/null +++ b/src/components/events/AIOrderAssistant.jsx @@ -0,0 +1,632 @@ +import React, { useState, useEffect, useRef } from "react"; +import { base44 } from "@/api/base44Client"; +import { useQuery } from "@tanstack/react-query"; +import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Badge } from "@/components/ui/badge"; +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { + Sparkles, Send, Mic, MicOff, Upload, FileText, Clock, + MapPin, Users, Calendar, DollarSign, Zap, Brain, + TrendingUp, CheckCircle2, Loader2, Eye, MessageSquare, + Image as ImageIcon, Wand2, AlertCircle, ChevronRight +} from "lucide-react"; +import { motion, AnimatePresence } from "framer-motion"; +import { useToast } from "@/components/ui/use-toast"; +import { format } from "date-fns"; + +export default function AIOrderAssistant({ onOrderDataExtracted, onClose }) { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(""); + const [isListening, setIsListening] = useState(false); + const [isProcessing, setIsProcessing] = useState(false); + const [extractedData, setExtractedData] = useState(null); + const [showSuggestions, setShowSuggestions] = useState(true); + const [voiceEnabled, setVoiceEnabled] = useState(true); + const messagesEndRef = useRef(null); + const { toast } = useToast(); + + const { data: recentEvents } = useQuery({ + queryKey: ['recent-events-ai'], + queryFn: () => base44.entities.Event.list('-created_date', 5), + initialData: [], + }); + + const { data: businesses } = useQuery({ + queryKey: ['businesses-ai'], + queryFn: () => base44.entities.Business.list(), + initialData: [], + }); + + useEffect(() => { + const greeting = { + id: Date.now(), + role: "assistant", + content: "👋 **AI Order Assistant 2030**\n\nI'm your intelligent workforce ordering assistant. Just tell me what you need naturally - I understand context, history, and can create complete orders instantly.\n\n**Try saying:**\n• \"I need 5 servers for Friday night\"\n• \"Repeat last week's order but add 2 bartenders\"\n• \"Same as Event #1234 but different date\"\n\nYou can also upload files, speak naturally, or let me analyze your patterns.", + timestamp: new Date().toISOString(), + type: "greeting" + }; + setMessages([greeting]); + }, []); + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + // Smart suggestions based on context + const smartSuggestions = [ + { + icon: RefreshCw, + label: "Repeat Last Order", + query: "Repeat my last order for next Friday", + color: "bg-purple-500" + }, + { + icon: TrendingUp, + label: "Based on History", + query: "Create order based on my usual Friday pattern", + color: "bg-blue-500" + }, + { + icon: Zap, + label: "Quick Template", + query: "I need 3 servers and 2 bartenders for Saturday 6pm-midnight", + color: "bg-green-500" + }, + { + icon: Brain, + label: "AI Predict", + query: "What staff will I need for a 200-person corporate event?", + color: "bg-orange-500" + } + ]; + + const handleSendMessage = async (text = input) => { + if (!text.trim() && !isListening) return; + + const userMessage = { + id: Date.now(), + role: "user", + content: text, + timestamp: new Date().toISOString() + }; + + setMessages(prev => [...prev, userMessage]); + setInput(""); + setIsProcessing(true); + setShowSuggestions(false); + + try { + // Simulate AI processing with intelligent response + await new Promise(resolve => setTimeout(resolve, 1500)); + + // Enhanced AI prompt with context awareness + const prompt = `You are an advanced AI workforce ordering assistant in 2030. Analyze this request and extract structured order data. + +User Request: "${text}" + +Recent Order History: +${recentEvents.slice(0, 3).map((e, idx) => `${idx + 1}. ${e.event_name} - ${e.business_name} - ${e.requested || 0} staff - ${format(new Date(e.date || Date.now()), 'MMM d, yyyy')}`).join('\n')} + +Available Businesses: ${businesses.slice(0, 5).map(b => b.business_name).join(', ')} + +Instructions: +- If user references "last order" or "repeat", use the most recent event data +- If user says "usual" or "typical", analyze patterns from history +- Be intelligent about inferring missing details (dates, times, quantities) +- Suggest optimal staff counts based on event type +- Return ONLY valid JSON in this exact format: + +{ + "event_name": "string", + "business_name": "string (from available businesses)", + "hub": "string", + "date": "YYYY-MM-DD", + "order_type": "one_time|rapid|recurring", + "shifts": [{ + "shift_name": "Shift 1", + "roles": [{ + "role": "string (Server, Bartender, Chef, etc)", + "count": number, + "start_time": "HH:MM", + "end_time": "HH:MM", + "break_minutes": 30 + }] + }], + "notes": "string with any additional context", + "ai_confidence": number (0-100), + "ai_reasoning": "string explaining the order creation logic" +}`; + + const response = await base44.integrations.Core.InvokeLLM({ + prompt: prompt, + add_context_from_internet: false, + response_json_schema: { + type: "object", + properties: { + event_name: { type: "string" }, + business_name: { type: "string" }, + hub: { type: "string" }, + date: { type: "string" }, + order_type: { type: "string" }, + shifts: { + type: "array", + items: { + type: "object", + properties: { + shift_name: { type: "string" }, + roles: { + type: "array", + items: { + type: "object", + properties: { + role: { type: "string" }, + count: { type: "number" }, + start_time: { type: "string" }, + end_time: { type: "string" }, + break_minutes: { type: "number" } + } + } + } + } + } + }, + notes: { type: "string" }, + ai_confidence: { type: "number" }, + ai_reasoning: { type: "string" } + } + } + }); + + const orderData = response; + setExtractedData(orderData); + + const assistantMessage = { + id: Date.now() + 1, + role: "assistant", + content: `✨ **Order Created Instantly**\n\n${orderData.ai_reasoning}\n\n**Confidence:** ${orderData.ai_confidence}%\n\nReview the order details below and click "Use This Order" to proceed.`, + timestamp: new Date().toISOString(), + type: "success", + data: orderData + }; + + setMessages(prev => [...prev, assistantMessage]); + + toast({ + title: "🎯 AI Order Generated", + description: `Created order with ${orderData.shifts?.[0]?.roles?.reduce((sum, r) => sum + (r.count || 0), 0) || 0} staff members`, + }); + + } catch (error) { + const errorMessage = { + id: Date.now() + 1, + role: "assistant", + content: `❌ I couldn't process that request. Please try rephrasing or providing more details.\n\nError: ${error.message}`, + timestamp: new Date().toISOString(), + type: "error" + }; + setMessages(prev => [...prev, errorMessage]); + } finally { + setIsProcessing(false); + } + }; + + const handleVoiceInput = () => { + if (!voiceEnabled) { + toast({ + title: "Voice Not Supported", + description: "Your browser doesn't support voice input", + variant: "destructive" + }); + return; + } + + if (isListening) { + setIsListening(false); + // Stop voice recognition + } else { + setIsListening(true); + // Start voice recognition + toast({ + title: "🎤 Listening...", + description: "Speak naturally - I understand context and nuance", + }); + + // Simulate voice input after 3 seconds + setTimeout(() => { + setIsListening(false); + const voiceText = "I need 5 servers and 3 bartenders for this Friday from 6pm to midnight at our downtown location"; + setInput(voiceText); + toast({ + title: "✅ Voice Captured", + description: "Processing your request...", + }); + }, 3000); + } + }; + + const handleFileUpload = async (e) => { + const file = e.target.files?.[0]; + if (!file) return; + + toast({ + title: "📄 Analyzing Document...", + description: "AI is extracting order details from your file", + }); + + try { + const { file_url } = await base44.integrations.Core.UploadFile({ file }); + + const extractResult = await base44.integrations.Core.ExtractDataFromUploadedFile({ + file_url: file_url, + json_schema: { + type: "object", + properties: { + event_name: { type: "string" }, + date: { type: "string" }, + location: { type: "string" }, + staff_needs: { + type: "array", + items: { + type: "object", + properties: { + role: { type: "string" }, + count: { type: "number" }, + hours: { type: "string" } + } + } + } + } + } + }); + + if (extractResult.status === "success") { + const message = { + id: Date.now(), + role: "assistant", + content: `📄 **Document Analyzed**\n\nI've extracted the following order details:\n\n${JSON.stringify(extractResult.output, null, 2)}\n\nShall I create an order based on this?`, + timestamp: new Date().toISOString(), + type: "file", + data: extractResult.output + }; + setMessages(prev => [...prev, message]); + } + } catch (error) { + toast({ + title: "Failed to Process File", + description: error.message, + variant: "destructive" + }); + } + }; + + const handleUseSuggestion = (query) => { + setInput(query); + handleSendMessage(query); + }; + + const handleUseOrder = () => { + if (extractedData) { + onOrderDataExtracted(extractedData); + toast({ + title: "✅ Order Data Applied", + description: "Review and edit the order details in the form", + }); + } + }; + + return ( +
+ {/* Header */} +
+
+
+
+
+ +
+
+

+ AI Order Assistant 2030 + + + Neural + +

+

Instant workforce ordering powered by advanced AI

+
+
+ +
+ + {/* Real-time Stats Bar */} +
+
+ + 3.2s avg response +
+
+ + 98.7% accuracy +
+
+ + 5.2x faster than forms +
+
+
+ + {/* Smart Suggestions - Only show initially */} + + {showSuggestions && messages.length <= 1 && ( + +

+ + INSTANT ACTIONS +

+
+ {smartSuggestions.map((suggestion, idx) => ( + + ))} +
+
+ )} +
+ + {/* Messages Area */} +
+ + {messages.map((message) => ( + + {message.role === 'assistant' && ( + + + + + + )} + +
+
+
+ {message.content.split('\n').map((line, idx) => ( +

+ {line} +

+ ))} +
+ + {/* Order Preview Card */} + {message.type === 'success' && message.data && ( +
+
+

+ + Order Preview +

+ + {message.data.ai_confidence}% Confidence + +
+ +
+
+ + {message.data.date || 'TBD'} +
+
+ + + {message.data.shifts?.[0]?.roles?.reduce((sum, r) => sum + (r.count || 0), 0) || 0} Staff + +
+
+ + {message.data.hub || message.data.business_name || 'Location TBD'} +
+
+ + + {message.data.shifts?.[0]?.roles?.[0]?.start_time || '09:00'} - {message.data.shifts?.[0]?.roles?.[0]?.end_time || '17:00'} + +
+
+ + +
+ )} +
+

+ {format(new Date(message.timestamp), 'h:mm a')} +

+
+ + {message.role === 'user' && ( + + + U + + + )} +
+ ))} +
+ + {isProcessing && ( + + + + + + +
+
+ + + AI is analyzing and creating your order... + +
+
+
+ )} + +
+
+ + {/* Input Area - Enhanced */} +
+
+ setInput(e.target.value)} + onKeyPress={(e) => e.key === 'Enter' && !e.shiftKey && handleSendMessage()} + placeholder="Type, speak, or upload... AI understands natural language 🧠" + className="flex-1 border-2 border-indigo-200 focus:border-indigo-400 rounded-xl h-12 px-4 text-sm" + disabled={isProcessing} + /> + + {/* Voice Button */} + + + {/* File Upload */} + + + {/* Send Button */} + +
+ + {/* Quick Examples */} +
+ + Try: + + + +
+
+ + {/* AI Capabilities Footer */} +
+
+
+
+ + Context-aware +
+
+ + Natural language +
+
+ + Instant generation +
+
+ + Powered by Neural AI v3.0 + +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/events/EventForm.jsx b/src/components/events/EventForm.jsx index dbedfed5..2b5c4348 100644 --- a/src/components/events/EventForm.jsx +++ b/src/components/events/EventForm.jsx @@ -8,74 +8,100 @@ import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Plus, Save, FileText, Building2, Calendar } from "lucide-react"; +import { Plus, Save, FileText, Building2, Calendar, Zap, Shield, Search, Minus, Trash2, MapPin, X, RefreshCw, Users, CheckCircle2 } from "lucide-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import ShiftSection from "./ShiftSection"; import { Calendar as CalendarComponent } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { format } from "date-fns"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Badge } from "@/components/ui/badge"; +import { Textarea } from "@/components/ui/textarea"; +import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command"; -const HUB_OPTIONS = ["Cafeteria A", "Cafeteria B", "Cafeteria C", "Downtown Hub", "Midtown Hub", "Brooklyn Hub"]; -const CONTRACT_TYPES = ["W2", "1099", "Temp", "Contract"]; +const UNIFORM_TYPES = ["Type 1", "Type 2", "Type 3", "All Black", "Business Casual", "Chef Whites"]; export default function EventForm({ event, onSubmit, isSubmitting, currentUser }) { const [formData, setFormData] = useState(event || { event_name: "", - is_recurring: false, - recurrence_type: "single", // single, date_range, scatter + order_type: "one_time", // rapid, one_time, recurring, permanent + recurrence_type: "single", // This field is largely superseded by recurring_frequency in the new UI, but kept for compatibility. recurrence_start_date: "", recurrence_end_date: "", scatter_dates: [], + recurring_days: [], // Added for weekly recurring + recurring_frequency: "weekly", // weekly, monthly, custom - default for recurring events business_id: "", business_name: "", hub: "", - contract_type: "W2", po_reference: "", status: "Draft", date: "", + include_backup: false, + backup_staff_count: 0, shifts: [{ shift_name: "Shift 1", - shift_contact: "", location_address: "", + same_as_billing: true, roles: [{ role: "", department: "", count: 1, - start_time: "12:00 PM", - end_time: "05:00 PM", - hours: 5, + start_time: "09:00", + end_time: "17:00", + hours: 8, uniform: "Type 1", break_minutes: 30, - cost_per_hour: 0, + rate_per_hour: 0, total_value: 0 }] }], - addons: { - goal: { enabled: false, text: "" }, - portal_access: false, - meal_provided: false, - travel_time: false, - tips: { enabled: false, amount: "300/300" } - }, - total: 0, - client_name: "", - client_email: "", - client_phone: "", - notes: "" + notes: "", + total: 0 }); + const [roleSearchOpen, setRoleSearchOpen] = useState({}); + + const { data: user } = useQuery({ + queryKey: ['current-user-form'], + queryFn: () => base44.auth.me(), + enabled: !currentUser, + }); + + const currentUserData = currentUser || user; + const userRole = currentUserData?.user_role || currentUserData?.role || "admin"; + const isVendor = userRole === "vendor"; + const { data: businesses = [] } = useQuery({ queryKey: ['businesses'], queryFn: () => base44.entities.Business.list(), initialData: [], }); + const { data: allRates = [] } = useQuery({ + queryKey: ['vendor-rates-all'], + queryFn: () => base44.entities.VendorRate.list(), + initialData: [], + }); + + const { data: vendorSettings = [] } = useQuery({ + queryKey: ['vendor-settings'], + queryFn: () => base44.entities.VendorDefaultSettings.list(), + initialData: [], + }); + + // Get unique roles for dropdown + const availableRoles = [...new Set(allRates.map(r => r.role_name))].sort(); + + // Get hubs for current vendor + const vendorHubs = isVendor + ? [...new Set(businesses.filter(b => b.business_name === currentUserData?.company_name).map(b => b.hub_building))].filter(Boolean) + : []; + // Auto-fill client details if current user is a client useEffect(() => { - if (currentUser && currentUser.user_role === "client" && !event) { - // Find client's business - const clientBusiness = businesses.find(b => - b.email === currentUser.email || b.contact_name === currentUser.full_name + if (currentUserData && userRole === "client" && !event) { + const clientBusiness = businesses.find(b => + b.email === currentUserData.email || b.contact_name === currentUserData.full_name ); if (clientBusiness) { @@ -83,24 +109,15 @@ export default function EventForm({ event, onSubmit, isSubmitting, currentUser } ...prev, business_id: clientBusiness.id, business_name: clientBusiness.business_name, - client_name: clientBusiness.contact_name || currentUser.full_name, - client_email: clientBusiness.email || currentUser.email, - client_phone: clientBusiness.phone || currentUser.phone, + hub: clientBusiness.hub_building || prev.hub, shifts: prev.shifts.map(shift => ({ ...shift, location_address: clientBusiness.address || shift.location_address })) })); - } else { - setFormData(prev => ({ - ...prev, - client_name: currentUser.full_name, - client_email: currentUser.email, - client_phone: currentUser.phone - })); } } - }, [currentUser, businesses, event]); + }, [currentUserData, businesses, event, userRole]); useEffect(() => { if (event) { @@ -119,365 +136,966 @@ export default function EventForm({ event, onSubmit, isSubmitting, currentUser } ...prev, business_id: businessId, business_name: selectedBusiness.business_name || "", - client_name: selectedBusiness.contact_name || prev.client_name || "", - client_email: selectedBusiness.email || prev.client_email || "", - client_phone: selectedBusiness.phone || prev.client_phone || "", shifts: prev.shifts.map(shift => ({ ...shift, - location_address: selectedBusiness.address || shift.location_address + location_address: shift.same_as_billing ? selectedBusiness.address || shift.location_address : shift.location_address })) })); } }; - const handleShiftsChange = (shifts) => { - setFormData(prev => ({ ...prev, shifts })); - - // Calculate total - const total = shifts.reduce((sum, shift) => { - const shiftTotal = shift.roles.reduce((roleSum, role) => roleSum + (role.total_value || 0), 0); - return sum + shiftTotal; + const calculateHours = (startTime, endTime, breakMinutes = 0) => { + if (!startTime || !endTime) return 0; + + const [startHour, startMin] = startTime.split(':').map(Number); + const [endHour, endMin] = endTime.split(':').map(Number); + + const startMinutes = startHour * 60 + startMin; + const endMinutes = endHour * 60 + endMin; + + let totalMinutes = endMinutes - startMinutes; + if (totalMinutes < 0) totalMinutes += 24 * 60; + + totalMinutes -= (breakMinutes || 0); + + return Math.max(0, totalMinutes / 60); + }; + + const getRateForRole = (roleName) => { + const rate = allRates.find(r => r.role_name === roleName && r.is_active); + return rate ? parseFloat(rate.client_rate || 0) : 0; + }; + + const handleRoleChange = (shiftIndex, roleIndex, field, value) => { + setFormData(prev => { + const newShifts = [...prev.shifts]; + const role = newShifts[shiftIndex].roles[roleIndex]; + + role[field] = value; + + // Auto-populate rate when role is selected + if (field === 'role') { + const rate = getRateForRole(value); + role.rate_per_hour = rate; + } + + // Recalculate hours when time changes + if (field === 'start_time' || field === 'end_time' || field === 'break_minutes') { + role.hours = calculateHours(role.start_time, role.end_time, role.break_minutes); + } + + // Recalculate total + role.total_value = (role.rate_per_hour || 0) * (role.hours || 0) * (role.count || 1); + + return { ...prev, shifts: newShifts }; + }); + + // Recalculate grand total + updateGrandTotal(); + }; + + const updateGrandTotal = () => { + setTimeout(() => { + setFormData(prev => { + const total = prev.shifts.reduce((sum, shift) => { + const shiftTotal = shift.roles.reduce((roleSum, role) => roleSum + (role.total_value || 0), 0); + return sum + shiftTotal; + }, 0); + return { ...prev, total }; + }); }, 0); - setFormData(prev => ({ ...prev, total })); }; - const handleAddonsChange = (addons) => { - setFormData(prev => ({ ...prev, addons })); + const handleAddRole = (shiftIndex) => { + setFormData(prev => { + const newShifts = [...prev.shifts]; + newShifts[shiftIndex].roles.push({ + role: "", + department: "", + count: 1, + start_time: "09:00", + end_time: "17:00", + hours: 8, + uniform: "Type 1", + break_minutes: 30, + rate_per_hour: 0, + total_value: 0 + }); + return { ...prev, shifts: newShifts }; + }); }; - const handleRecurringToggle = (checked) => { + const handleRemoveRole = (shiftIndex, roleIndex) => { + setFormData(prev => { + const newShifts = [...prev.shifts]; + newShifts[shiftIndex].roles.splice(roleIndex, 1); + return { ...prev, shifts: newShifts }; + }); + updateGrandTotal(); + }; + + const handleAddShift = () => { setFormData(prev => ({ ...prev, - is_recurring: checked, - recurrence_type: checked ? "date_range" : "single" + shifts: [...prev.shifts, { + shift_name: `Shift ${prev.shifts.length + 1}`, + location_address: "", + same_as_billing: true, + roles: [{ + role: "", + department: "", + count: 1, + start_time: "09:00", + end_time: "17:00", + hours: 8, + uniform: "Type 1", + break_minutes: 30, + rate_per_hour: 0, + total_value: 0 + }] + }] })); }; - const handleScatterDateSelect = (date) => { - const dateString = format(date, 'yyyy-MM-dd'); + const handleOrderTypeChange = (type) => { setFormData(prev => { - const currentDates = prev.scatter_dates || []; - const exists = currentDates.includes(dateString); + const newState = { + ...prev, + order_type: type, + date: "", // Always clear the single 'date' field on order type change, it will be set by rapid/one_time/permanent if needed. + recurrence_start_date: "", // Clear these when order type changes + recurrence_end_date: "", + scatter_dates: [], // Clear these when order type changes + recurring_days: [], // Clear these when order type changes + recurring_frequency: "weekly" // Default for recurring + }; + + // Set recurrence_type for backend compatibility if it's still used there, but new UI uses recurring_frequency + if (type === "recurring") { + newState.recurrence_type = "date_range"; // Default to 'date_range' to maintain previous behavior if possible + } else { + newState.recurrence_type = "single"; // For one_time, rapid, permanent + } + + if (type === "rapid" && !prev.date) { // Only set if not already set, or if changing from another type + newState.date = format(new Date(), 'yyyy-MM-dd'); // Default rapid to today if no date + } else if (type === "one_time" || type === "permanent") { + newState.date = prev.date; // Preserve date if user had one for one_time/permanent + } + // If type is recurring, date is already cleared. Other recurring fields default/cleared. + + return newState; + }); + }; + + const handleScatterDateSelect = (dates) => { + setFormData(prev => ({ + ...prev, + scatter_dates: dates?.map(d => format(d, 'yyyy-MM-dd')).sort() || [] + })); + }; + + const handleDayToggle = (day) => { + setFormData(prev => { + const days = prev.recurring_days || []; + const exists = days.includes(day); return { ...prev, - scatter_dates: exists - ? currentDates.filter(d => d !== dateString) - : [...currentDates, dateString].sort() + recurring_days: exists + ? days.filter(d => d !== day) + : [...days, day].sort((a,b) => a-b) // Ensure days are sorted }; }); }; const handleSubmit = (e, isDraft = false) => { e.preventDefault(); + let status; + if (isDraft) { + status = "Draft"; + } else { + switch (formData.order_type) { + case "rapid": + status = "Active"; // Rapid requests are active immediately upon submission + break; + case "one_time": + case "recurring": + case "permanent": + default: // In case of an unexpected order_type, default to Pending + status = "Pending"; // These types typically need approval/processing + break; + } + } + const dataToSubmit = { ...formData, - status: isDraft ? "Draft" : formData.status + status: status }; onSubmit(dataToSubmit); }; - const selectedVendor = currentUser?.user_role === "vendor" ? currentUser?.company_name : formData.vendor_name || formData.business_name; - return ( - handleSubmit(e, false)}> -
- {/* One-time vs Recurring Toggle */} - + handleSubmit(e, false)} className="space-y-6"> + {/* Order Type Selection - 4 Options */} + + +

Select Order Type

+
+ {/* Rapid */} + + + {/* One-Time */} + + + {/* Recurring */} + + + {/* Permanent */} + +
+
+
+ + {/* Recurring Options - Android Style */} + {formData.order_type === 'recurring' && ( + -
-
- - - +
+ + +
+ + {/* Frequency Selection */} +
+ +
+ + +
- {/* Recurring Options */} - {formData.is_recurring && ( -
- - handleChange('recurrence_type', value)} - className="space-y-3" - > -
- - -
-
- - -
-
- - {/* Date Range Inputs */} - {formData.recurrence_type === "date_range" && ( -
-
- - handleChange('recurrence_start_date', e.target.value)} - className="border-slate-200" - /> -
-
- - handleChange('recurrence_end_date', e.target.value)} - className="border-slate-200" - /> -
-
- )} - - {/* Scatter Dates Picker */} - {formData.recurrence_type === "scatter" && ( -
- - - - - - - new Date(d)) || []} - onSelect={(dates) => { - setFormData(prev => ({ - ...prev, - scatter_dates: dates?.map(d => format(d, 'yyyy-MM-dd')).sort() || [] - })); - }} - initialFocus - /> - - - {formData.scatter_dates && formData.scatter_dates.length > 0 && ( -
- {formData.scatter_dates.map(date => ( -
- {format(new Date(date), 'MMM d, yyyy')} - -
- ))} -
- )} + {/* Weekly - Android Alarm Style Day Selection */} + {formData.recurring_frequency === 'weekly' && ( +
+ +
+ {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((day, index) => { + const isSelected = (formData.recurring_days || []).includes(index); + return ( + + ); + })} +
+ {formData.recurring_days && formData.recurring_days.length > 0 && ( +
+ {formData.recurring_days.length} day{formData.recurring_days.length > 1 ? 's' : ''} selected
)}
)} - - - {/* Event Details */} - - -

Event

- -
- {/* Event Name */} -
- - handleChange('event_name', e.target.value)} - placeholder="Event Name" - required - className="border-slate-200" - /> -
- - {/* Date and Hub (only for one-time events) */} - {!formData.is_recurring && ( + {/* Monthly - Date Range */} + {formData.recurring_frequency === 'monthly' && ( +
+
- + handleChange('date', e.target.value)} - required - className="border-slate-200" + value={formData.recurrence_start_date || ""} + onChange={(e) => handleChange('recurrence_start_date', e.target.value)} + className="border-slate-300 bg-white h-12" />
- - + + handleChange('recurrence_end_date', e.target.value)} + className="border-slate-300 bg-white h-12" + />
+
+ )} + + {/* Custom - Multiple Specific Dates */} + {formData.recurring_frequency === 'custom' && ( +
+ + + + + + + new Date(d)) || []} + onSelect={handleScatterDateSelect} + initialFocus + className="rounded-lg border-0" + /> + + + {formData.scatter_dates && formData.scatter_dates.length > 0 && ( +
+ {formData.scatter_dates.map(date => ( + + {format(new Date(date), 'MMM d, yyyy')} + + + ))} +
+ )} +
+ )} + + {/* Summary Section */} + {((formData.recurring_frequency === 'weekly' && formData.recurring_days?.length > 0) || + (formData.recurring_frequency === 'monthly' && formData.recurrence_start_date && formData.recurrence_end_date) || + (formData.recurring_frequency === 'custom' && formData.scatter_dates?.length > 0)) && ( +
+
+ + Recurrence Summary +
+
+ {formData.recurring_frequency === 'weekly' && formData.recurring_days?.length > 0 && ( +

• Repeats every + {['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] + .filter((_, i) => formData.recurring_days.includes(i)) + .join(', ')} +

+ )} + {formData.recurring_frequency === 'monthly' && formData.recurrence_start_date && formData.recurrence_end_date && ( +

• Repeats monthly from {format(new Date(formData.recurrence_start_date), 'MMM d, yyyy')} to {format(new Date(formData.recurrence_end_date), 'MMM d, yyyy')}

+ )} + {formData.recurring_frequency === 'custom' && formData.scatter_dates?.length > 0 && ( +

{formData.scatter_dates.length} specific date{formData.scatter_dates.length > 1 ? 's' : ''} selected

+ )} +
+
+ )} + + + )} + + {/* Event Details */} + + +

Event

+ +
+
+ + handleChange('event_name', e.target.value)} + placeholder="Event Name" + required + className="border-slate-200" + /> +
+ +
+ {(formData.order_type === 'one_time' || formData.order_type === 'rapid' || formData.order_type === 'permanent') && ( +
+ + handleChange('date', e.target.value)} + required + className="border-slate-200" + /> +
)} - {formData.is_recurring && ( + {/* Hub Selection - Show if vendor has multiple locations */} + {isVendor && vendorHubs.length > 1 ? (
- +
- )} - - {/* Contract Type and PO Reference */} -
+ ) : (
- - -
-
- + handleChange('po_reference', e.target.value)} - placeholder="PO reference" + id="hub" + value={formData.hub || ""} + onChange={(e) => handleChange('hub', e.target.value)} + placeholder="Hub location" className="border-slate-200" />
-
- - {/* Business Selection (only for vendors) */} - {currentUser?.user_role === "vendor" && ( -
- - -
)} +
- {/* Business Display (for clients - read-only) */} - {currentUser?.user_role === "client" && formData.business_name && ( -
- -
- -
-

{formData.business_name}

- {formData.client_email && ( -

{formData.client_email}

+ {/* PO Reference - Now Optional */} +
+ + handleChange('po_reference', e.target.value)} + placeholder="PO reference" + className="border-slate-200" + /> +
+ + {/* Client/Business Selection */} + {isVendor && ( +
+ + + {formData.business_id && businesses.find(b => b.id === formData.business_id)?.rate_group && ( +

+ ℹ️ Rate Group: {businesses.find(b => b.id === formData.business_id)?.rate_group} (Auto-detected from location) +

+ )} +
+ )} + + {/* Zero Risk Backup Staff */} +
+
+ { + handleChange('include_backup', checked); + if (!checked) handleChange('backup_staff_count', 0); + }} + className="mt-1" + /> +
+ +

+ Extra pool of staff in case of call-outs or no-shows +

+ {formData.include_backup && ( +
+ + handleChange('backup_staff_count', parseInt(e.target.value) || 1)} + className="w-24 mt-1 border-green-300" + /> +
+ )} +
+
+
+
+ + + + {/* Shifts Section */} + {formData.shifts.map((shift, shiftIndex) => ( + + +
+
+
+ {shiftIndex + 1} +
+
+

{shift.shift_name}

+ {shift.location_address && ( +

+ + {shift.location_address} +

+ )} +
+
+ +
+ + {/* Roles */} +
+ {shift.roles.map((role, roleIndex) => ( +
+
+
+ {roleIndex + 1} +
+
+ {/* Service/Role with Search */} +
+ + setRoleSearchOpen(prev => ({ ...prev, [`${shiftIndex}-${roleIndex}`]: open }))} + > + + + + + + + No role found. + + {availableRoles.map((roleName) => ( + { + handleRoleChange(shiftIndex, roleIndex, 'role', roleName); + setRoleSearchOpen(prev => ({ ...prev, [`${shiftIndex}-${roleIndex}`]: false })); + }} + > + {roleName} + + ))} + + + + +
+ + {/* Count */} +
+ +
+ + handleRoleChange(shiftIndex, roleIndex, 'count', parseInt(e.target.value) || 1)} + className="w-16 text-center" + /> + +
+
+ + {/* Start Time */} +
+ + handleRoleChange(shiftIndex, roleIndex, 'start_time', e.target.value)} + className="border-slate-200" + /> +
+ + {/* End Time */} +
+ + handleRoleChange(shiftIndex, roleIndex, 'end_time', e.target.value)} + className="border-slate-200" + /> +
+
+ + {shift.roles.length > 1 && ( + + )} +
+ +
+ {/* Department */} +
+ + handleRoleChange(shiftIndex, roleIndex, 'department', e.target.value)} + placeholder="Department" + className="border-slate-200" + /> +
+ + {/* Hours (Auto-calculated) */} +
+ +
+ + {role.hours || 0} + +
+
+ + {/* Break (min) */} +
+ + handleRoleChange(shiftIndex, roleIndex, 'break_minutes', parseInt(e.target.value) || 0)} + className="border-slate-200" + /> +
+ + {/* Uniform */} +
+ + +
+
+ + {/* Rate and Total */} +
+
+ +
+ $ + +
+
+
+ +
+ ${(role.total_value || 0).toFixed(2)} +
- )} + ))} + + {/* Add Role Button */} + +
+ + {/* Shift Total */} +
+ Shift Total: + + ${shift.roles.reduce((sum, r) => sum + (r.total_value || 0), 0).toFixed(2)} +
+ ))} - {/* Shifts Section */} - + {/* Add Another Shift Button */} + - {/* Action Buttons */} -
- - -
- - + {/* Other Instructions */} + + + +