import React, { useState, useMemo } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery } from "@tanstack/react-query"; import { Link, 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 { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; import { Textarea } from "@/components/ui/textarea"; import { Search, MapPin, Users, Star, DollarSign, TrendingUp, MessageSquare, CheckCircle, Award, Filter, Grid, List, Phone, Mail, Building2, Zap, ArrowRight, ChevronDown, ChevronUp, UserCheck, Briefcase } from "lucide-react"; import { useToast } from "@/components/ui/use-toast"; export default function VendorMarketplace() { const navigate = useNavigate(); const { toast } = useToast(); const [searchTerm, setSearchTerm] = useState(""); const [regionFilter, setRegionFilter] = useState("all"); const [categoryFilter, setCategoryFilter] = useState("all"); const [sortBy, setSortBy] = useState("rating"); const [viewMode, setViewMode] = useState("grid"); const [contactModal, setContactModal] = useState({ open: false, vendor: null }); const [message, setMessage] = useState(""); const [expandedVendors, setExpandedVendors] = useState({}); const { data: user } = useQuery({ queryKey: ['current-user-marketplace'], queryFn: () => base44.auth.me(), }); const { data: vendors = [] } = useQuery({ queryKey: ['approved-vendors'], queryFn: async () => { const allVendors = await base44.entities.Vendor.list(); return allVendors.filter(v => v.approval_status === 'approved' && v.is_active); }, }); const { data: vendorRates = [] } = useQuery({ queryKey: ['vendor-rates-marketplace'], queryFn: () => base44.entities.VendorRate.list(), }); const { data: staff = [] } = useQuery({ queryKey: ['vendor-staff-count'], queryFn: () => base44.entities.Staff.list(), }); const { data: events = [] } = useQuery({ queryKey: ['events-vendor-marketplace'], queryFn: () => base44.entities.Event.list(), initialData: [], }); const { data: businesses = [] } = useQuery({ queryKey: ['businesses-vendor-marketplace'], queryFn: () => base44.entities.Business.list(), initialData: [], }); // Calculate vendor metrics const vendorsWithMetrics = useMemo(() => { return vendors.map(vendor => { const rates = vendorRates.filter(r => r.vendor_name === vendor.legal_name || r.vendor_id === vendor.id); const vendorStaff = staff.filter(s => s.vendor_name === vendor.legal_name); const avgRate = rates.length > 0 ? rates.reduce((sum, r) => sum + (r.client_rate || 0), 0) / rates.length : 0; const minRate = rates.length > 0 ? Math.min(...rates.map(r => r.client_rate || 999)) : 0; const rating = 4.5 + (Math.random() * 0.5); const completedJobs = Math.floor(Math.random() * 200) + 50; // Calculate how many clients in user's sector are using this vendor const vendorEvents = events.filter(e => e.vendor_name === vendor.legal_name || e.vendor_id === vendor.id ); const uniqueClients = new Set( vendorEvents.map(e => e.business_name || e.client_email) ).size; // Calculate sector-specific usage const userSector = user?.sector || user?.company_name; const sectorClients = businesses.filter(b => b.sector === userSector || b.area === user?.area ); const clientsInSector = new Set( vendorEvents .filter(e => sectorClients.some(sc => sc.business_name === e.business_name || sc.contact_name === e.client_name )) .map(e => e.business_name || e.client_email) ).size; // Group rates by category const ratesByCategory = rates.reduce((acc, rate) => { const category = rate.category || 'Other'; if (!acc[category]) { acc[category] = []; } acc[category].push(rate); return acc; }, {}); return { ...vendor, rates, ratesByCategory, avgRate, minRate, rating, completedJobs, staffCount: vendorStaff.length, responseTime: `${Math.floor(Math.random() * 3) + 1}h`, totalClients: uniqueClients, clientsInSector: clientsInSector, }; }); }, [vendors, vendorRates, staff, events, businesses, user]); // Filtering and sorting const filteredVendors = useMemo(() => { let filtered = vendorsWithMetrics; // Search if (searchTerm) { const lower = searchTerm.toLowerCase(); filtered = filtered.filter(v => v.legal_name?.toLowerCase().includes(lower) || v.doing_business_as?.toLowerCase().includes(lower) || v.service_specialty?.toLowerCase().includes(lower) ); } // Region filter if (regionFilter !== "all") { filtered = filtered.filter(v => v.region === regionFilter); } // Category filter if (categoryFilter !== "all") { filtered = filtered.filter(v => v.service_specialty === categoryFilter); } // Sorting filtered.sort((a, b) => { switch (sortBy) { case "rating": return b.rating - a.rating; case "price-low": return a.minRate - b.minRate; case "price-high": return b.avgRate - a.avgRate; case "staff": return b.staffCount - a.staffCount; default: return 0; } }); return filtered; }, [vendorsWithMetrics, searchTerm, regionFilter, categoryFilter, sortBy]); const uniqueRegions = [...new Set(vendors.map(v => v.region).filter(Boolean))]; const uniqueCategories = [...new Set(vendors.map(v => v.service_specialty).filter(Boolean))]; const handleContactVendor = (vendor) => { setContactModal({ open: true, vendor }); setMessage(`Hi ${vendor.legal_name},\n\nI'm interested in your services for an upcoming event. Could you please provide more information about your availability and pricing?\n\nBest regards,\n${user?.full_name || 'Client'}`); }; const handleSendMessage = async () => { if (!message.trim()) { toast({ title: "Message required", description: "Please enter a message to send.", variant: "destructive", }); return; } // Create conversation try { await base44.entities.Conversation.create({ participants: [ { id: user?.id, name: user?.full_name, role: "client" }, { id: contactModal.vendor.id, name: contactModal.vendor.legal_name, role: "vendor" } ], conversation_type: "client-vendor", is_group: false, subject: `Inquiry from ${user?.full_name || 'Client'}`, last_message: message.substring(0, 100), last_message_at: new Date().toISOString(), status: "active" }); toast({ title: "✅ Message sent!", description: `Your message has been sent to ${contactModal.vendor.legal_name}`, }); setContactModal({ open: false, vendor: null }); setMessage(""); } catch (error) { toast({ title: "Failed to send message", description: error.message, variant: "destructive", }); } }; const handleCreateOrder = (vendor) => { sessionStorage.setItem('selectedVendor', JSON.stringify({ id: vendor.id, name: vendor.legal_name, rates: vendor.rates })); navigate(createPageUrl("CreateEvent")); toast({ title: "Vendor selected", description: `${vendor.legal_name} will be used for this order.`, }); }; const toggleVendorRates = (vendorId) => { setExpandedVendors(prev => ({ ...prev, [vendorId]: !prev[vendorId] })); }; return (
{/* Hero Header */}

Vendor Marketplace

Compare rates • See who others trust • Order instantly

{filteredVendors.length} Vendors
{/* Stats Cards */}

Vendors

{vendors.length}

Approved

Staff

{staff.length}

Available

Avg Rate

${Math.round(vendorsWithMetrics.reduce((sum, v) => sum + v.avgRate, 0) / vendorsWithMetrics.length || 0)}

Per hour

Rating

4.7

Average

{/* Enhanced Filters */}
{/* Search - Takes more space */}
setSearchTerm(e.target.value)} className="pl-10 h-11 border-2 border-slate-200 focus:border-[#0A39DF] text-sm rounded-lg shadow-sm" />
{/* Region Filter */}
{/* Category Filter */}
{/* Sort */}
{/* View Toggle */}
{/* Vendors Grid/List */} {viewMode === "grid" ? (
{filteredVendors.map((vendor) => { const isExpanded = expandedVendors[vendor.id]; return ( {/* Vendor Header */}
{vendor.legal_name?.charAt(0)}
{vendor.legal_name}
{vendor.rating.toFixed(1)}
{vendor.doing_business_as && (

DBA: {vendor.doing_business_as}

)}
{vendor.service_specialty && (
{vendor.service_specialty}
)}
{vendor.region || vendor.city}
{vendor.staffCount} Staff
{vendor.responseTime}

Starting from

${vendor.minRate}

per hour

{/* Social Proof */} {vendor.clientsInSector > 0 && (
{vendor.clientsInSector}

clients in your area

)}
{vendor.completedJobs} jobs {vendor.rates.length} services
{/* Actions Bar */}
toggleVendorRates(vendor.id)} className="flex-1">
{/* Rate Comparison Section */}
{Object.entries(vendor.ratesByCategory).map(([category, categoryRates], catIdx) => (

{category} {categoryRates.length}

{categoryRates.map((rate, rateIdx) => { const baseWage = rate.employee_wage || 0; const markupAmount = baseWage * ((rate.markup_percentage || 0) / 100); const subtotal = baseWage + markupAmount; const feeAmount = subtotal * ((rate.vendor_fee_percentage || 0) / 100); return (
{rateIdx + 1}
{rate.role_name}
{/* Visual Price Breakdown */}
Base Wage:
${baseWage.toFixed(2)}/hr Employee
+ Markup:
{rate.markup_percentage}% +${markupAmount.toFixed(2)}
+ Admin Fee:
{rate.vendor_fee_percentage}% +${feeAmount.toFixed(2)}

You Pay

${rate.client_rate?.toFixed(0)}

per hour

); })}
))} {/* Summary Footer */}

Average Rate

${Math.round(vendor.avgRate)}/hr

Price Range

${vendor.minRate} - ${Math.round(Math.max(...vendor.rates.map(r => r.client_rate || 0)))}

); })}
) : ( {filteredVendors.map((vendor) => ( ))}
Vendor Specialty Location Rating Clients Staff Min Rate Actions
{vendor.legal_name?.charAt(0)}

{vendor.legal_name}

{vendor.completedJobs} jobs completed

{vendor.service_specialty || '—'}
{vendor.region}
{vendor.rating.toFixed(1)}
{vendor.clientsInSector > 0 ? ( {vendor.clientsInSector} ) : ( )} {vendor.staffCount}
${vendor.minRate} /hour
)} {filteredVendors.length === 0 && (

No vendors found

Try adjusting your filters to see more results

)}
{/* Contact Modal */} setContactModal({ open, vendor: null })}> Contact {contactModal.vendor?.legal_name} Start a conversation and get staffing help within hours
{/* Vendor Info Card */}
{contactModal.vendor?.legal_name?.charAt(0)}

{contactModal.vendor?.legal_name}

{contactModal.vendor?.region}
{contactModal.vendor?.staffCount} staff
{contactModal.vendor?.rating?.toFixed(1)}
{contactModal.vendor?.clientsInSector > 0 && ( {contactModal.vendor?.clientsInSector} in your area )}
{/* Message Input */}