/* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useEffect, useState, useMemo } from "react"; import CreateOrderFooter from "./CreateOrderFooter"; import PackageGrid from "./Step1/PackageGrid"; import SelectOptions, { OptionType } from "../../../TextField/SelectOptions"; import { getMasterList, // getInternationalCities, } from "../../../../Api/MastersApi"; import Step1Skeleton from "./Step1/Step1Skeleton"; import { initiateInternationalDraftOrder } from "../../../../Api/InternationalOrderApi"; import { useAppSelector } from "@/Redux/Hooks"; import RequiredStar from "./RequiredStar"; import { useCurrency } from "@/context/CurrencyContext"; type Step1Props = { onSave: (data: any) => void; step: number; setStep: React.Dispatch>; defaultOrderDetails: any; isEditMode?: boolean; confirmSaveStep?: (step: number, data: any) => void; }; interface PackageDetail { weight: string; length: string; width: string; height: string; package_description: string; customer_input_package_value: string; } const Step1: React.FC = ({ onSave, step, setStep, defaultOrderDetails, isEditMode, }) => { const { currencyName } = useCurrency(); const [isLoading, setIsLoading] = useState(false); const createOrderData: any = useAppSelector( (state) => state.createOrder, )?.step1; const [step1Data, setStep1Data] = useState(createOrderData?.step1 || {}); // Store step1 data in local state const [fromCountry, setFromCountry] = useState(null); const [toCountry, setToCountry] = useState(null); const [fromCity, setFromCity] = useState(null); const [toCity, setToCity] = useState(null); const [shipmentContent, setShipmentContent] = useState<"Document" | "Parcel">( "Parcel", ); const [noOfPackages, setNoOfPackages] = useState(1); const [defaultPackageWeight, setDefaultPackageWeight] = useState(""); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [defaultPackageValue, setDefaultPackageValue] = useState(""); const [defaultPackageDescription, setDefaultPackageDescription] = useState(""); const [packageDetails, setPackageDetails] = useState([ { weight: "", length: "", width: "", height: "", package_description: "", customer_input_package_value: "", }, ]); const [countries, setCountries] = useState([]); // Validation errors state const [errors, setErrors] = useState<{ fromCountry?: string; toCountry?: string; fromCity?: string; toCity?: string; packageDetails?: { [key: number]: { [field: string]: string } }; }>({}); // Helper: persist step1 data locally const persistStep1Local = (data: any) => { try { localStorage.setItem("CREATE_INTL_STEP1", JSON.stringify(data)); } catch (err) { console.error("Failed to persist step1:", err); } }; // Helper: read persisted step1 data (fallback) const readPersistedStep1 = (): any => { try { return JSON.parse(localStorage.getItem("CREATE_INTL_STEP1") || "null"); } catch { return null; } }; useEffect(() => { const fetchCountries = async () => { try { setIsLoading(true); const response = await getMasterList("country"); if (response?.status) { const countryOptions = response.data.map((c: any) => ({ value: c.id, label: c.name, code: c.code, name: c.name, id: c.id, })); setCountries(countryOptions); // Set default From Country to Bahrain if available // const bahrain = countryOptions.find( // (c: any) => c.code === "BH" || c.name === "Bahrain", // ); // if (bahrain) setFromCountry(bahrain); // Try to restore persisted / redux selections AFTER countries loaded // Logic moved to separate useEffect to avoid dependency loop } } catch (err) { console.error("Error fetching countries:", err); } finally { setIsLoading(false); } }; fetchCountries(); }, []); // Run only on mount // Restore selections when countries are loaded or createOrderData changes useEffect(() => { if (countries.length > 0 && (createOrderData || readPersistedStep1())) { const persisted = readPersistedStep1() || createOrderData || null; // Only restore if not already set (to avoid overwriting user changes if they happen before this runs) // Or if we want to force sync, we should be careful. // For now, let's assume if state is null, we try to restore. if (!fromCountry) { const persistedFromId = persisted?.fromCountry?.value || persisted?.fromCountry?.id || persisted?.shipper_country_details?.id || persisted?.shipperCountryId; if (persistedFromId) { const match = countries.find( (co: any) => co.value === persistedFromId, ); if (match) setFromCountry(match); } else { // Default to Bahrain if nothing persisted and not set const bahrain = countries.find( (c: any) => c.code === "BH" || c.name === "Bahrain", ); if (bahrain) setFromCountry(bahrain); } } if (!toCountry) { const persistedToId = persisted?.toCountry?.value || persisted?.toCountry?.id || persisted?.recipient_country_details?.id || persisted?.recipientCountryId; if (persistedToId) { const match = countries.find((co: any) => co.value === persistedToId); if (match) setToCountry(match); } } } }, [countries, createOrderData, fromCountry, toCountry]); const step1 = JSON.parse(localStorage.getItem("CREATE_INTL_STEP1") || "null"); // Initialize from redux/createOrder data useEffect(() => { if (createOrderData) { // Set initial values if (createOrderData.fromCountry) setFromCountry(createOrderData.fromCountry); if (createOrderData.toCountry) setToCountry(createOrderData.toCountry); if (createOrderData.fromCity) setFromCity(createOrderData.fromCity); if (createOrderData.toCity) setToCity(createOrderData.toCity); if (createOrderData.shipmentContent) setShipmentContent(createOrderData.shipmentContent); if (createOrderData.noOfPackages) setNoOfPackages(createOrderData.noOfPackages); if (createOrderData.packageDetails) setPackageDetails(createOrderData.packageDetails); else if (createOrderData.package_details) setPackageDetails(createOrderData.package_details); if (step1) { setFromCountry(step1.fromCountry); setToCountry(step1.toCountry); setFromCity(step1.fromCity); setToCity(step1.toCity); setShipmentContent(step1.shipmentContent); setNoOfPackages(step1.noOfPackages); setPackageDetails(step1.package_details); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [createOrderData]); // Load default package value from localStorage useEffect(() => { try { const allData = JSON.parse(localStorage.getItem("ALL_DATA") || "{}"); const packageDescription = allData?.data?.packageDescription || ""; handleDefaultDescriptionChange(packageDescription); } catch (error) { console.error("Error loading default package value:", error); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const totalWeight = useMemo(() => { return packageDetails.reduce( (sum, pkg) => sum + (parseFloat(pkg?.weight) || 0), 0, ); }, [packageDetails]); const totalValue = useMemo(() => { return packageDetails.reduce( (sum, pkg) => sum + (parseFloat(pkg.customer_input_package_value) || 0), 0, ); }, [packageDetails]); const handlePackagesChange = (val: number) => { const count = Math.max(1, val); setNoOfPackages(count); const updated = [...packageDetails]; if (count > updated.length) { for (let i = updated.length; i < count; i++) { updated.push({ weight: "", length: "", width: "", height: "", package_description: "", customer_input_package_value: "", }); } } else { updated.splice(count); } setPackageDetails(updated); onSave({ noOfPackages: count, packageDetails: updated }); }; const handleSwap = () => { const tempCountry = fromCountry; const tempCity = fromCity; setFromCountry(toCountry); setToCountry(tempCountry); setFromCity(toCity); setToCity(tempCity); onSave({ fromCountry: toCountry, toCountry: tempCountry, fromCity: toCity, toCity: tempCity, }); }; const handleDefaultWeightChange = (value: string) => { setDefaultPackageWeight(value); // Update all package weights const updated = packageDetails.map((pkg) => ({ ...pkg, weight: value, })); setPackageDetails(updated); onSave({ defaultPackageWeight: value, packageDetails: updated }); }; // eslint-disable-next-line @typescript-eslint/no-unused-vars const handleDefaultValueChange = (value: string) => { setDefaultPackageValue(value); // Update all package values const updated = packageDetails.map((pkg) => ({ ...pkg, customer_input_package_value: value, })); setPackageDetails(updated); onSave({ defaultPackageValue: value, packageDetails: updated }); }; const handleDefaultDescriptionChange = (value: string) => { setDefaultPackageDescription(value); // Update all package values const updated = packageDetails.map((pkg) => ({ ...pkg, package_description: value, })); setPackageDetails(updated); onSave({ defaultPackageDescription: value, packageDetails: updated }); }; const validateStep1 = async () => { const newErrors: typeof errors = {}; // Validate countries and cities if (!fromCountry) { newErrors.fromCountry = "From Country is required"; } if (!toCountry) { newErrors.toCountry = "To Country is required"; } if (!fromCity) { newErrors.fromCity = "From City is required"; } if (!toCity) { newErrors.toCity = "To City is required"; } // Validate package details const packageErrors: { [key: number]: { [field: string]: string } } = {}; packageDetails.forEach((pkg, index) => { const pkgErrors: { [field: string]: string } = {}; if (!pkg.length || parseFloat(pkg.length) <= 0) { pkgErrors.length = "Length is required"; } if (!pkg.width || parseFloat(pkg.width) <= 0) { pkgErrors.width = "Width is required"; } if (!pkg.height || parseFloat(pkg.height) <= 0) { pkgErrors.height = "Height is required"; } if (!pkg.weight || parseFloat(pkg.weight) <= 0) { pkgErrors.weight = "Weight is required"; } if ( !pkg.customer_input_package_value || parseFloat(pkg.customer_input_package_value) <= 0 ) { pkgErrors.customer_input_package_value = "Package value is required"; } if (Object.keys(pkgErrors).length > 0) { packageErrors[index] = pkgErrors; } }); if (Object.keys(packageErrors).length > 0) { newErrors.packageDetails = packageErrors; } if (Object.keys(newErrors).length > 0) { setErrors(newErrors); return false; } setErrors({}); const allData = JSON.parse(localStorage.getItem("ALL_DATA") || "{}")?.data; const payload = { created_for_id: allData?.user?.id, fromCountry, toCountry, fromCity, toCity, shipmentContent, noOfPackages, package_details: packageDetails, total_weight: totalWeight, total_value: totalValue, }; try { setIsLoading(true); // Use existing draft_order_id from state or persisted storage if available const persisted = readPersistedStep1(); const draftOrderId = step1Data?.draft_order_id || persisted?.draft_order_id || 0; const response = await initiateInternationalDraftOrder({ ...payload, product_type: payload?.shipmentContent, draft_order_id: draftOrderId, shipper_country_id: fromCountry?.value, recipient_country_id: toCountry?.value, shipper_city_id: fromCity?.value, recipient_city_id: toCity?.value, }); if (response.status) { const resData: any = response.data; // helpers to map API country/city to OptionType const mapCountry = (c: any): OptionType | null => c ? { value: c.id, label: c.name, code: c.shortCode || c.code, name: c.name, id: c.id, } : null; const mapCity = (c: any): OptionType | null => c ? { value: c.id, label: c.name, name: c.name, id: c.id } : null; const updatedFromCountry = mapCountry(resData.shipper_country_details) || fromCountry; const updatedToCountry = mapCountry(resData.recipient_country_details) || toCountry; const updatedFromCity = mapCity(resData.shipper_city_details) || fromCity; const updatedToCity = mapCity(resData.recipient_city_details) || toCity; // Map draft_order_package_list to local package structure if provided const updatedPackages: PackageDetail[] = Array.isArray( resData.draft_order_package_list, ) ? resData.draft_order_package_list.map((p: any) => ({ weight: p.weight ?? "", length: p.length ?? "", width: p.width ?? "", height: p.height ?? "", package_description: p.packageDescription ?? "", customer_input_package_value: p.customerInputPackageValue ?? "", })) : packageDetails; const updatedStep1Data = { ...payload, draft_order_id: resData.id, // Update draft_order_id with the response fromCountry: updatedFromCountry, toCountry: updatedToCountry, fromCity: updatedFromCity, toCity: updatedToCity, package_details: updatedPackages, // keep also raw ids for safer restore shipperCityId: resData.shipperCityId ?? resData.shipper_city_details?.id, recipientCityId: resData.recipientCityId ?? resData.recipient_city_details?.id, }; // Update component state so UI shows country/city & packages from response setStep1Data(updatedStep1Data); setFromCountry(updatedFromCountry); setToCountry(updatedToCountry); setFromCity(updatedFromCity); setToCity(updatedToCity); setPackageDetails(updatedPackages); // persist for future fallback persistStep1Local(updatedStep1Data); onSave(updatedStep1Data); // Save the updated data return true; } else { setErrors({ fromCountry: "Failed to initiate order. Please try again.", }); return false; } } catch (error) { console.error("Error initiating draft:", error); setErrors({ fromCountry: "An error occurred. Please try again." }); return false; } finally { setIsLoading(false); } }; console.log(packageDetails, "packageDetails"); if (isLoading) { return ; } return ( <>
{/* Left Sidebar - Receipt Style Preview */}
Preview Details
{fromCountry?.name || "Bahrain"}
{toCountry?.name || "Select Country"}
{fromCity && toCity && (

{fromCity.name} → {toCity.name}

)}
Package Type {shipmentContent}

No. of Packages {String(noOfPackages).padStart(2, "0")}

Total Weight {totalWeight.toFixed(2)} KG

Order Value {currencyName} {totalValue.toFixed(3)}

From Country {fromCountry?.name || "Bahrain"}

To Country {toCountry?.name || "-"}
{/* Main Content */}
{/* From/To Section */}
{/* From Section */}
From
{ if (val?.value !== fromCountry?.value) { setFromCity(null); } setFromCountry(val); if (errors.fromCountry) { setErrors({ ...errors, fromCountry: undefined, }); } }} isDisabled placeholder="Select Country" divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "15px", height: "50px", paddingLeft: "40px", border: errors.fromCountry ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", "&:hover": { borderColor: errors.fromCountry ? "#dc3545" : "#dee2e6", }, }), }} />
{errors.fromCountry && (
{errors.fromCountry}
)}
{ setFromCity(val); if (errors.fromCity) { setErrors({ ...errors, fromCity: undefined }); } }} placeholder={ !fromCountry ? "Select Country First" : "Select City" } divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "15px", height: "50px", paddingLeft: "40px", border: errors.fromCity ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", "&:hover": { borderColor: errors.fromCity ? "#dc3545" : "#dee2e6", }, }), }} />
{errors.fromCity && (
{errors.fromCity}
)}
{/* Vertical Separator & Swap Button */}
{/* To Section */}
To
{ if (val?.value !== toCountry?.value) { setToCity(null); } setToCountry(val); if (errors.toCountry) { setErrors({ ...errors, toCountry: undefined }); } }} placeholder="Select Country" divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "15px", height: "50px", paddingLeft: "40px", border: errors.toCountry ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", "&:hover": { borderColor: errors.toCountry ? "#dc3545" : "#dee2e6", }, }), }} />
{errors.toCountry && (
{errors.toCountry}
)}
{ setToCity(val); if (errors.toCity) { setErrors({ ...errors, toCity: undefined }); } }} isDisabled={!toCountry} placeholder={ !toCountry ? "Select Country First" : "Select City" } divClassName="mb-0" style={{ control: (base: any) => ({ ...base, borderRadius: "15px", height: "50px", paddingLeft: "40px", border: errors.toCity ? "1px solid #dc3545" : "1px solid #dee2e6", boxShadow: "none", "&:hover": { borderColor: errors.toCity ? "#dc3545" : "#dee2e6", }, }), }} />
{errors.toCity && (
{errors.toCity}
)}
{/* Shipment Content & Package Info */}
{/* Shipment Content */}
What is Your Shipment Content?
{/* Number of Packages */}
Number of Packages
handlePackagesChange(parseInt(e.target.value)) } />
Default Pkg Weight
handleDefaultWeightChange(e.target.value) } placeholder="Weight" />
{/*
Default Pkg Value
handleDefaultValueChange(e.target.value)} placeholder="Package value" />
*/}
Default Pkg description
handleDefaultDescriptionChange(e.target.value) } placeholder="Package description" />
Total Weight
{totalWeight.toFixed(2)} Kg
{/* Package Grid */}
No. of Packages ({String(noOfPackages).padStart(2, "0")})
{ setPackageDetails(updatedPackages); if (errors.packageDetails) { setErrors({ ...errors, packageDetails: undefined }); } }} errors={errors.packageDetails || null} />
{ if (await validateStep1()) setStep(nextStep); }} validation={validateStep1} backButton={false} defaultOrderDetails={defaultOrderDetails} isEditMode={isEditMode} isInternational={true} /> ); }; export default Step1;