import React, { useState, useEffect } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { Zap, Send, Check, Edit3, MapPin, Clock, Users, AlertCircle, Sparkles, Mic, X, Calendar as CalendarIcon, ArrowLeft } from "lucide-react"; import { useToast } from "@/components/ui/use-toast"; import { motion, AnimatePresence } from "framer-motion"; import { format } from "date-fns"; // Helper function to convert 24-hour time to 12-hour format const convertTo12Hour = (time24) => { if (!time24 || time24 === "—") return time24; try { const parts = time24.split(':'); if (!parts || parts.length < 2) return time24; const hours = parseInt(parts[0], 10); const minutes = parseInt(parts[1], 10); if (isNaN(hours) || isNaN(minutes)) return time24; const period = hours >= 12 ? 'PM' : 'AM'; const hours12 = hours % 12 || 12; const minutesStr = minutes.toString().padStart(2, '0'); return `${hours12}:${minutesStr} ${period}`; } catch (error) { console.error('Error converting time:', error); return time24; } }; export default function RapidOrder() { const navigate = useNavigate(); const { toast } = useToast(); const queryClient = useQueryClient(); const [message, setMessage] = useState(""); const [conversation, setConversation] = useState([]); const [detectedOrder, setDetectedOrder] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [isListening, setIsListening] = useState(false); const [submissionTime, setSubmissionTime] = useState(null); const { data: user } = useQuery({ queryKey: ['current-user-rapid'], queryFn: () => base44.auth.me(), }); const { data: businesses } = useQuery({ queryKey: ['user-businesses'], queryFn: () => base44.entities.Business.filter({ contact_name: user?.full_name }), enabled: !!user, initialData: [], }); const createRapidOrderMutation = useMutation({ mutationFn: (orderData) => base44.entities.Event.create(orderData), onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: ['events'] }); queryClient.invalidateQueries({ queryKey: ['client-events'] }); const now = new Date(); setSubmissionTime(now); toast({ title: "✅ RAPID Order Created", description: "Order sent to preferred vendor with priority notification", }); // Show success message in chat setConversation(prev => [...prev, { role: 'assistant', content: `🚀 **Order Submitted Successfully!**\n\nOrder Number: **${data.id?.slice(-8) || 'RAPID-001'}**\nSubmitted: **${format(now, 'h:mm:ss a')}**\n\nYour preferred vendor has been notified and will assign staff shortly.`, isSuccess: true }]); // Reset after delay setTimeout(() => { navigate(createPageUrl("ClientDashboard")); }, 3000); }, }); const analyzeMessage = async (msg) => { setIsProcessing(true); setConversation(prev => [...prev, { role: 'user', content: msg }]); try { const response = await base44.integrations.Core.InvokeLLM({ prompt: `You are an order assistant. Analyze this message and extract order details: Message: "${msg}" Current user: ${user?.full_name} User's locations: ${businesses.map(b => b.business_name).join(', ')} Extract: 1. Urgency keywords (ASAP, today, emergency, call out, urgent, rapid, now) 2. Role/position needed (cook, bartender, server, dishwasher, etc.) 3. Number of staff (if mentioned, parse the number correctly - e.g., "5 cooks" = 5, "need 3 servers" = 3) 4. End time (if mentioned, extract the time - e.g., "until 5am" = "05:00", "until 11pm" = "23:00", "until midnight" = "00:00") 5. Location (if mentioned, otherwise use first available location) IMPORTANT: - Make sure to correctly extract the number of staff from phrases like "need 5 cooks" or "I need 3 bartenders" - If end time is mentioned (e.g., "until 5am", "till 11pm"), extract it in 24-hour format (e.g., "05:00", "23:00") - If no end time is mentioned, leave it as null Return a concise summary.`, response_json_schema: { type: "object", properties: { is_urgent: { type: "boolean" }, role: { type: "string" }, count: { type: "number" }, location: { type: "string" }, end_time: { type: "string" } } } }); const parsed = response; const primaryLocation = businesses[0]?.business_name || "Primary Location"; // Ensure count is properly set - default to 1 if not detected const staffCount = parsed.count && parsed.count > 0 ? parsed.count : 1; // Get current time for start_time (when ASAP) const now = new Date(); const currentTime = format(now, 'HH:mm'); // Handle end_time - use parsed end time or current time as confirmation time const endTime = parsed.end_time || currentTime; const order = { is_rapid: parsed.is_urgent || true, role: parsed.role || "Staff Member", count: staffCount, location: parsed.location || primaryLocation, start_time: currentTime, // Always use current time for ASAP orders (24-hour format for storage) end_time: endTime, // Use parsed end time or current time (24-hour format for storage) start_time_display: convertTo12Hour(currentTime), // For display end_time_display: convertTo12Hour(endTime), // For display business_name: primaryLocation, hub: businesses[0]?.hub_building || "Main Hub", submission_time: now // Store the actual submission time }; setDetectedOrder(order); const aiMessage = `Is this a RAPID ORDER for **${order.count} ${order.role}${order.count > 1 ? 's' : ''}** at **${order.location}**?\n\nStart Time: ${order.start_time_display}\nEnd Time: ${order.end_time_display}`; setConversation(prev => [...prev, { role: 'assistant', content: aiMessage, showConfirm: true }]); } catch (error) { setConversation(prev => [...prev, { role: 'assistant', content: "I couldn't process that. Please provide more details like: role needed, how many, and when." }]); } finally { setIsProcessing(false); } }; const handleSendMessage = () => { if (!message.trim()) return; analyzeMessage(message); setMessage(""); }; const handleVoiceInput = () => { if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) { toast({ title: "Voice not supported", description: "Your browser doesn't support voice input", variant: "destructive", }); return; } const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = new SpeechRecognition(); recognition.onstart = () => setIsListening(true); recognition.onend = () => setIsListening(false); recognition.onresult = (event) => { const transcript = event.results[0][0].transcript; setMessage(transcript); analyzeMessage(transcript); }; recognition.onerror = () => { setIsListening(false); toast({ title: "Voice input failed", description: "Please try typing instead", variant: "destructive", }); }; recognition.start(); }; const handleConfirmOrder = () => { if (!detectedOrder) return; const now = new Date(); const confirmTime = format(now, 'HH:mm'); const confirmTime12Hour = convertTo12Hour(confirmTime); // Create comprehensive order data with proper requested field and actual times const orderData = { event_name: `RAPID: ${detectedOrder.count} ${detectedOrder.role}${detectedOrder.count > 1 ? 's' : ''}`, is_rapid: true, status: "Pending", business_name: detectedOrder.business_name, hub: detectedOrder.hub, event_location: detectedOrder.location, date: now.toISOString().split('T')[0], requested: Number(detectedOrder.count), // Ensure it's a number client_name: user?.full_name, client_email: user?.email, notes: `RAPID ORDER - Submitted at ${detectedOrder.start_time_display} - Confirmed at ${confirmTime12Hour}\nStart: ${detectedOrder.start_time_display} | End: ${detectedOrder.end_time_display}`, shifts: [{ shift_name: "Emergency Shift", location: detectedOrder.location, roles: [{ role: detectedOrder.role, count: Number(detectedOrder.count), // Ensure it's a number start_time: detectedOrder.start_time, // Store in 24-hour format end_time: detectedOrder.end_time // Store in 24-hour format }] }] }; console.log('Creating RAPID order with data:', orderData); // Debug log createRapidOrderMutation.mutate(orderData); }; const handleEditOrder = () => { setConversation(prev => [...prev, { role: 'assistant', content: "Please describe what you'd like to change." }]); setDetectedOrder(null); }; return (
{/* Header */}

RAPID Order

Emergency staffing in minutes

{format(new Date(), 'EEEE, MMMM d, yyyy')}
{format(new Date(), 'h:mm a')}
Tell us what you need URGENT
{/* Chat Messages */}
{conversation.length === 0 && (

Need staff urgently?

Type or speak what you need, I'll handle the rest

Example: "We had a call out. Need 2 cooks ASAP"
Example: "Need 5 bartenders ASAP until 5am"
Example: "Emergency! Need 3 servers right now till midnight"
)} {conversation.map((msg, idx) => (
{msg.role === 'assistant' && !msg.isSuccess && (
AI Assistant
)}

{msg.content}

{msg.showConfirm && detectedOrder && (

Staff Needed

{detectedOrder.count} {detectedOrder.role}{detectedOrder.count > 1 ? 's' : ''}

Location

{detectedOrder.location}

Time

Start: {detectedOrder.start_time_display} | End: {detectedOrder.end_time_display}

)}
))}
{isProcessing && (
Processing your request...
)}
{/* Input */}