import React, { useState, useEffect } from "react"; import { base44 } from "@/api/base44Client"; import { useMutation, useQuery } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { Building2, FileText, MapPin, DollarSign, Sparkles, Upload, CheckCircle2, Loader2, AlertCircle, ArrowRight, ArrowLeft, Shield, TrendingUp, Users, Briefcase, Mail, Phone, Hash, Search, Calendar, Plus, Trash2, Check, Target } from "lucide-react"; import { useToast } from "@/components/ui/use-toast"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import DragDropFileUpload from "@/components/common/DragDropFileUpload"; import DocumentViewer from "@/components/vendor/DocumentViewer"; // Google Places Autocomplete Component const GoogleAddressInput = ({ value, onChange, placeholder, label, required }) => { const [inputValue, setInputValue] = useState(value || ""); const [suggestions, setSuggestions] = useState([]); const [showSuggestions, setShowSuggestions] = useState(false); const inputRef = React.useRef(null); useEffect(() => { setInputValue(value || ""); }, [value]); const handleAddressSearch = async (searchText) => { setInputValue(searchText); if (searchText.length < 3) { setSuggestions([]); return; } try { // Use Google Places API via integration const response = await base44.integrations.Core.InvokeLLM({ prompt: `Extract and return ONLY a valid JSON array of 5 US address suggestions for: "${searchText}". Format each as: {"address": "full formatted address", "city": "city", "state": "state", "zip": "zip"}. Return ONLY the JSON array, no other text.`, response_json_schema: { type: "object", properties: { suggestions: { type: "array", items: { type: "object", properties: { address: { type: "string" }, city: { type: "string" }, state: { type: "string" }, zip: { type: "string" } } } } } } }); if (response?.suggestions) { setSuggestions(response.suggestions); setShowSuggestions(true); } } catch (error) { console.error("Address search error:", error); } }; const handleSelectAddress = (suggestion) => { const fullAddress = `${suggestion.address}, ${suggestion.city}, ${suggestion.state} ${suggestion.zip}`; setInputValue(fullAddress); onChange(fullAddress); setSuggestions([]); setShowSuggestions(false); }; return (
{ handleAddressSearch(e.target.value); }} onBlur={() => { // Delay to allow click on suggestion setTimeout(() => setShowSuggestions(false), 200); }} onFocus={() => { if (suggestions.length > 0) setShowSuggestions(true); }} placeholder={placeholder} className="pl-10" />
{showSuggestions && suggestions.length > 0 && (
{suggestions.map((suggestion, idx) => ( ))}
)}
); }; export default function SmartVendorOnboarding() { const { toast } = useToast(); const navigate = useNavigate(); const [currentStep, setCurrentStep] = useState(0); // Changed from 1 to 0 for welcome screen const [generatingRates, setGeneratingRates] = useState(false); // Function to detect minimum wage based on business address const getMinimumWageFromAddress = (address) => { if (!address) return 18; // Default fallback const addr = address.toLowerCase(); // State-specific minimum wages (as of 2024) if (addr.includes('california') || addr.includes(' ca ') || addr.includes('ca,')) return 16.00; if (addr.includes('washington') || addr.includes(' wa ')) return 16.28; if (addr.includes('massachusetts') || addr.includes(' ma ')) return 15.00; if (addr.includes('new york') || addr.includes(' ny ')) return 15.00; if (addr.includes('connecticut') || addr.includes(' ct ')) return 15.00; if (addr.includes('arizona') || addr.includes(' az ')) return 14.35; if (addr.includes('colorado') || addr.includes(' co ')) return 14.42; if (addr.includes('maine') || addr.includes(' me ')) return 14.15; if (addr.includes('oregon') || addr.includes(' or ')) return 14.20; if (addr.includes('vermont') || addr.includes(' vt ')) return 13.67; if (addr.includes('illinois') || addr.includes(' il ')) return 14.00; if (addr.includes('rhode island') || addr.includes(' ri ')) return 14.00; if (addr.includes('new jersey') || addr.includes(' nj ')) return 15.13; if (addr.includes('florida') || addr.includes(' fl ')) return 12.00; if (addr.includes('nevada') || addr.includes(' nv ')) return 12.00; if (addr.includes('hawaii') || addr.includes(' hi ')) return 14.00; if (addr.includes('texas') || addr.includes(' tx ')) return 7.25; if (addr.includes('georgia') || addr.includes(' ga ')) return 7.25; if (addr.includes('pennsylvania') || addr.includes(' pa ')) return 7.25; if (addr.includes('ohio') || addr.includes(' oh ')) return 10.45; if (addr.includes('michigan') || addr.includes(' mi ')) return 10.33; if (addr.includes('virginia') || addr.includes(' va ')) return 12.00; if (addr.includes('north carolina') || addr.includes(' nc ')) return 7.25; if (addr.includes('tennessee') || addr.includes(' tn ')) return 7.25; return 15.00; // Default minimum wage for unspecified states }; const [formData, setFormData] = useState({ // NEW: NDA Step (Step 1) nda_acknowledged: false, nda_signed_by: "", nda_signature_date: "", nda_signature_time: "", nda_signature_image: "", // NEW: Store the signature image data // Contract Data (now Step 2) contract_review_notes: "", contract_acknowledged: false, contract_va_fee_acknowledged: false, contract_review_time: 0, // Business Identity (now Step 3) legal_name: "", dba: "", tax_id: "", business_type: "", primary_contact_name: "", primary_contact_email: "", primary_contact_phone: "", billing_address: "", service_address: "", same_as_billing: false, // This now means "billing address is same as service address" total_employees: "", has_software: "", software_name: "", software_type: "", // Documents (now Step 4) w9_file: null, coi_file: null, sos_file: null, w9_url: "", coi_url: "", sos_url: "", background_check_attestation: false, i9_compliance_attestation: false, legal_compliance_attestation: false, // Service Coverage (now Step 5) coverage_regions: [], selected_states: [], selected_cities: {}, // Rate Proposals (now Step 6) rate_proposals: [], default_location: "" }); const [uploadingDoc, setUploadingDoc] = useState(null); const [validatingDoc, setValidatingDoc] = useState(null); const [docValidation, setDocValidation] = useState({ w9: null, coi: null, sos: null, // contract: null, // Removed for contract upload status }); const [showAIInsights, setShowAIInsights] = useState(false); const [aiInsights, setAiInsights] = useState(null); // Get invite data from URL const urlParams = new URLSearchParams(window.location.search); const inviteCode = urlParams.get('invite'); const { data: invite } = useQuery({ queryKey: ['vendor-invite', inviteCode], queryFn: async () => { if (!inviteCode) return null; const invites = await base44.entities.VendorInvite.filter({ invite_code: inviteCode }); return invites[0]; }, enabled: !!inviteCode }); // Pre-fill data from invite useEffect(() => { if (invite) { setFormData(prev => ({ ...prev, legal_name: invite.company_name || "", primary_contact_name: invite.primary_contact_name || "", primary_contact_email: invite.primary_contact_email || "" })); } }, [invite]); const steps = [ { number: 0, title: "Welcome", icon: Sparkles, subtitle: "Let's get started" }, { number: 1, title: "NDA & Trust", icon: Shield, subtitle: "Sign and accept agreement" }, { number: 2, title: "Foodbuy Contract", icon: FileText, subtitle: "Review & acknowledge terms" }, { number: 3, title: "Business Identity", icon: Building2, subtitle: "Let's set your stage" }, { number: 4, title: "Documents & Validation", icon: Shield, subtitle: "Compliance essentials" }, { number: 5, title: "Service Coverage", icon: MapPin, subtitle: "Where you operate" }, { number: 6, title: "Rate Proposals", icon: DollarSign, subtitle: "Competitive pricing" }, { number: 7, title: "AI Intelligence", icon: Sparkles, subtitle: "Market insights" } ]; const progressPercentage = currentStep === 0 ? 0 : ((currentStep - 1) / (steps.length - 2)) * 100; // Upload document const handleFileUpload = async (file, docType) => { if (!file) return; setUploadingDoc(docType); try { // Upload file const { file_url } = await base44.integrations.Core.UploadFile({ file }); setFormData(prev => ({ ...prev, [`${docType}_url`]: file_url, [`${docType}_file`]: file })); // For contract, the logic has been removed as it's handled by DocumentViewer // and AI analysis of an uploaded contract is no longer directly here. // Validate document with AI setValidatingDoc(docType); const validation = await validateDocument(file_url, docType); setDocValidation(prev => ({ ...prev, [docType]: validation })); toast({ title: "Document Uploaded", description: validation.isValid ? "✅ Document validated successfully" : "⚠️ Please review validation notes", }); } catch (error) { toast({ title: "Upload Failed", description: error.message, variant: "destructive" }); } finally { setUploadingDoc(null); setValidatingDoc(null); } }; // Validate document with AI const validateDocument = async (fileUrl, docType) => { const prompts = { w9: "Analyze this W-9 tax form and verify: 1) Business name is filled 2) Tax ID is present 3) Business entity type is checked 4) Signature is present. Return validation results.", coi: "Analyze this Certificate of Insurance and verify: 1) General liability coverage is present 2) Coverage amount meets $1M minimum 3) Policy is not expired 4) KROW or client is listed as additional insured. Return validation results.", sos: "Analyze this Secretary of State certificate and verify: 1) Business is actively registered 2) Registration is current/not expired 3) Business name matches application 4) State of registration. Return validation results." }; try { const analysis = await base44.integrations.Core.InvokeLLM({ prompt: prompts[docType], file_urls: [fileUrl], response_json_schema: { type: "object", properties: { isValid: { type: "boolean" }, businessName: { type: "string" }, expiryDate: { type: "string" }, registrationState: { type: "string" }, issues: { type: "array", items: { type: "string" } }, notes: { type: "string" } } } }); return analysis; } catch (error) { return { isValid: false, issues: ["Unable to validate document automatically"], notes: "Manual review required" }; } }; // Generate AI rate suggestions - This function remains but its direct UI trigger in Step 4 is removed const generateAIRates = async () => { setGeneratingRates(true); try { const response = await base44.integrations.Core.InvokeLLM({ prompt: ` Generate competitive rate proposals for ${formData.legal_name}. Business Type: ${formData.business_type} Service Regions: ${Object.values(formData.selected_cities).flat().map(city => city).join(", ")} Total Employees: ${formData.total_employees} Software Type: ${formData.software_type} Provide 10-15 common staffing roles with competitive rates for the hospitality/event industry. Consider regional market rates and vendor's operational efficiency. For each role, provide: - Role name - Category (Kitchen and Culinary, Concessions, Facilities, Bartending, Security, Event Staff, Management) - Employee wage (competitive market rate) - Suggested markup percentage (18-25% based on role complexity) - Calculated client rate `, add_context_from_internet: true, response_json_schema: { type: "object", properties: { roles: { type: "array", items: { type: "object", properties: { role_name: { type: "string" }, category: { type: "string" }, employee_wage: { type: "number" }, markup_percentage: { type: "number" }, client_rate: { type: "number" }, market_comparison: { type: "string" } } } } } } }); if (response?.roles) { setFormData(prev => ({ ...prev, rate_proposals: response.roles })); toast({ title: "Rates Generated", description: `${response.roles.length} competitive rates suggested`, }); } } catch (error) { toast({ title: "Generation Failed", description: error.message, variant: "destructive" }); } finally { setGeneratingRates(null); } }; // Generate AI insights const generateAIInsights = async () => { try { const insights = await base44.integrations.Core.InvokeLLM({ prompt: ` Analyze this vendor application and provide strategic insights: Vendor: ${formData.legal_name} Business Type: ${formData.business_type} Total Employees: ${formData.total_employees} Software: ${formData.software_name || formData.software_type} Service Areas: ${Object.values(formData.selected_cities).flat().map(city => city).join(", ")} Rate Proposals: ${formData.rate_proposals.length} roles Provide: 1. Competitive positioning (1-5 stars) 2. Market alignment assessment 3. Pricing competitiveness 4. Operational readiness score 5. Recommended focus areas 6. Potential challenges `, add_context_from_internet: true, response_json_schema: { type: "object", properties: { overall_score: { type: "number" }, competitive_position: { type: "string" }, market_alignment: { type: "string" }, pricing_analysis: { type: "string" }, operational_readiness: { type: "string" }, strengths: { type: "array", items: { type: "string" } }, recommendations: { type: "array", items: { type: "string" } }, potential_challenges: { type: "array", items: { type: "string" } } } } }); setAiInsights(insights); setShowAIInsights(true); } catch (error) { toast({ title: "Analysis Failed", description: error.message, variant: "destructive" }); } }; // US States and Major Cities Data const usLocationData = { "Alabama": ["Birmingham", "Montgomery", "Mobile", "Huntsville"], "Alaska": ["Anchorage", "Fairbanks", "Juneau"], "Arizona": ["Phoenix", "Tucson", "Mesa", "Scottsdale", "Chandler"], "Arkansas": ["Little Rock", "Fort Smith", "Fayetteville"], "California": ["Los Angeles", "San Francisco", "San Diego", "San Jose", "Sacramento", "Oakland", "Fresno", "Long Beach", "Anaheim", "Bakersfield"], "Colorado": ["Denver", "Colorado Springs", "Aurora", "Boulder", "Fort Collins"], "Connecticut": ["Hartford", "New Haven", "Stamford", "Bridgeport"], "Delaware": ["Wilmington", "Dover", "Newark"], "Florida": ["Miami", "Orlando", "Tampa", "Jacksonville", "Fort Lauderdale", "West Palm Beach"], "Georgia": ["Atlanta", "Savannah", "Augusta", "Columbus", "Macon"], "Hawaii": ["Honolulu", "Hilo", "Kailua"], "Idaho": ["Boise", "Meridian", "Nampa"], "Illinois": ["Chicago", "Aurora", "Naperville", "Rockford", "Joliet"], "Indiana": ["Indianapolis", "Fort Wayne", "Evansville", "South Bend"], "Iowa": ["Des Moines", "Cedar Rapids", "Davenport"], "Kansas": ["Wichita", "Overland Park", "Kansas City", "Topeka"], "Kentucky": ["Louisville", "Lexington", "Bowling Green"], "Louisiana": ["New Orleans", "Baton Rouge", "Shreveport", "Lafayette"], "Maine": ["Portland", "Lewiston", "Bangor"], "Maryland": ["Baltimore", "Columbia", "Germantown", "Silver Spring"], "Massachusetts": ["Boston", "Worcester", "Springfield", "Cambridge", "Lowell"], "Michigan": ["Detroit", "Grand Rapids", "Warren", "Sterling Heights", "Ann Arbor"], "Minnesota": ["Minneapolis", "St. Paul", "Rochester", "Duluth"], "Mississippi": ["Jackson", "Gulfport", "Southaven"], "Missouri": ["Kansas City", "St. Louis", "Springfield", "Columbia"], "Montana": ["Billings", "Missoula", "Great Falls"], "Nebraska": ["Omaha", "Lincoln", "Bellevue"], "Nevada": ["Las Vegas", "Henderson", "Reno", "North Las Vegas"], "New Hampshire": ["Manchester", "Nashua", "Concord"], "New Jersey": ["Newark", "Jersey City", "Paterson", "Elizabeth", "Edison"], "New Mexico": ["Albuquerque", "Las Cruces", "Rio Rancho", "Santa Fe"], "New York": ["New York City", "Buffalo", "Rochester", "Yonkers", "Syracuse", "Albany"], "North Carolina": ["Charlotte", "Raleigh", "Greensboro", "Durham", "Winston-Salem"], "North Dakota": ["Fargo", "Bismarck", "Grand Forks"], "Ohio": ["Columbus", "Cleveland", "Cincinnati", "Toledo", "Akron"], "Oklahoma": ["Oklahoma City", "Tulsa", "Norman"], "Oregon": ["Portland", "Salem", "Eugene", "Gresham"], "Pennsylvania": ["Philadelphia", "Pittsburgh", "Allentown", "Erie", "Reading"], "Rhode Island": ["Providence", "Warwick", "Cranston"], "South Carolina": ["Charleston", "Columbia", "North Charleston", "Mount Pleasant"], "South Dakota": ["Sioux Falls", "Rapid City", "Aberdeen"], "Tennessee": ["Nashville", "Memphis", "Knoxville", "Chattanooga"], "Texas": ["Houston", "San Antonio", "Dallas", "Austin", "Fort Worth", "El Paso", "Arlington", "Corpus Christi"], "Utah": ["Salt Lake City", "West Valley City", "Provo", "West Jordan"], "Vermont": ["Burlington", "South Burlington", "Rutland"], "Virginia": ["Virginia Beach", "Norfolk", "Chesapeake", "Richmond", "Newport News"], "Washington": ["Seattle", "Spokane", "Tacoma", "Vancouver", "Bellevue"], "West Virginia": ["Charleston", "Huntington", "Morgantown"], "Wisconsin": ["Milwaukee", "Madison", "Green Bay", "Kenosha"], "Wyoming": ["Cheyenne", "Casper", "Laramie"] }; // Submit vendor application - UPDATED const submitApplicationMutation = useMutation({ mutationFn: async () => { // Generate vendor number const vendorNumber = `VN-${Math.floor(1000 + Math.random() * 9000)}`; // Build coverage regions from selected cities const coverageRegionsList = []; Object.keys(formData.selected_cities).forEach(state => { formData.selected_cities[state].forEach(city => { coverageRegionsList.push(`${city}, ${state}`); }); }); // Create vendor record const vendor = await base44.entities.Vendor.create({ vendor_number: vendorNumber, legal_name: formData.legal_name, doing_business_as: formData.dba, tax_id: formData.tax_id, business_type: formData.business_type, primary_contact_name: formData.primary_contact_name, primary_contact_email: formData.primary_contact_email, primary_contact_phone: formData.primary_contact_phone, // Updated logic for billing_address and service_address based on new flow service_address: formData.service_address, billing_address: formData.same_as_billing ? formData.service_address : formData.billing_address, coverage_regions: coverageRegionsList, w9_document: formData.w9_url, coi_document: formData.coi_url, insurance_certificate: formData.coi_url, approval_status: "pending", is_active: false, // Updated contract note to reflect review not upload notes: `Total Employees: ${formData.total_employees}, Software: ${formData.software_name || formData.software_type}, SOS: ${formData.sos_url ? 'Verified' : 'Pending'}, Contract: ${formData.contract_acknowledged ? 'Acknowledged' : 'Not Acknowledged'}. Contract Review Notes: ${formData.contract_review_notes}. NDA Signed: ${formData.nda_acknowledged ? 'Yes' : 'No'}` }); // Create rate proposals with location-specific rates const vendorFee = invite?.vendor_admin_fee || 12; await Promise.all( formData.rate_proposals .filter(rate => rate.is_active) .map(rate => base44.entities.VendorRate.create({ vendor_id: vendor.id, vendor_name: formData.legal_name, category: rate.category, role_name: rate.role_name, employee_wage: rate.employee_wage, markup_percentage: rate.markup_percentage, vendor_fee_percentage: vendorFee, client_rate: rate.client_rate, is_active: true, ai_analysis: rate.ai_analysis, is_custom: rate.is_custom, notes: rate.location_rates ? JSON.stringify(rate.location_rates) : null }) ) ); // Update invite status if exists if (invite) { await base44.entities.VendorInvite.update(invite.id, { invite_status: "completed", vendor_id: vendor.id, invite_accepted_date: new Date().toISOString() }); } // Send confirmation email await base44.integrations.Core.SendEmail({ from_name: "KROW Platform", to: formData.primary_contact_email, subject: "Vendor Application Received - Under Review", body: `

Application Received Successfully!

Dear ${formData.primary_contact_name},

Thank you for completing your vendor application with KROW.

Application Summary:

Vendor Number: ${vendorNumber}

Company: ${formData.legal_name}

Status: Under Review

Our procurement team will review your application and get back to you within 2-3 business days.

Best regards,
KROW Team

` }); return vendor; }, onSuccess: (vendor) => { toast({ title: "Application Submitted!", description: "You'll hear from us within 2-3 business days", }); navigate(createPageUrl("VendorManagement")); }, onError: (error) => { toast({ title: "Submission Failed", description: error.message, variant: "destructive" }); } }); const handleNext = () => { // Step 0: Welcome (no validation, just go to next step) if (currentStep === 0) { setCurrentStep(1); return; } // Step 1: NDA if (currentStep === 1) { if (!formData.nda_acknowledged) { toast({ title: "NDA Required", description: "You must sign and accept the NDA before proceeding", variant: "destructive" }); return; } } // Step 2: Foodbuy Contract if (currentStep === 2) { if (!formData.contract_acknowledged || !formData.contract_va_fee_acknowledged) { toast({ title: "Contract Review Required", description: "Please acknowledge all terms to proceed", variant: "destructive" }); return; } } // Step 3: Business Identity if (currentStep === 3) { if (!formData.legal_name || !formData.tax_id || !formData.business_type || !formData.primary_contact_name || !formData.primary_contact_email || !formData.service_address || !formData.total_employees || (formData.has_software === "yes" && (!formData.software_type || !formData.software_name))) { toast({ title: "Missing Information", description: "Please fill in all required fields", variant: "destructive" }); return; } } // Step 4: Documents if (currentStep === 4) { const isSosValidated = (docValidation.sos?.autoVerified && docValidation.sos.isRegistered && (docValidation.sos.registrationStatus === 'Active' || docValidation.sos.registrationStatus === 'Good Standing')) || (docValidation.sos && docValidation.sos.isValid); if (!formData.w9_url || !formData.coi_url || !isSosValidated) { toast({ title: "Missing Documents", description: "Please upload W-9, COI, and verify/upload Secretary of State certificate", variant: "destructive" }); return; } // NEW: Validate compliance attestations if (!formData.background_check_attestation || !formData.i9_compliance_attestation || !formData.legal_compliance_attestation) { toast({ title: "Compliance Attestation Required", description: "Please confirm all compliance attestations to proceed", variant: "destructive" }); return; } } // Step 5: Service Coverage if (currentStep === 5) { const totalCities = Object.values(formData.selected_cities).reduce((sum, cities) => sum + cities.length, 0); if (totalCities === 0) { toast({ title: "No Coverage Selected", description: "Please select at least one city/location you can service", variant: "destructive" }); return; } } // Step 6: Rate Proposals if (currentStep === 6) { const activeRates = formData.rate_proposals.filter(rate => rate.is_active); if (activeRates.length === 0) { toast({ title: "No Active Rate Proposals", description: "Please activate at least one rate proposal.", variant: "destructive" }); return; } const hasInvalidRates = activeRates.some(rate => !rate.role_name || !rate.category || rate.employee_wage <= 0 || rate.markup_percentage <= 0 || rate.client_rate <= 0 ); if (hasInvalidRates) { toast({ title: "Incomplete Rate Proposals", description: "Please ensure all active rate proposals have valid employee wages and markups.", variant: "destructive" }); return; } } if (currentStep < steps.length - 1) { setCurrentStep(prev => prev + 1); } }; const handleBack = () => { if (currentStep > 0) { setCurrentStep(prev => prev - 1); } }; const handleSubmit = () => { submitApplicationMutation.mutate(); }; // Update handleSignNDA to handle signature data from DocumentViewer const handleSignNDA = (acknowledgmentData) => { const now = new Date(); setFormData(prev => ({ ...prev, nda_acknowledged: true, nda_signed_by: acknowledgmentData.signerName || invite?.primary_contact_name || prev.primary_contact_name || "Vendor", nda_signature_date: now.toLocaleDateString(), nda_signature_time: now.toLocaleTimeString(), nda_signature_image: acknowledgmentData.signature || "" // Store the signature image })); toast({ title: "✅ NDA Signed", description: `Signed on ${now.toLocaleString()}`, }); }; return (
{/* STEP 0: Welcome Screen */} {currentStep === 0 && (
{/* Logo - KROW LOGO */}
KROW Logo
{/* Welcome Message */}

Welcome to KROW

The Workforce Control Tower that connects you to the most trusted procurement and operator network.

Let's begin your onboarding journey, it'll take just a few minutes to get your company fully connected.

{/* Progress indicator */}
0% Complete

Step 1 of 8: NDA & Trust Agreement

{/* Start Button */} {invite && ( ✅ Invited by {invite.invited_by} )}
)} {/* Steps 1-7: Show header and progress only if not on welcome screen */} {currentStep > 0 && ( <> {/* Header */}
KROW Logo

Smart Vendor Onboarding

Real-time market analysis • Predictive scoring • Instant validation

{invite && ( ✅ Invited by {invite.invited_by} )}
{/* Progress Bar */}

Step {currentStep} of {steps.length - 1}

{Math.round(progressPercentage)}% Complete

{/* Step indicators */}
{steps.slice(1).map((step) => { const Icon = step.icon; const isActive = currentStep === step.number; const isComplete = currentStep > step.number; return ( ); })}
)} {/* STEP 1: NDA & Trust Agreement */} {currentStep === 1 && (
NDA & Trust Agreement

Sign and accept - Date and time will be recorded

{/* NDA Document Viewer */} {/* Warning if not signed */} {!formData.nda_acknowledged && (

You must review and sign the NDA to proceed with onboarding

)} {/* Success message if signed - NOW WITH SIGNATURE IMAGE */} {formData.nda_acknowledged && (

✅ NDA Signed Successfully

{/* Signature and Details Card */}
{/* Signer Name */}

Signed by:

{formData.nda_signed_by}

{/* Signature Image */} {formData.nda_signature_image && (

Digital Signature:

Signature
)} {/* Date and Time */}
Date: {formData.nda_signature_date}
Time: {formData.nda_signature_time}

✓ You may now proceed to the next step

)}
)} {/* STEP 2: Foodbuy Contract Review (was Step 1) */} {currentStep === 2 && (
Foodbuy Contract Review

Please review the terms before proceeding

{/* Contract Document Viewer */} { setFormData(prev => ({ ...prev, contract_review_notes: acknowledgmentData.notes || prev.contract_review_notes, contract_review_time: acknowledgmentData.reviewTime || prev.contract_review_time, contract_acknowledged: true })); }} initialNotes={formData.contract_review_notes} isAcknowledged={formData.contract_acknowledged} timeSpent={formData.contract_review_time} /> {/* Performance Requirements & VA Fee Structure Breakdown */}

Performance Requirements & Service Standards

{/* Fill Rate & KPIs */}

Key Performance Indicators (KPIs)

Fill Rate Target ≥ 95%
On-Time Arrival ≥ 98%
Client Satisfaction (CSAT) ≥ 4.5/5.0
Cancellation Rate ≤ 3%
No-Show Rate ≤ 1%
Response Time ≤ 2 hours
{/* Compliance & Attestations */}

Compliance & Attestation Requirements

Background Check Compliance

All employees must have valid background checks per federal and state requirements

I-9 Employment Eligibility

Maintain complete and valid I-9 forms for all employees with proper documentation

Insurance & Liability Coverage

General liability insurance minimum $1M, Workers' Compensation as required by law

Legal & Regulatory Compliance

Comply with all federal, state, and local employment laws including wage & hour, safety, and anti-discrimination

Tax & Payroll Compliance

Proper W-9 on file, accurate tax withholding, and timely payment of all employment taxes

{/* VA Fee Structure */}

Vendor Fee Structure

Vendor Fee {invite?.vendor_admin_fee || 12}%

Cost of doing business with Foodbuy as your partner

Fee Calculation Example
Employee Wage $18.50/hr
Your Markup (20%) +$3.70/hr
Bill Rate (to client) $22.20/hr
Vendor Fee ({invite?.vendor_admin_fee || 12}%) -${((22.20 * (invite?.vendor_admin_fee || 12)) / 100).toFixed(2)}/hr
You Receive ${(22.20 - (22.20 * (invite?.vendor_admin_fee || 12) / 100)).toFixed(2)}/hr

💡 What the Vendor Fee Covers: Platform access, procurement management, client relationships, compliance oversight, payment processing, insurance coordination, and KROW system support.

{/* Acknowledgment Checkbox */}
setFormData(prev => ({ ...prev, contract_va_fee_acknowledged: checked }))} className="mt-1 data-[state=checked]:bg-[#0A39DF] data-[state=checked]:border-[#0A39DF]" />

Including the {invite?.vendor_admin_fee || 12}% vendor fee and service standards outlined above

{(!formData.contract_acknowledged || !formData.contract_va_fee_acknowledged) && (

You must review and acknowledge the contract terms to proceed with onboarding

)}
)} {/* STEP 3: Business Identity (was Step 2) */} {currentStep === 3 && (
Business Identity

Let's set your stage

{/* Legal Business Name */}
setFormData(prev => ({ ...prev, legal_name: e.target.value }))} placeholder="ABC Staffing Solutions LLC" className="mt-2" />
setFormData(prev => ({ ...prev, dba: e.target.value }))} placeholder="ABC Staffing" className="mt-2" />
{/* Tax ID & Business Type */}
setFormData(prev => ({ ...prev, tax_id: e.target.value }))} placeholder="XX-XXXXXXX" className="mt-2" />
{/* Contact Information */}
setFormData(prev => ({ ...prev, primary_contact_name: e.target.value }))} placeholder="John Smith" className="mt-2" />
setFormData(prev => ({ ...prev, primary_contact_email: e.target.value }))} placeholder="john@abcstaffing.com" className="mt-2" />
setFormData(prev => ({ ...prev, primary_contact_phone: e.target.value }))} placeholder="(555) 123-4567" className="mt-2" />
{/* Google Address Autocomplete - SERVICE ADDRESS FIRST */}
setFormData(prev => ({ ...prev, service_address: value }))} placeholder="123 Main Street, Suite 100, San Francisco, CA 94105" label="Service Address" required />
{/* Same as service checkbox */}
setFormData(prev => ({ ...prev, same_as_billing: checked }))} className="data-[state=checked]:bg-[#0A39DF] data-[state=checked]:border-[#0A39DF]" />
{/* Billing Address - only show if checkbox is unchecked */} {!formData.same_as_billing && (
setFormData(prev => ({ ...prev, billing_address: value }))} placeholder="456 Office Blvd, Oakland, CA 94612" label="Billing Address" />
)} {/* NEW FIELDS: Staff Count & Software */}

Operations Information

{/* Total Employees */}
setFormData(prev => ({ ...prev, total_employees: e.target.value }))} placeholder="e.g., 250" className="mt-2" />

Total active workforce members

{/* Has Software */}
{/* Software Details */} {formData.has_software === "yes" && (
setFormData(prev => ({ ...prev, software_name: e.target.value }))} placeholder={formData.software_type === "internal" ? "Internal System" : "e.g., Instawork, Qwick"} className="mt-2" />
)}
)} {/* STEP 4: Documents & Validation (was Step 3) */} {currentStep === 4 && (
Documents & Validation

Compliance essentials - AI powered verification

{/* W-9 Upload */}

W-9 Tax Form *

Federal tax classification document

{docValidation.w9 && ( {docValidation.w9.isValid ? "✅ Validated" : "ℹ Review"} )}
handleFileUpload(file, 'w9')} accept=".pdf,.jpg,.jpeg,.png" uploading={uploadingDoc === 'w9' || validatingDoc === 'w9'} uploaded={!!formData.w9_url} uploadedFileName={formData.w9_file?.name} disabled={uploadingDoc === 'w9' || validatingDoc === 'w9'} /> {docValidation.w9 && (

Validation Results:

{docValidation.w9.businessName && (

• Business: {docValidation.w9.businessName}

)} {docValidation.w9.issues && docValidation.w9.issues.length > 0 && (
{docValidation.w9.issues.map((issue, idx) => (

ℹ {issue}

))}
)} {docValidation.w9.notes && (

{docValidation.w9.notes}

)}
)}
{/* COI Upload */}

Certificate of Insurance (COI) *

General liability insurance certificate

{docValidation.coi && ( {docValidation.coi.isValid ? "✅ Validated" : "ℹ Review"} )}
handleFileUpload(file, 'coi')} accept=".pdf,.jpg,.jpeg,.png" uploading={uploadingDoc === 'coi' || validatingDoc === 'coi'} uploaded={!!formData.coi_url} uploadedFileName={formData.coi_file?.name} disabled={uploadingDoc === 'coi' || validatingDoc === 'coi'} /> {docValidation.coi && (

Validation Results:

{docValidation.coi.expiryDate && (

• Expires: {docValidation.coi.expiryDate}

)} {docValidation.coi.issues && docValidation.coi.issues.length > 0 && (
{docValidation.coi.issues.map((issue, idx) => (

ℹ {issue}

))}
)} {docValidation.coi.notes && (

{docValidation.coi.notes}

)}
)}
{/* Secretary of State Certificate */}

Secretary of State Certificate *

Business registration verification - Required

{docValidation.sos && ( {(docValidation.sos.isValid || (docValidation.sos.isRegistered && docValidation.sos.autoVerified)) ? "✅ Validated" : "ℹ Review"} )}
{/* Auto-Check Button - NOW REQUIRED */}

🔍 Automatic Verification - Required

Click "Auto-Check" to verify your business registration with the Secretary of State. This is mandatory for approval.

{/* Show auto-verification results */} {docValidation.sos?.autoVerified && (
{docValidation.sos.isRegistered ? ( ) : ( )}

{docValidation.sos.isRegistered ? "✅ Automatically Verified" : "ℹ Verification Results"}

{docValidation.sos.businessName && (
Business Name: {docValidation.sos.businessName}
)} {docValidation.sos.registrationState && (
State: {docValidation.sos.registrationState}
)} {docValidation.sos.registrationStatus && (
Status: {docValidation.sos.registrationStatus}
)} {docValidation.sos.entityType && (
EntityType: {docValidation.sos.entityType}
)} {docValidation.sos.registrationDate && (
Registered: {docValidation.sos.registrationDate}
)}
{docValidation.sos.issues && docValidation.sos.issues.length > 0 && (

Issues Found:

{docValidation.sos.issues.map((issue, idx) => (

ℹ {issue}

))}
)} {docValidation.sos.notes && (

{docValidation.sos.notes}

)}
)} {/* Manual Upload Option with Drag & Drop */}

Or upload certificate manually for verification:

handleFileUpload(file, 'sos')} accept=".pdf,.jpg,.jpeg,.png" uploading={uploadingDoc === 'sos' && !docValidation.sos?.autoVerified} uploaded={!!formData.sos_url && !docValidation.sos?.autoVerified} uploadedFileName={formData.sos_file?.name} disabled={uploadingDoc === 'sos' || validatingDoc === 'sos'} /> {/* Display manual validation results if not auto-verified, or if auto-verified failed/was skipped and manual was used */} {docValidation.sos && !docValidation.sos.autoVerified && (

Document Validation Results:

{docValidation.sos.businessName && (

• Business: {docValidation.sos.businessName}

)} {docValidation.sos.registrationState && (

• State: {docValidation.sos.registrationState}

)} {docValidation.sos.expiryDate && (

• Current through: {docValidation.sos.expiryDate}

)} {docValidation.sos.issues && docValidation.sos.issues.length > 0 && (
{docValidation.sos.issues.map((issue, idx) => (

ℹ {issue}

))}
)} {docValidation.sos.notes && (

{docValidation.sos.notes}

)}
)}

REQUIRED: This certificate verifies your business is actively registered with your state. You must either use Auto-Check or upload a valid certificate to proceed.

{/* NEW: Compliance Attestations Section */}

Compliance Attestations

Verify your compliance with employment and safety regulations

{/* Background Check Attestation */}
setFormData(prev => ({ ...prev, background_check_attestation: checked }))} className="mt-1 data-[state=checked]:bg-[#0A39DF] data-[state=checked]:border-[#0A39DF]" />

I attest that my company conducts background checks on all employees in accordance with federal, state, and local laws. We maintain proper documentation and follow all FCRA (Fair Credit Reporting Act) requirements.

{/* I-9 Compliance Attestation */}
setFormData(prev => ({ ...prev, i9_compliance_attestation: checked }))} className="mt-1 data-[state=checked]:bg-[#0A39DF] data-[state=checked]:border-[#0A39DF]" />

I attest that my company maintains complete and valid I-9 forms for all employees as required by U.S. immigration law. All employees are verified for employment eligibility and documentation is kept on file for the required retention period.

{/* Legal Compliance Attestation */}
setFormData(prev => ({ ...prev, legal_compliance_attestation: checked }))} className="mt-1 data-[state=checked]:bg-[#0A39DF] data-[state=checked]:border-[#0A39DF]" />

I attest that my company complies with all applicable federal, state, and local employment laws including but not limited to: wage and hour laws, workers' compensation, unemployment insurance, anti-discrimination laws, OSHA safety standards, and all licensing requirements for our industry and geographic locations.

{/* Warning Message */} {(!formData.background_check_attestation || !formData.i9_compliance_attestation || !formData.legal_compliance_attestation) && (

Required Attestations

All compliance attestations are mandatory. By checking these boxes, you affirm that your company meets all legal requirements and understands that providing false information may result in immediate termination of vendor partnership and potential legal action.

)} {/* Success Message */} {formData.background_check_attestation && formData.i9_compliance_attestation && formData.legal_compliance_attestation && (

✓ All compliance attestations completed. Your commitment to legal compliance is appreciated.

)}
)} {/* STEP 5: Service Coverage (was Step 4) */} {currentStep === 5 && (
Service Coverage

Select all cities and regions where you can provide services

{Object.values(formData.selected_cities).reduce((sum, cities) => sum + cities.length, 0)} Cities Selected
{/* Search and Quick Actions */}
{ // Filtering logic would be implemented here, e.g., storing search term in state // and then filtering `Object.entries(usLocationData)` below. // For now, it's a visual placeholder as per original outline intent. }} />
{/* Selected Regions Summary */} {Object.values(formData.selected_cities).reduce((sum, cities) => sum + cities.length, 0) > 0 && (

Selected Service Areas

{Object.entries(formData.selected_cities).map(([state, cities]) => { if (cities.length === 0) return null; // Don't show states with no selected cities return (
{state} {cities.map(city => ( ))}
); })}
)} {/* State and City Selection */}
{Object.entries(usLocationData).map(([state, cities]) => (

{state}

{cities.map(city => { const isSelected = formData.selected_cities[state]?.includes(city); return ( ); })}
))}
{Object.values(formData.selected_cities).reduce((sum, cities) => sum + cities.length, 0) === 0 && (

No cities selected yet

Select the cities where you can provide staffing services

)}
)} {/* STEP 6: Rate Proposals (was Step 5) */} {currentStep === 6 && (
Service Matrix Builder

Tell us where you shine - AI-powered rate analysis

Vendor Admin Fee (VA)

{invite?.vendor_admin_fee || 12}%

Set by Procurement

🧠 AI runs in background:

Benchmarks each entry against KROW's dynamic rate matrix, historic client spend, and market average for your region and role.

{/* Minimum Wage Detected */} {formData.service_address && ( // Changed to service_address

Local Minimum Wage Detected: ${getMinimumWageFromAddress(formData.service_address)}/hr

Based on your business location. All payrates are pre-populated at or above this minimum. You can adjust them as needed.

Auto-Detected
)} {/* Global Controls */}

Quick Actions:

{/* Select All / Deselect All */}
{/* Apply Markup to All */}
%
{/* Enhanced Rate Cards with Location Support */}
{(() => { // Get minimum wage based on business location (service_address) const localMinWage = getMinimumWageFromAddress(formData.service_address); // Pre-defined roles with wages based on local minimum wage const defaultRoles = [ { category: "Bartending", role: "Bartender", wageMultiplier: 1.2 }, { category: "Kitchen and Culinary", role: "Cook", wageMultiplier: 1.2 }, { category: "Kitchen and Culinary", role: "Line Cook", wageMultiplier: 1.2 }, { category: "Kitchen and Culinary", role: "Sous Chef", wageMultiplier: 1.6 }, { category: "Kitchen and Culinary", role: "Executive Chef", wageMultiplier: 2.3 }, { category: "Kitchen and Culinary", role: "Prep Cook", wageMultiplier: 1.0 }, { category: "Concessions", role: "Concessions Attendant", wageMultiplier: 1.0 }, { category: "Concessions", role: "Cashier", wageMultiplier: 1.0 }, { category: "Facilities", role: "Janitor", wageMultiplier: 1.05 }, { category: "Facilities", role: "Maintenance Technician", wageMultiplier: 1.4 }, { category: "Bartending", role: "Bar Back", wageMultiplier: 1.0 }, { category: "Security", role: "Security Guard", wageMultiplier: 1.3 }, { category: "Event Staff", role: "Event Server", wageMultiplier: 1.05 }, { category: "Event Staff", role: "Event Coordinator", wageMultiplier: 1.6 }, { category: "Management", role: "General Manager", wageMultiplier: 2.6 }, { category: "Management", role: "Assistant Manager", wageMultiplier: 1.8 }, ]; // Initialize rate proposals if empty if (formData.rate_proposals.length === 0) { const initialRates = defaultRoles.map(r => { const calculatedWage = parseFloat((localMinWage * r.wageMultiplier).toFixed(2)); const vendorFee = invite?.vendor_admin_fee || 12; return { category: r.category, role_name: r.role, employee_wage: calculatedWage, markup_percentage: 20, vendor_fee_percentage: vendorFee, client_rate: parseFloat((calculatedWage * 1.2 * (1 + (vendorFee / 100))).toFixed(2)), is_active: true, ai_analysis: null, is_custom: false, location_rates: {} // Initialize empty object for location-specific rates }; }); // Using a functional update to ensure we get the latest state setFormData(prev => ({ ...prev, rate_proposals: initialRates })); } return null; // This IIFE does not render anything directly })()} {formData.rate_proposals.map((rate, idx) => { const vendorFee = invite?.vendor_admin_fee || 12; const selectedLocations = Object.entries(formData.selected_cities).flatMap(([state, cities]) => cities.map(city => `${city}, ${state}`) ); // Determine status based on client rate vs market average (simulated) const marketAverage = rate.employee_wage * 1.35; let status = "competitive"; let statusIcon = "✓"; let statusText = "Good Deal"; let statusClass = "bg-green-100 text-green-700"; if (rate.client_rate > marketAverage * 1.15) { status = "risk"; statusIcon = "!"; statusText = "Risk Zone"; statusClass = "bg-red-100 text-red-700"; } else if (rate.client_rate > marketAverage * 1.05) { status = "market"; statusIcon = "~"; statusText = "At Market"; statusClass = "bg-blue-100 text-blue-700"; } return (
{/* Toggle */}
{/* Role Info */}
{/* Position */}

Position

{rate.is_custom ? ( { const newRates = [...formData.rate_proposals]; newRates[idx].role_name = e.target.value; setFormData(prev => ({ ...prev, rate_proposals: newRates })); }} className="h-8 text-sm" disabled={!rate.is_active} /> ) : (

{rate.role_name}

)}

{rate.category}

{/* Payrate */}

Payrate

$ { const newRates = [...formData.rate_proposals]; const wage = parseFloat(e.target.value) || 0; newRates[idx].employee_wage = wage; newRates[idx].client_rate = parseFloat((wage * (1 + newRates[idx].markup_percentage / 100) * (1 + vendorFee / 100)).toFixed(2)); // Also update client rates in location_rates if (newRates[idx].location_rates) { newRates[idx].location_rates = Object.fromEntries( Object.entries(newRates[idx].location_rates).map(([loc, lr]) => [ loc, { ...lr, employee_wage: wage, // Update wage for location-specific rate client_rate: parseFloat((wage * (1 + lr.markup_percentage / 100) * (1 + vendorFee / 100)).toFixed(2)) } ]) ); } setFormData(prev => ({ ...prev, rate_proposals: newRates })); }} className="h-8 text-sm pl-5 font-semibold" disabled={!rate.is_active} />
{/* Markup */}

Mark up

{ const newRates = [...formData.rate_proposals]; const markup = parseFloat(e.target.value) || 0; newRates[idx].markup_percentage = markup; newRates[idx].client_rate = parseFloat((newRates[idx].employee_wage * (1 + markup / 100) * (1 + vendorFee / 100)).toFixed(2)); // Also update client rates in location_rates if (newRates[idx].location_rates) { newRates[idx].location_rates = Object.fromEntries( Object.entries(newRates[idx].location_rates).map(([loc, lr]) => [ loc, { ...lr, markup_percentage: markup, // Update markup for location-specific rate client_rate: parseFloat((lr.employee_wage * (1 + markup / 100) * (1 + vendorFee / 100)).toFixed(2)) } ]) ); } setFormData(prev => ({ ...prev, rate_proposals: newRates })); }} className="h-8 text-sm font-semibold text-blue-600" disabled={!rate.is_active} /> %
{/* Vendor Fee % (Read-only) */}

Vendor Fee %

{vendorFee}%
{/* Proposed Bill Rate */}

Proposed Bill Rate

${rate.client_rate}
{/* Status */}

Status

{statusIcon} {statusText}
{/* Actions */} {rate.is_custom && ( )}
{/* NEW: Location-Specific Rates Section */} {rate.is_active && selectedLocations.length > 0 && ( // Show if active and at least one location is selected
Location-Specific Rates
{selectedLocations.length} Locations Available
{selectedLocations.map(location => { // Default to the base rate if no specific location rate is set const locationRate = rate.location_rates?.[location] || { employee_wage: rate.employee_wage, markup_percentage: rate.markup_percentage, client_rate: rate.client_rate }; return (

{location}

$ { const newWage = parseFloat(e.target.value) || 0; const newClientRate = parseFloat((newWage * (1 + locationRate.markup_percentage / 100) * (1 + vendorFee / 100)).toFixed(2)); setFormData(prev => { const newRates = [...prev.rate_proposals]; if (!newRates[idx].location_rates) newRates[idx].location_rates = {}; newRates[idx].location_rates[location] = { ...locationRate, employee_wage: newWage, client_rate: newClientRate }; return { ...prev, rate_proposals: newRates }; }); }} className="h-7 text-xs pl-4" />
{ const newMarkup = parseFloat(e.target.value) || 0; const newClientRate = parseFloat((locationRate.employee_wage * (1 + newMarkup / 100) * (1 + vendorFee / 100)).toFixed(2)); setFormData(prev => { const newRates = [...prev.rate_proposals]; if (!newRates[idx].location_rates) newRates[idx].location_rates = {}; newRates[idx].location_rates[location] = { ...locationRate, markup_percentage: newMarkup, client_rate: newClientRate }; return { ...prev, rate_proposals: newRates }; }); }} className="h-7 text-xs" />
${locationRate.client_rate}
); })}
)} {/* Expanded Details - Visual Breakdown */} {rate.is_active && (
{/* Cost Breakdown Bar */}

Cost Breakdown

${rate.employee_wage}
{rate.markup_percentage}%
{vendorFee}%
Payrate: ${rate.employee_wage}/hr Markup: {rate.markup_percentage}% (+${(rate.employee_wage * rate.markup_percentage / 100).toFixed(2)}) VA: {vendorFee}% (+${(rate.employee_wage * (1 + rate.markup_percentage / 100) * vendorFee / 100).toFixed(2)})
{/* AI Insights */}

💡 AI Insights

Market Avg: ${marketAverage.toFixed(2)}/hr
Your Rate: ${rate.client_rate}/hr
Difference: {rate.client_rate < marketAverage ? '-' : '+'}${Math.abs(rate.client_rate - marketAverage).toFixed(2)}
Fill Rate: {status === 'competitive' ? '95%' : status === 'market' ? '75%' : '45%'}/yr
{/* Status Message */} {status === 'competitive' && (
Good Deal: Your rate is {((1 - rate.client_rate / marketAverage) * 100).toFixed(0)}% below market average. Highly competitive with predicted 95% fill rate.
)} {status === 'market' && (
~ At Market: Your rate aligns with market average. Competitive with predicted 75% fill rate.
)} {status === 'risk' && (
! Risk Zone: Your rate is {(((rate.client_rate / marketAverage) - 1) * 100).toFixed(0)}% above market average. This may reduce competitiveness with predicted 45% fill rate. Consider lowering markup.
)}
)}
); })}
{/* Summary Stats */}

{formData.rate_proposals.filter(r => r.is_active && r.client_rate < (r.employee_wage * 1.35 * 1.05)).length}

✓ Good Deals

{formData.rate_proposals.filter(r => r.is_active && r.client_rate >= (r.employee_wage * 1.35 * 1.05) && r.client_rate <= (r.employee_wage * 1.35 * 1.15)).length}

~ At Market

{formData.rate_proposals.filter(r => r.is_active && r.client_rate > (r.employee_wage * 1.35 * 1.15)).length}

! Risk Zone

{formData.rate_proposals.filter(r => r.is_active).length}

Active Roles

)} {/* STEP 7: AI Intelligence (was Step 6) */} {currentStep === 7 && (
AI Intelligence

Market insights & recommendations

{!aiInsights && ( )}
{!aiInsights ? (

Ready to analyze your application

Get AI-powered insights on your competitive positioning

) : (
{/* Overall Score */}

Overall Assessment

{aiInsights.overall_score}/100

{aiInsights.competitive_position}

{/* Strengths */} {aiInsights.strengths && aiInsights.strengths.length > 0 && (

Strengths

{aiInsights.strengths.map((strength, idx) => (

✓ {strength}

))}
)} {/* Recommendations */} {aiInsights.recommendations && aiInsights.recommendations.length > 0 && (

Recommendations

{aiInsights.recommendations.map((rec, idx) => (

💡 {rec}

))}
)} {/* Analysis Details */}
Market Alignment

{aiInsights.market_alignment}

Pricing Analysis

{aiInsights.pricing_analysis}

)}
)} {/* Navigation Buttons */} {currentStep > 0 && (
{currentStep < steps.length - 1 ? ( ) : ( )}
)}
); }