import React, { useMemo, useState } 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 { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Plus, Minus, Trash2, Search, DollarSign, TrendingUp, Check } from "lucide-react"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; const DEPARTMENTS = [ "Accounting", "Operations", "Sales", "HR", "Finance", "IT", "Marketing", "Customer Service", "Logistics" ]; const UNIFORMS = ["Type 1", "Type 2", "Type 3", "Casual", "Formal"]; const TIME_OPTIONS = []; for (let h = 1; h <= 12; h++) { for (let m of ['00', '30']) { TIME_OPTIONS.push(`${h.toString().padStart(2, '0')}:${m} AM`); } } for (let h = 1; h <= 12; h++) { for (let m of ['00', '30']) { TIME_OPTIONS.push(`${h.toString().padStart(2, '0')}:${m} PM`); } } export default function ShiftRoleCard({ role, roleIndex, onRoleChange, onDelete, canDelete, selectedVendor }) { const [roleSearchOpen, setRoleSearchOpen] = useState(false); // Get current user to check role const { data: user } = useQuery({ queryKey: ['current-user-shift-role'], queryFn: () => base44.auth.me(), }); const userRole = user?.user_role || user?.role; const isClient = userRole === "client"; // Get client's vendor relationships if client const { data: clientVendors = [] } = useQuery({ queryKey: ['client-vendors-for-roles', user?.id], queryFn: async () => { if (!isClient) return []; const allEvents = await base44.entities.Event.list(); const clientEvents = allEvents.filter(e => e.client_email === user?.email || e.business_name === user?.company_name || e.created_by === user?.email ); const vendorNames = new Set(); clientEvents.forEach(event => { if (event.shifts && Array.isArray(event.shifts)) { event.shifts.forEach(shift => { if (shift.roles && Array.isArray(shift.roles)) { shift.roles.forEach(role => { if (role.vendor_name) vendorNames.add(role.vendor_name); }); } }); } }); return Array.from(vendorNames); }, enabled: isClient && !!user, initialData: [], }); // Fetch all vendor rates const { data: allRates = [], isLoading } = useQuery({ queryKey: ['vendor-rates-for-event'], queryFn: () => base44.entities.VendorRate.list(), initialData: [], }); // Filter rates by selected vendor AND client access const availableRates = useMemo(() => { if (!allRates || !Array.isArray(allRates)) return []; let filtered = allRates.filter(r => r && r.is_active); // If client, only show rates from vendors they work with if (isClient) { filtered = filtered.filter(r => { const hasVendorRelationship = clientVendors.length === 0 || clientVendors.includes(r.vendor_name); const isVisibleToClient = r.client_visibility === 'all' || (r.client_visibility === 'specific' && r.available_to_clients && Array.isArray(r.available_to_clients) && // Ensure it's an array before using includes r.available_to_clients.includes(user?.id)); return hasVendorRelationship && isVisibleToClient; }); } // Filter by selected vendor if provided if (selectedVendor) { filtered = filtered.filter(r => r.vendor_name === selectedVendor); } return filtered; }, [allRates, selectedVendor, isClient, clientVendors, user?.id]); // Group rates by category const ratesByCategory = useMemo(() => { if (!availableRates || !Array.isArray(availableRates)) return {}; return availableRates.reduce((acc, rate) => { if (!rate || !rate.category) return acc; if (!acc[rate.category]) acc[rate.category] = []; acc[rate.category].push(rate); return acc; }, {}); }, [availableRates]); // Handle role selection from vendor rates const handleRoleSelect = (rate) => { if (!rate) return; onRoleChange('role', rate.role_name || ''); onRoleChange('department', rate.category || ''); onRoleChange('cost_per_hour', rate.client_rate || 0); onRoleChange('vendor_name', rate.vendor_name || ''); onRoleChange('vendor_id', rate.vendor_id || ''); setRoleSearchOpen(false); }; // Get selected rate details const selectedRate = availableRates.find(r => r && r.role_name === role.role); return (
{/* Row Number */}
{roleIndex + 1}
{/* Role Selection with Vendor Rates - SEARCHABLE */}

No services found.

{selectedVendor && (

Contact {selectedVendor} to add services.

)} {!selectedVendor && (

Select a vendor first to see available services.

)}
{Object.entries(ratesByCategory || {}).map(([category, rates]) => ( {Array.isArray(rates) && rates.map((rate) => ( handleRoleSelect(rate)} className="flex items-center justify-between py-3 cursor-pointer" >

{rate.role_name}

{role.role === rate.role_name && ( )}
{rate.vendor_name} {rate.pricing_status === 'optimal' && ( Optimal Price )}

${rate.client_rate}

per hour

))}
))}
{/* Department (Auto-filled from category) */}
{/* Count */}
onRoleChange('count', parseInt(e.target.value) || 1)} className="w-14 h-9 text-center p-0 text-sm bg-white" />
{/* Time */}
{/* Hours Badge */}
{role.hours || 0}
{/* Uniform & Break */}
onRoleChange('break_minutes', parseInt(e.target.value) || 0)} className="h-9 text-center text-sm bg-white" placeholder="30" />
{/* Cost & Value */}
onRoleChange('cost_per_hour', parseFloat(e.target.value) || 0)} className="h-9 text-sm pl-6 bg-white" placeholder="0.00" disabled={!!selectedRate} />
{selectedRate && (

From vendor rate card

)}
${(role.total_value || 0).toFixed(2)}
{canDelete && ( )}
{/* Pricing Info Bar */} {selectedRate && (
Employee Wage: ${selectedRate.employee_wage || 0}/hr Markup: {selectedRate.markup_percentage || 0}% VA Fee: {selectedRate.vendor_fee_percentage || 0}%
Transparent Pricing
)}
); }