/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useEffect, useState } from "react"; import CreateOrderFooter from "./CreateOrderFooter"; import SelectOptions, { OptionType } from "../../../TextField/SelectOptions"; import InternationalPhoneInput from "../../../TextField/InternationalPhoneInput"; import { useAppSelector } from "@/Redux/Hooks"; import { getMasterList, getInternationalCities, } from "../../../../Api/MastersApi"; import { initiateInternationalDraftOrder } from "../../../../Api/InternationalOrderApi"; import { buildAddressText, resolveCountryCode } from "../../../../lib/Helper"; import RequiredStar from "./RequiredStar"; import AddressList from "../../MyProfile/Containers/AddressList"; import Modal from "../../../Modal/Modal"; import HourGlassLoader from "../../../Loader/Loader"; import Swal from "sweetalert2"; type Step3Props = { onSave: (data: any) => void; step: number; setStep: React.Dispatch>; defaultOrderDetails: any; isEditMode?: boolean; }; const Step3: React.FC = ({ onSave, step, setStep, defaultOrderDetails, isEditMode, }) => { const createOrderData: any = useAppSelector((state) => state.createOrder); const step1Data = createOrderData?.step1; const step3Data = createOrderData?.step3; const step4Data = createOrderData?.step4; type Step3Errors = { senderCompanyName?: boolean; senderName?: boolean; senderPhone?: boolean; senderAddress?: boolean; senderCountry?: boolean; senderCity?: boolean; senderTaxId?: boolean; senderPostalCode?: boolean; senderAltPhone?: boolean; senderEmail?: boolean; senderAddress2?: boolean; senderSave?: boolean; receiverCompanyName?: boolean; receiverName?: boolean; receiverPhone?: boolean; receiverAddress?: boolean; receiverCountry?: boolean; receiverCity?: boolean; receiverTaxId?: boolean; receiverPostalCode?: boolean; receiverAltPhone?: boolean; receiverEmail?: boolean; receiverAddress2?: boolean; receiverSave?: boolean; }; const [errors, setErrors] = useState({}); const [isLoading, setIsLoading] = useState(false); // --- Sender State --- const [senderCompanyName, setSenderCompanyName] = useState( step3Data?.senderCompanyName || "", ); console.log(step3Data?.senderName, 'step3Data?.senderNamestep3Data?.senderNamestep3Data?.senderName') const [senderName, setSenderName] = useState( step3Data?.senderName || "", ); const [senderTaxId, setSenderTaxId] = useState( step3Data?.senderTaxId || "", ); const [senderCountry, setSenderCountry] = useState( step3Data?.senderCountry || step1Data?.fromCountry || null, ); const [senderCity, setSenderCity] = useState( step3Data?.senderCity || step1Data?.fromCity || null, ); const [senderPostalCode, setSenderPostalCode] = useState( step3Data?.senderPostalCode || "", ); const [senderPhone, setSenderPhone] = useState( step3Data?.senderPhone || "", ); const [senderAltPhone, setSenderAltPhone] = useState( step3Data?.senderAltPhone || "", ); const [senderEmail, setSenderEmail] = useState( step3Data?.senderEmail || "", ); const [senderAddress, setSenderAddress] = useState( step3Data?.senderAddress || "", ); const [senderAddress2, setSenderAddress2] = useState( step3Data?.senderAddress2 || "", ); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [saveSender, setSaveSender] = useState( step3Data?.saveSender ?? false, ); // --- Receiver State --- const [receiverCompanyName, setReceiverCompanyName] = useState( step3Data?.receiverCompanyName || "", ); const [receiverName, setReceiverName] = useState( step3Data?.receiverName || "", ); const [receiverTaxId, setReceiverTaxId] = useState( step3Data?.receiverTaxId || "", ); const [receiverCountry, setReceiverCountry] = useState( step3Data?.receiverCountry || step1Data?.toCountry || null, ); const [receiverCity, setReceiverCity] = useState( step3Data?.receiverCity || step1Data?.toCity || null, ); const [receiverPostalCode, setReceiverPostalCode] = useState( step3Data?.receiverPostalCode || "", ); const [receiverPhone, setReceiverPhone] = useState( step3Data?.receiverPhone || "", ); const [receiverAltPhone, setReceiverAltPhone] = useState( step3Data?.receiverAltPhone || "", ); const [receiverEmail, setReceiverEmail] = useState( step3Data?.receiverEmail || "", ); const [receiverAddress, setReceiverAddress] = useState( step3Data?.receiverAddress || "", ); const [receiverAddress2, setReceiverAddress2] = useState( step3Data?.receiverAddress2 || "", ); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [saveReceiver, setSaveReceiver] = useState( step3Data?.saveReceiver ?? false, ); // --- Lists --- const [countries, setCountries] = useState([]); const [senderCities, setSenderCities] = useState([]); const [receiverCities, setReceiverCities] = useState([]); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [pickupAddressId, setPickupAddressId] = useState(() => { const saved = localStorage.getItem("PICKUP_ADDRESS_ID"); return saved ? Number(saved) : step4Data?.pickup_address_id || null; }); const [showAddressList, setShowAddressList] = useState(false); const allData = JSON.parse(localStorage.getItem("ALL_DATA") || "{}"); const handleAddressSelect = () => { const addresses = allData?.data?.addresses || []; const primaryAddress = addresses.find((addr: any) => addr.is_primary) || addresses[0] || null; const address = primaryAddress || null; const { line1, line2 } = buildAddressText(address); setSenderAddress(`${line1}${line2}`); // setSenderAddress2(line2); setPickupAddressId(address.id); localStorage.setItem("PICKUP_ADDRESS_ID", String(address.id)); setErrors((prev) => ({ ...prev, senderAddress: false, })); // toggleAddressList(); // ✅ close modal setShowAddressList(false); }; useEffect(() => { const allData = JSON.parse(localStorage.getItem("ALL_DATA") || "{}"); const addresses = allData?.data?.addresses || []; if (!addresses.length) return; const primary = addresses.find((addr: any) => addr.is_primary) || addresses[0]; if (primary && !senderAddress) { handleAddressSelect(); } }, []); // --- Effects --- useEffect(() => { const fetchCountries = async () => { try { const response = await getMasterList("country"); if (response?.status) { const countryOptions = response.data.map((c: any) => ({ value: c.id, label: c.name, code: c.code ?? c.shortCode, name: c.name, id: c.id, })); setCountries(countryOptions); } } catch (err) { console.error("Error fetching countries:", err); } }; fetchCountries(); }, []); // When countries or step1 data load, restore sender/receiver country & cities if not already set useEffect(() => { const restoreFromStep1 = async () => { if (!countries || countries.length === 0) return; const findCountryMatch = (ref: any) => { if (!ref) return null; // prefer id/value if available const refId = ref.id ?? ref.value ?? null; if (refId !== null && refId !== undefined) { const byId = countries.find((c) => String(c.id) === String(refId)) || countries.find((c) => String(c.value) === String(refId)); if (byId) return byId; } // match by code (normalized) const refCode = String(ref.code ?? ref.shortCode ?? "").toUpperCase(); if (refCode) { const byCode = countries.find( (c) => String(c.code ?? "").toUpperCase() === refCode, ); if (byCode) return byCode; } // exact name/label match (case-insensitive) const refName = (ref.label ?? ref.name ?? "") .toString() .trim() .toLowerCase(); if (refName) { const byName = countries.find( (c) => (c.label ?? c.name ?? "").toString().trim().toLowerCase() === refName, ); if (byName) return byName; } // no loose fallback — return null so caller does not pick wrong country return null; }; // restore sender country if (!senderCountry && step1Data?.fromCountry) { const ref = step1Data.fromCountry; const found = findCountryMatch(ref); if (found) { setSenderCountry(found); // fetch cities for this country and try to restore city const res = await getInternationalCities({ country_id: found.value }); if (res?.status) { const cityOptions = res.data.map((c: any) => ({ value: c.id, label: c.name, name: c.name, id: c.id, })); setSenderCities(cityOptions); // restore city if present in step1 const cityRef = step3Data?.senderCity || step1Data?.fromCity; if (cityRef) { const cityId = (cityRef.id ?? cityRef.value ?? cityRef)?.toString?.() ?? ""; const foundCity = cityOptions.find( (ct: { id: any }) => String(ct.id) === String(cityId), ) || cityOptions.find( (ct: { label: any; name: any }) => (ct.label ?? ct.name ?? "").toString().toLowerCase() === (cityRef.name ?? "").toString().toLowerCase(), ); if (foundCity) setSenderCity(foundCity); } } } } // restore receiver country if (!receiverCountry && step1Data?.toCountry) { const ref = step1Data.toCountry; const found = findCountryMatch(ref); if (found) { setReceiverCountry(found); const res = await getInternationalCities({ country_id: found.value }); if (res?.status) { const cityOptions = res.data.map((c: any) => ({ value: c.id, label: c.name, name: c.name, id: c.id, })); setReceiverCities(cityOptions); const cityRef = step3Data?.receiverCity || step1Data?.toCity; if (cityRef) { const cityId = (cityRef.id ?? cityRef.value ?? cityRef)?.toString?.() ?? ""; const foundCity = cityOptions.find( (ct: { id: any }) => String(ct.id) === String(cityId), ) || cityOptions.find( (ct: { label: any; name: any }) => (ct.label ?? ct.name ?? "").toString().toLowerCase() === (cityRef.name ?? "").toString().toLowerCase(), ); if (foundCity) setReceiverCity(foundCity); } } } } }; // fire without blocking render restoreFromStep1().catch((e) => console.error("restoreFromStep1", e)); console.log(allData, "ds"); setSenderCompanyName(allData?.data?.companyName); setSenderName(step3Data?.senderName ? step3Data?.senderName : `${allData?.data?.altFirstName} ${allData?.data?.altLastName}` || ""); setSenderEmail(allData?.data?.email); setSenderPhone(allData?.data?.phone); setSenderAltPhone(allData?.data?.altPhone); }, [countries, step1Data]); // helper to fetch cities const fetchCitiesFor = async ( country: OptionType | null, setCities: React.Dispatch>, ) => { if (!country) { setCities([]); return; } try { const response = await getInternationalCities({ country_id: country.value, }); if (response?.status) { setCities( response.data.map((c: any) => ({ value: c.id, label: c.name, name: c.name, id: c.id, })), ); // if we have step1 data city matching this country, restore it // (keep this quick and defensive) if (country === senderCountry && step1Data?.fromCity) { const found = response.data.find( (ct: any) => ct.id === (step3Data?.senderCity?.value ?? step1Data?.fromCity?.value) || ct.name === (step3Data?.senderCity?.name ?? step1Data?.fromCity?.name), ); if (found) { setSenderCity({ value: found.id, label: found.name, id: found.id, name: found.name, }); } } if (country === receiverCountry && step1Data?.toCity) { const found = response.data.find( (ct: any) => ct.id === (step3Data?.receiverCity?.value ?? step1Data?.toCity?.value) || ct.name === (step3Data?.receiverCity?.name ?? step1Data?.toCity?.name), ); if (found) { setReceiverCity({ value: found.id, label: found.name, id: found.id, name: found.name, }); } } } else { setCities([]); } } catch (err) { console.error("Error fetching cities:", err); setCities([]); } }; useEffect(() => { fetchCitiesFor(senderCountry, setSenderCities); }, [senderCountry]); useEffect(() => { fetchCitiesFor(receiverCountry, setReceiverCities); }, [receiverCountry]); // --- Handlers --- const handleClearSender = () => { setSenderCompanyName(""); setSenderName(""); setSenderTaxId(""); // Keep country/city as they are likely correct from Step 1 setSenderPostalCode(""); setSenderPhone(""); setSenderAltPhone(""); setSenderEmail(""); setSenderAddress(""); setSenderAddress2(""); }; const handleClearReceiver = () => { setReceiverCompanyName(""); setReceiverName(""); setReceiverTaxId(""); // Keep country/city as they are likely correct from Step 1 setReceiverPostalCode(""); setReceiverPhone(""); setReceiverAltPhone(""); setReceiverEmail(""); setReceiverAddress(""); setReceiverAddress2(""); }; const validateStep3 = async () => { if (isLoading) return false; if (!step1Data) return false; const newErrors: Step3Errors = { senderCompanyName: !senderCompanyName, senderName: !senderName, senderPhone: !senderPhone, senderAddress: !senderAddress, senderCountry: !senderCountry, senderCity: !senderCity, senderPostalCode: !senderPostalCode, receiverCompanyName: !receiverCompanyName, receiverName: !receiverName, receiverPhone: !receiverPhone, receiverAddress: !receiverAddress, receiverCountry: !receiverCountry, receiverCity: !receiverCity, receiverPostalCode: !receiverPostalCode, }; setErrors(newErrors); const hasError = Object.values(newErrors).some(Boolean); if (hasError) return false; if (isLoading) return false; // prevent duplicate submissions // ensure step1 exists if (!step1Data) { window.alert("Please complete Step 1 before proceeding."); return false; } // Basic validation if ( !senderCompanyName || !senderName || !senderPhone || !senderAddress || !senderCountry || !senderCity || !senderPostalCode || !receiverCompanyName || !receiverName || !receiverPhone || !receiverAddress || !receiverCountry || !receiverCity || !receiverPostalCode ) { window.alert("Please fill all required fields in From and To sections."); return false; } const step1 = JSON.parse( localStorage.getItem("CREATE_INTL_STEP1") || "null", ); const allData = JSON.parse(localStorage.getItem("ALL_DATA") || "{}"); const addresses = allData?.data?.addresses || []; const primaryAddress = addresses.find((addr: any) => addr.is_primary) || addresses[0] || null; const payloadBody = { // Step 1: Draft & Package Info draft_order_id: step1Data.draft_order_id, package_details: (step1?.package_details || []).map((pkg: any) => ({ package_type_id: pkg.package_type_id ?? undefined, weight: parseFloat(pkg.weight || 0), length: parseFloat(pkg.length || 0), width: parseFloat(pkg.width || 0), height: parseFloat(pkg.height || 0), package_description: pkg.package_description || undefined, customer_input_package_value: parseFloat( pkg.customer_input_package_value || 0, ), })), customer_input_order_id: step1Data.customerInputOrderId || undefined, description: step1Data.shipmentContent || undefined, no_of_packages: step1Data.noOfPackages ?? undefined, total_weight: step1Data.totalWeight ?? undefined, total_value: step1Data.totalValue ?? undefined, pickup_address_id: primaryAddress?.id, // Step 2: Carrier / Service carrier: createOrderData.step2?.selectedCarrierDetails?.name || undefined, service_code: createOrderData.step2?.selectedServiceDetails?.id || undefined, service_name: createOrderData.step2?.selectedServiceDetails?.name || undefined, shipping_charge: createOrderData.step2?.selectedServiceDetails?.price ?? undefined, currency: createOrderData.step2?.selectedServiceDetails?.currency ?? undefined, // Step 3: Sender Info shipper_name: senderName || undefined, pickup_customer_name: senderName || undefined, shipper_company_name: senderCompanyName || undefined, shipper_email: senderEmail || undefined, pickup_mobile_number: senderPhone || undefined, pickup_alternate_number: senderAltPhone || undefined, shipper_address: senderAddress || undefined, shipper_address_2: senderAddress2 || undefined, shipper_city_id: senderCity?.value || undefined, shipper_city: senderCity?.label || undefined, shipper_postal_code: senderPostalCode || undefined, shipper_country_id: senderCountry?.value || step1Data?.fromCountry?.value || undefined, shipper_country: senderCountry?.label || step1Data?.fromCountry?.label || undefined, shipper_tax_no: senderTaxId || undefined, // Step 3: Receiver Info recipient_name: receiverName || undefined, destination_customer_name: receiverName || undefined, recipient_company_name: receiverCompanyName || undefined, recipient_email: receiverEmail || undefined, destination_mobile_number: receiverPhone || undefined, destination_alternate_number: receiverAltPhone || undefined, recipient_address: receiverAddress || undefined, recipient_address_2: receiverAddress2 || undefined, recipient_city_id: receiverCity?.value || undefined, recipient_city: receiverCity?.label || undefined, recipient_postal_code: receiverPostalCode || undefined, recipient_country_id: receiverCountry?.value || step1Data?.toCountry?.value || undefined, recipient_country: receiverCountry?.label || step1Data?.toCountry?.label || undefined, recipient_tax_no: receiverTaxId || undefined, // Step 4: Pickup & Reference // pickup_address_id: step4Data?.pickup_address_id || undefined, // pickup_customer_name: step4Data?.pickup_customer_name || undefined, // pickup_mobile_number: step4Data?.pickup_mobile_number || undefined, // pickup_alternate_number: step4Data?.pickup_alternate_number || undefined, delivery_instructions: step4Data?.delivery_instructions || undefined, pickup_date: step4Data?.pickup_date ? new Date(step4Data.pickup_date) : undefined, pickup_slot_type: step4Data?.pickup_slot_type ?? undefined, ref_order_id: step1Data.ref_order_id || undefined, // Optional Customs / COD payment_type: step1Data.paymentType || undefined, customs_value: step1Data.totalValue || undefined, is_cod: step1Data.isCod ?? undefined, cod_amount: step1Data.codAmount ?? undefined, product_group: step1Data.productGroup || undefined, product_type: step1Data.productType || undefined, }; try { setIsLoading(true); const response = await initiateInternationalDraftOrder(payloadBody); if (response?.status) { // pass saved values back (include API response if useful) onSave({ senderCompanyName, senderName, senderTaxId, senderCountry, senderCity, senderPostalCode, senderPhone, senderAltPhone, senderEmail, senderAddress, senderAddress2, saveSender, receiverCompanyName, receiverName, receiverTaxId, receiverCountry, receiverCity, receiverPostalCode, receiverPhone, receiverAltPhone, receiverEmail, receiverAddress, receiverAddress2, saveReceiver, apiResponse: response.data ?? null, }); return true; } else { console.error("Failed to update draft:", response?.message); Swal.fire({ icon: "error", title: "Failed to update order details", text: response?.message || "Something went wrong. Please try again.", customClass: { confirmButton: "delybell-primary px-4", cancelButton: "delybell-dark", }, }); return false; } } catch (error) { console.error("Error updating draft:", error); Swal.fire({ icon: "error", title: "Failed to update order details", text: "An error occurred while updating draft. Please try again.", customClass: { confirmButton: "delybell-primary px-4", cancelButton: "delybell-dark", }, }); return false; } finally { setIsLoading(false); } }; const toggleAddressList = () => { setShowAddressList((prev) => !prev); // handleAddressSelect() }; useEffect(() => { // When modal is CLOSED, refresh latest address if (!showAddressList) { handleAddressSelect(); } }, [showAddressList]); return ( <> {isLoading && }
{/* Sender Section (From) */}
From
setSenderCompanyName(e.target.value)} placeholder="Company Name" />
setSenderName(e.target.value)} placeholder="Name" />
setSenderCountry(val)} placeholder="Select Country" divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "10px", height: "45px", paddingLeft: "35px", border: errors.senderCountry ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", }), }} />
setSenderCity(val)} placeholder="Select City" divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "15px", height: "50px", paddingLeft: "40px", border: errors.senderCity ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", "&:hover": { borderColor: errors.senderCity ? "#dc3545" : "#dee2e6", }, }), }} />
setSenderPostalCode(e.target.value)} placeholder="Postal Code" />
setSenderTaxId(e.target.value)} placeholder="Tax ID/VAT/EIN Number" />
setSenderPhone(val)} className={`form-control custom-input-rounded ${ errors.senderPhone ? "is-invalid" : "" }`} placeholder="Mobile Number" country={resolveCountryCode(senderCountry, countries)} />
setSenderAltPhone(val)} className={`form-control custom-input-rounded ${ errors.senderAltPhone ? "is-invalid" : "" }`} placeholder="Alternative Mobile Number" country={resolveCountryCode(senderCountry, countries)} />
setSenderEmail(e.target.value)} placeholder="Email Address" />
{/*
setSenderAddress(e.target.value)} placeholder="Address Line 1" />
setSenderAddress2(e.target.value)} placeholder="Address Line 2" />
*/}
{/* LEFT icon */} {/* Text input */} setSenderAddress(e.target.value)} placeholder="Address" /> {/* RIGHT edit icon */}
{/*
setSaveSender(e.target.checked)} />
*/}
{/* Receiver Section (To) */}
To
setReceiverCompanyName(e.target.value)} placeholder="Company Name" />
setReceiverName(e.target.value)} placeholder="Name" />
setReceiverCountry(val)} placeholder="Select Country" divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "10px", height: "45px", paddingLeft: "35px", border: errors.receiverCountry ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", }), }} />
setReceiverCity(val)} placeholder="Select City" divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "10px", height: "45px", paddingLeft: "35px", border: errors.receiverCity ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", }), }} />
setReceiverPostalCode(e.target.value)} placeholder="Postal Code" />
setReceiverTaxId(e.target.value)} placeholder="Tax ID/VAT/EIN Number" />
setReceiverPhone(val)} placeholder="Mobile Number" className={`form-control custom-input-rounded ${ errors.receiverPhone ? "is-invalid" : "" }`} country={resolveCountryCode(receiverCountry, countries)} />
setReceiverAltPhone(val)} className={`form-control custom-input-rounded ${ errors.receiverAltPhone ? "is-invalid" : "" }`} placeholder="Alternative Mobile Number" country={resolveCountryCode(receiverCountry, countries)} />
setReceiverEmail(e.target.value)} placeholder="Email Address" />
setReceiverAddress(e.target.value)} placeholder="Address" />
{/*
setReceiverAddress2(e.target.value)} placeholder="Address Line 2" />
*/} {/*
setSaveReceiver(e.target.checked)} />
*/}
{/* ADDRESS PREVIEW SECTION */} {/*
Address Preview
From

{senderName || "—"}

{senderAddress || "—"}

{senderAddress2 &&

{senderAddress2}

}

{senderCity?.label || ""}{" "} {senderPostalCode && `- ${senderPostalCode}`}

{senderCountry?.label || ""}

{senderPhone || ""}

To

{receiverName || "—"}

{receiverAddress || "—"}

{receiverAddress2 &&

{receiverAddress2}

}

{receiverCity?.label || ""}{" "} {receiverPostalCode && `- ${receiverPostalCode}`}

{receiverCountry?.label || ""}

{receiverPhone || ""}

*/} { if (await validateStep3()) setStep(nextStep); }} validation={validateStep3} backButton={true} // Navigate explicitly to Step 2 and notify listeners so Step2 can reload selected package/service. backButtonFn={() => { setStep(2); try { // Emit event so Step2 can listen and re-populate its selects if necessary. // include reload:true so Step2 knows to re-fetch/restore state window.dispatchEvent( new CustomEvent("navigate-to-step", { detail: { step: 2, reload: true }, }), ); // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (err) { // ignore in non-browser environments } }} defaultOrderDetails={defaultOrderDetails} isEditMode={isEditMode} /> ); }; export default Step3;