import React, { useState, useEffect } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery } from "@tanstack/react-query"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; 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, Zap, Shield, Search, Minus, Trash2, MapPin, X, RefreshCw, Users, CheckCircle2 } from "lucide-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; 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 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: "", 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: "", po_reference: "", status: "Draft", date: "", include_backup: false, backup_staff_count: 0, shifts: [{ shift_name: "Shift 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 }] }], 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 (currentUserData && userRole === "client" && !event) { const clientBusiness = businesses.find(b => b.email === currentUserData.email || b.contact_name === currentUserData.full_name ); if (clientBusiness) { setFormData(prev => ({ ...prev, business_id: clientBusiness.id, business_name: clientBusiness.business_name, hub: clientBusiness.hub_building || prev.hub, shifts: prev.shifts.map(shift => ({ ...shift, location_address: clientBusiness.address || shift.location_address })) })); } } }, [currentUserData, businesses, event, userRole]); useEffect(() => { if (event) { setFormData(event); } }, [event]); const handleChange = (field, value) => { setFormData(prev => ({ ...prev, [field]: value })); }; const handleBusinessChange = (businessId) => { const selectedBusiness = businesses.find(b => b.id === businessId); if (selectedBusiness) { setFormData(prev => ({ ...prev, business_id: businessId, business_name: selectedBusiness.business_name || "", shifts: prev.shifts.map(shift => ({ ...shift, location_address: shift.same_as_billing ? selectedBusiness.address || shift.location_address : shift.location_address })) })); } }; 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); }; 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 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, 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 handleOrderTypeChange = (type) => { setFormData(prev => { 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, 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: status }; onSubmit(dataToSubmit); }; return (
); }