"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 (
);
}
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}
) : (
)}
);
}