"use client"; import { useCallback, useState } from "react"; import type { Priority1DemoInput } from "@/workers/rpa/priority1/demo-input"; import { DEFAULT_PRIORITY1_DEMO } from "@/workers/rpa/priority1/demo-input"; import type { ExpeditedTrailerType, FtlAdditionalService, FtlTrailerType, Priority1ShipmentType, } from "@/workers/rpa/priority1/shipment-types"; import { P1_COMMON_UI, P1_DELIVERY_ACCESSORIALS, P1_EXP_TRAILERS, P1_EXPEDITED_UI, P1_FREQUENCY_OPTIONS, P1_FREIGHT_CLASS_OPTIONS, P1_FTL_ADDITIONAL, P1_FTL_LIFTGATE_SERVICE, P1_FTL_TRAILERS, P1_FTL_UI, P1_LTL_UI, P1_LOCATION_OPTIONS, P1_OPEN_DECK_OPTIONS, P1_PACKAGING_OPTIONS, P1_PICKUP_ACCESSORIALS, P1_SHIPMENT_CARDS, P1_SPECIAL_HANDLING, P1_STEP2_HEADING, P1_STEP2_SUBTITLE, } from "@/lib/priority1/ui-labels"; import { FeatheryCard, FeatheryCardGrid, P1FieldLabel, P1InstantQuotesButton, P1Step2Progress, P1StickyActionBar, P1WeightField, ShipmentTypeCard, } from "@/components/priority1/feathery-card"; import { P1DateField } from "@/components/priority1/p1-date-field"; import { P1PhoneField } from "@/components/priority1/p1-phone-field"; import { findPhoneCountry } from "@/lib/priority1/phone-countries"; import { pickupDateValidationMessage } from "@/lib/priority1/pickup-date"; import { SelectField } from "@/components/ui/select-field"; export interface Priority1SimulatorProps { disabled?: boolean; loading?: boolean; onSubmit: (input: Priority1DemoInput) => void; } function toggleInList(list: string[], value: string): string[] { return list.includes(value) ? list.filter((v) => v !== value) : [...list, value]; } function toggleService( list: FtlAdditionalService[], svc: FtlAdditionalService, ): FtlAdditionalService[] { return list.includes(svc) ? list.filter((s) => s !== svc) : [...list, svc]; } function P1FeatherySelect({ id, label, required, value, disabled, options, onChange, }: { id: string; label: string; required?: boolean; value: string; disabled?: boolean; options: Array<{ value: string; label: string }>; onChange: (v: string) => void; }) { return (
{label}
); } function P1AccessorialGrid({ legend, options, selected, disabled, onToggle, }: { legend: string; options: Array<{ value: string; label: string }>; selected: string[]; disabled?: boolean; onToggle: (value: string) => void; }) { return (
{legend}
{options.map((opt) => ( ))}
); } function P1TextInput({ id, label, required, value, disabled, error, type = "text", onChange, }: { id: string; label: string; required?: boolean; value: string; disabled?: boolean; error?: string; type?: string; onChange: (v: string) => void; }) { return (
{label} onChange(e.target.value)} className={`h-11 w-full rounded-sm border bg-neutral-100 px-3 text-sm focus:border-neutral-600 focus:outline-none disabled:opacity-60 ${ error ? "border-red-500" : "border-neutral-400" }`} /> {error ?

{error}

: null}
); } /** 仿 Priority1 两步动态表单(与 form-logic-map 分支一致) */ export function Priority1Simulator({ disabled, loading, onSubmit, }: Priority1SimulatorProps) { const [step, setStep] = useState<1 | 2>(1); const [form, setForm] = useState({ ...DEFAULT_PRIORITY1_DEMO, }); const [errors, setErrors] = useState>({}); const patch = useCallback((partial: Partial) => { setForm((prev) => ({ ...prev, ...partial })); }, []); const validateStep1 = (): boolean => { const next: Record = {}; if (!/^\d{5}$/.test(form.originZip.trim())) { next.originZip = "请输入 5 位起运邮编"; } if (!/^\d{5}$/.test(form.destinationZip.trim())) { next.destinationZip = "请输入 5 位目的邮编"; } if (form.originZip === form.destinationZip) { next.destinationZip = "起运与目的邮编不能相同"; } if (!/^\d{2}\/\d{2}\/\d{4}$/.test(form.pickupDate.trim())) { next.pickupDate = "请选择提货日"; } else { const pickupErr = pickupDateValidationMessage(form.pickupDate); if (pickupErr) next.pickupDate = pickupErr; } if (!form.email.trim()) next.email = "请填写邮箱"; const phoneDigits = form.phone.replace(/\D/g, ""); const country = findPhoneCountry(form.phoneCountry); if (country.code === "US" || country.code === "CA") { if (phoneDigits.length !== 10) next.phone = "请填写 10 位电话号码"; } else if (phoneDigits.length < 6 || phoneDigits.length > 15) { next.phone = "请填写有效电话号码"; } setErrors(next); return Object.keys(next).length === 0; }; const validateStep2 = (): boolean => { const next: Record = {}; if (form.shipmentType === "ltl" && !form.weightLb.trim()) { next.weightLb = "请填写总重量"; } if (form.shipmentType === "ftl" || form.shipmentType === "expedited") { if (!form.commodity.trim()) next.commodity = "请填写货描"; if (!form.weightLb.trim()) next.weightLb = "请填写总重量"; } setErrors(next); return Object.keys(next).length === 0; }; const handleStep1Next = () => { if (!validateStep1()) return; setErrors({}); setStep(2); window.scrollTo({ top: 0, behavior: "smooth" }); }; const handleFinalSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!validateStep2()) return; onSubmit({ ...form, phone: form.phone.replace(/\D/g, "").slice(-10), }); }; return (
{P1_COMMON_UI.step1} {P1_COMMON_UI.step2}
{step === 1 ? (
{P1_COMMON_UI.shipmentType}
{P1_SHIPMENT_CARDS.map((card) => ( patch({ shipmentType: card.id })} /> ))}
patch({ originZip: v })} /> patch({ destinationZip: v })} />
{P1_COMMON_UI.frequency}
patch({ pickupDate: v })} /> patch({ email: v })} /> patch({ phoneCountry: c })} onChange={(v) => patch({ phone: v })} /> {P1_COMMON_UI.getQuotes}
) : (

{P1_STEP2_HEADING[form.shipmentType]}

{form.shipmentType !== "ltl" ? (

{form.shipmentType === "expedited" ? P1_EXPEDITED_UI.subtitle : form.shipmentType === "ftl" ? P1_FTL_UI.subtitle : P1_STEP2_SUBTITLE}

) : null}
{form.shipmentType === "ltl" ? ( <> {P1_LTL_UI.freightSection}
patch({ lengthIn: v })} /> patch({ widthIn: v })} /> patch({ heightIn: v })} />
{P1_LTL_UI.dimensionUnit}
patch({ weightLb: v })} />
patch({ packaging: v })} /> patch({ palletCount: v })} />
patch({ freightClass: v })} /> {P1_LTL_UI.pickupSection} patch({ pickupLocation: v })} /> patch({ pickupServices: toggleInList(form.pickupServices, value), }) } /> {P1_LTL_UI.deliverySection} patch({ deliveryLocation: v })} /> patch({ deliveryServices: toggleInList( form.deliveryServices, value, ), }) } /> ) : null} {form.shipmentType === "ftl" ? ( <> {P1_FTL_UI.selectTrailer} {P1_FTL_TRAILERS.map((t) => ( { const next = t.id as FtlTrailerType; const partial: Partial = { ftlTrailer: next, }; if (next === "ftl_expedited") { partial.ftlAdditionalServices = []; } patch(partial); }} /> ))} {form.ftlTrailer === "open_deck" ? ( patch({ openDeckSubtype: e.target.value })} /> ) : null} {form.ftlTrailer === "ftl_expedited" ? ( <> {P1_FTL_UI.selectExpeditedTrailer} {P1_EXP_TRAILERS.map((t) => ( { const next = t.id as ExpeditedTrailerType; patch({ ftlExpeditedTrailer: next, ...(next !== "large_straight" ? { expeditedLiftgate: false } : {}), }); }} /> ))} {form.ftlExpeditedTrailer === "large_straight" ? ( <> {P1_FTL_UI.additionalServices} patch({ expeditedLiftgate: !form.expeditedLiftgate, }) } /> ) : null} patch({ pickupDate: v })} />

{P1_FTL_UI.freightSection}

patch({ commodity: v })} />
{P1_FTL_UI.specialHandling}
{P1_SPECIAL_HANDLING.map((opt) => ( ))}
patch({ weightLb: v })} /> ) : ( <> {P1_FTL_UI.additionalServices} {P1_FTL_ADDITIONAL.map((s) => ( patch({ ftlAdditionalServices: toggleService( form.ftlAdditionalServices, s.id, ), }) } /> ))} {form.ftlTrailer === "temperature_controlled" ? (
patch({ tempMinF: v })} /> patch({ tempMaxF: v })} />
) : null}

{P1_FTL_UI.freightSection}

patch({ commodity: v })} />
patch({ weightLb: v })} /> patch({ palletCount: v })} />
)} ) : null} {form.shipmentType === "expedited" ? ( <> {P1_EXPEDITED_UI.selectTrailer} {P1_EXP_TRAILERS.map((t) => ( { const next = t.id as ExpeditedTrailerType; patch({ expeditedTrailer: next, ...(next !== "large_straight" ? { expeditedLiftgate: false } : {}), }); }} /> ))} {form.expeditedTrailer === "large_straight" ? ( <> {P1_EXPEDITED_UI.additionalServices} patch({ expeditedLiftgate: !form.expeditedLiftgate }) } /> ) : null}

{P1_EXPEDITED_UI.freightSection}

patch({ commodity: v })} /> patch({ weightLb: v })} />
) : null}
{P1_COMMON_UI.getQuotes}
)}
); }