import React, { useState, useEffect } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { ChevronLeft } from "lucide-react"; import { useDispatch, useSelector } from "react-redux"; import { updatePersonalDetails, updateEducationalDetails, updateFamilyDetails, updateLifestyleDetails, updatePartnerPreferences, submitForm, } from "../redux/registrationFormSlice"; import PersonalDetailsForm from "./PersonalDetailsForm"; import EducationalDetailsForm from "./EducationalDetailsForm"; import FamilyDetailsForm from "./FamilyDetailsForm"; import LifestyleDetailsForm from "./LifestyleDetailsForm"; import PartnerPreferencesForm from "./PartnerPreferencesForm"; import PreviewScreen from "./PreviewScreen"; import { useLocation, useNavigate } from "react-router-dom"; import { useRegisterStep1, useRegisterStep2, useRegisterStep3, useRegisterStep4, useRegisterStep5, } from "../hooks/useRegister"; import axiosInstance, { apiForFiles, setAccessToken } from "../api/axiosInstance"; import toast from "react-hot-toast"; import { API_ENDPOINTS } from "../api/apiEndpoints"; import { isAuthenticated } from "../utills/auth"; import { getPreviewDetails } from "../api/preview.api"; const STEP_FIELD_ORDER = { 1: [ "name", "gender", "mobileNumber", "dob", "height", "weight", "maritalStatus", "religion", "profileFor", "caste", "subCaste", "gothram", "raasi", "star", "email", "password", "confirmPassword", "state", "city", "pincode", "profiles", ], 2: [ "fieldOfStudy", "qualification", "collegeName", "occupation", "organization", "employeeType", "income", "workLocation", ], 3: [ "fatherName", "fatherOccupation", "motherName", "motherOccupation", "brotherCount", "sisterCount", "familyStatus", "nativePlace", ], 4: ["diets", "hobbies", "dob", "tob", "placeOfBirth"], 5: [ "ageRange", "castes", "subCastes", "occupations", "educations", "hobbies", "annualIncome", "states", "districts", ], }; const STEP1_SERVER_FIELD_MAP = { name: "name", mobile: "mobileNumber", mobile_number: "mobileNumber", mobileNumber: "mobileNumber", phone: "mobileNumber", email: "email", gender: "gender", dob: "dob", height: "height", weight: "weight", marital_status: "maritalStatus", maritalStatus: "maritalStatus", religion: "religion", profile_for: "profileFor", profileFor: "profileFor", caste: "caste", sub_caste: "subCaste", subCaste: "subCaste", gothram: "gothram", raasi: "raasi", star: "star", state: "state", district: "city", city: "city", pincode: "pincode", password: "password", confirm_password: "confirmPassword", confirmPassword: "confirmPassword", profiles: "profiles", profile_images: "profiles", }; // const Stepper = ({ currentStep, enabledSteps, onStepClick,completedSteps }) => { // const steps = [ // { num: 1, label: "Personal" }, // { num: 2, label: "Educational" }, // { num: 3, label: "Family" }, // { num: 4, label: "Lifestyle" }, // { num: 5, label: "Partner" }, // { num: 6, label: "Preview" }, // ]; // return ( //
// {steps.map((step, index) => { // const isEnabled = enabledSteps.includes(step.num); // return ( // //
isEnabled && onStepClick(step.num)} // > //
= step.num // ? "bg-red-600 text-white" // : "bg-gray-300 text-gray-600" // }`} // > // {step.num} //
//
// {index < steps.length - 1 && ( //
step.num ? "bg-red-600" : "bg-gray-300" // }`} // /> // )} // // ); // })} //
// ); // }; import { Check } from "lucide-react"; const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick }) => { const steps = [ { num: 1, label: "Personal" }, { num: 2, label: "Educational" }, { num: 3, label: "Family" }, { num: 4, label: "Lifestyle" }, { num: 5, label: "Partner" }, { num: 6, label: "Preview" }, ]; return (
{steps.map((step, index) => { const isEnabled = enabledSteps.includes(step.num); const isCompleted = completedSteps.includes(step.num); return (
isEnabled && onStepClick(step.num)} >
{isCompleted ? : step.num}
{step.label}
{index < steps.length - 1 && (
)} ); })}
); }; const StepperForm = () => { const dispatch = useDispatch(); const queryClient = useQueryClient(); const location = useLocation(); const navigate = useNavigate(); const hideStepperRoutes = ["/profile-edit"]; const shouldHideStepper = hideStepperRoutes.includes(location.pathname); const personalDetails = useSelector( (state) => state.registerform.personalDetails ); const educationalDetails = useSelector( (state) => state.registerform.educationalDetails ); const familyDetails = useSelector((state) => state.registerform.familyDetails); const lifestyleDetails = useSelector( (state) => state.registerform.lifestyleDetails ); const partnerPreferences = useSelector( (state) => state.registerform.partnerPreferences ); const [currentStep, setCurrentStep] = useState(() => { if (location.state?.step) { return location.state.step; } const savedStep = localStorage.getItem("registration_current_step"); return savedStep ? Number(savedStep) : 1; }); const [enabledSteps, setEnabledSteps] = useState([1]); const [completedSteps, setCompletedSteps] = useState([]); const [isStep1Update, setIsStep1Update] = useState(false); const [errors, setErrors] = useState({}); const isAuth = isAuthenticated(); const registerStep1 = useRegisterStep1(); const registerStep2 = useRegisterStep2(); const registerStep3 = useRegisterStep3(); const registerStep4 = useRegisterStep4(); const registerStep5 = useRegisterStep5(); useEffect(() => { localStorage.setItem("registration_current_step", currentStep); }, [currentStep]); const normalizeStep1Field = (key) => { if (!key) return key; const trimmed = String(key).trim(); if (!trimmed) return trimmed; // Map backend profile_images errors (e.g., profile_images.0) to the profiles field if (trimmed.startsWith("profile_images")) { return "profiles"; } return ( STEP1_SERVER_FIELD_MAP[trimmed] || STEP1_SERVER_FIELD_MAP[trimmed.toLowerCase()] || trimmed ); }; const coerceErrorMessage = (value) => { if (Array.isArray(value)) { return value.filter(Boolean).join(" "); } if (typeof value === "string") return value; if (value && typeof value === "object") { return ( value.message || value.msg || value.error || value.detail || "" ); } if (value === null || value === undefined) return ""; return String(value); }; const mapServerErrors = (error) => { const data = error?.response?.data ?? error?.data ?? error; if (!data) return {}; const payload = data.errors ?? data.error ?? data.data ?? data; if (typeof payload === "string") { return { _form: payload }; } if (Array.isArray(payload)) { const out = {}; payload.forEach((item) => { if (!item) return; if (typeof item === "string") { out._form = out._form ? `${out._form} ${item}` : item; return; } const key = item.field || item.name || item.param || item.key; const message = item.message || item.msg || item.error || item.detail || ""; if (key) { out[normalizeStep1Field(key)] = String(message || "Invalid value"); } }); return out; } if (typeof payload === "object") { const out = {}; Object.entries(payload).forEach(([key, value]) => { if ( (key === "message" || key === "error" || key === "detail") && typeof value === "string" ) { out._form = out._form ? `${out._form} ${value}` : value; return; } const normalizedKey = normalizeStep1Field(key); const message = coerceErrorMessage(value); if (!normalizedKey) return; out[normalizedKey] = message || "Invalid value"; }); return out; } return {}; }; const focusFirstError = (errorMap, fieldOrder = []) => { if (!errorMap || Object.keys(errorMap).length === 0) return; const order = fieldOrder.filter((key) => errorMap[key]); const firstKey = order[0] || Object.keys(errorMap).find((key) => key !== "_form"); if (!firstKey) return; setTimeout(() => { const byAria = document.querySelector( `[aria-labelledby~="${firstKey}-label"]` ); if (byAria && typeof byAria.focus === "function") { byAria.focus(); return; } const byName = document.querySelector(`[name="${firstKey}"]`); if (byName && typeof byName.focus === "function") { byName.focus(); return; } const byId = document.getElementById(firstKey); if (byId && typeof byId.focus === "function") { byId.focus(); } }, 0); }; const clearFieldErrors = (fields) => { if (!fields) return; const list = Array.isArray(fields) ? fields : [fields]; setErrors((prev) => { if (!prev || Object.keys(prev).length === 0) return prev; let changed = false; const next = { ...prev }; list.forEach((field) => { if (field in next) { delete next[field]; changed = true; } }); if (next._form) { delete next._form; changed = true; } return changed ? next : prev; }); }; useEffect(() => { // in case user comes again with a different step if (location.state?.step) { setCurrentStep(location.state.step); setEnabledSteps([1, 2, 3, 4, 5, 6]); window.scrollTo(0, 0); } }, [location.state?.step]); useEffect(() => { // Clear the state so it doesn't persist on refresh if (location.state?.step) { navigate(location.pathname, { replace: true, state: {} }); } }, [location.state, navigate, location.pathname]); useEffect(() => { if (!isAuth) return; const fetchPersonalDetails = async () => { try { const response = await axiosInstance.get(API_ENDPOINTS.EDIT_PERSONAL_DETAILS); const data = response.data; if (data.status === "success" && data.personal_details) { const pd = data.personal_details; setIsStep1Update(true); const rawImages = pd.profile_images || pd.images || []; const mappedImages = await Promise.all( rawImages.map(async (url, index) => { const imageUrl = typeof url === "string" ? url : url?.url; let file = null; let mimeType = "image/jpeg"; let fileName = `image-${index}.jpg`; try { const response = await fetch(imageUrl); const blob = await response.blob(); if (blob.type) mimeType = blob.type; const ext = mimeType.split("/")[1] || "jpg"; fileName = `image-${index}.${ext}`; file = new File([blob], fileName, { type: mimeType }); } catch (error) { console.error("Error converting image URL to File:", error); } return { id: `server-${index}`, preview: imageUrl, imageUrl: imageUrl, file: file, name: fileName, type: mimeType, valid: true, }; }) ); const formattedDob = pd.dob ? pd.dob.split("T")[0] : ""; dispatch( updatePersonalDetails({ name: pd.name || "", mobileNumber: pd.mobile || "", email: pd.email || "", gender: pd.gender || "", dob: formattedDob, height: pd.height || "", weight: pd.weight || "", maritalStatus: pd.marital_status_id || "", religion: pd.religion_id || "", profileFor: pd.profile_for_id || "", caste: pd.caste_id || "", subCaste: pd.sub_caste_id || "", gothram: pd.gothram_id || "", raasi: pd.raasi_id || "", star: pd.star_id || "", state: pd.state_id || "", city: pd.district_id || "", pincode: pd.pincode || "", profiles: mappedImages, }) ); } } catch (error) { console.error("Error fetching personal details:", error); } }; fetchPersonalDetails(); }, [dispatch, isAuth]); // Fetch Educational Details const { data: educationalData } = useQuery({ queryKey: ["educationalDetails"], queryFn: async () => { const response = await axiosInstance.get(API_ENDPOINTS.EDIT_EDUCATION_DETAILS); return response.data; }, enabled: isAuth, retry: false, refetchOnWindowFocus: false, }); useEffect(() => { if (educationalData?.status === "success" && educationalData?.educational_details) { const ed = educationalData.educational_details; dispatch( updateEducationalDetails({ fieldOfStudy: ed.study_field_id || "", qualification: ed.education_id || "", collegeName: ed.college_name || "", occupation: ed.occupation_id || "", organization: ed.company_name || "", employeeType: ed.employee_type_id || "", income: ed.annual_income_id || "", workLocation: ed.work_location || "", }) ); } }, [educationalData, dispatch]); // Fetch family details const {data:familyData} = useQuery({ queryKey:["familyDetails"], queryFn: async()=>{ const response = await axiosInstance.get(API_ENDPOINTS.EDIT_FAMILY_DETAILS); return response.data; }, enabled: isAuth, retry:false, refetchOnWindowFocus:false, }); useEffect(()=>{ if (familyData?.status === "success" && familyData?.family_details) { const fd = familyData.family_details; const mappedBrothers = (fd.brothers || []).map((b) => ({ name: b.name || "", occupation: b.occupation_name || "", maritalStatus: b.marital_status || "", haveChildrens: b.have_childrens === true ? 1 : (b.have_childrens === false ? 0 : b.have_childrens), })); const mappedSisters = (fd.sisters || []).map((s) => ({ name: s.name || "", occupation: s.occupation_name || "", maritalStatus: s.marital_status || "", haveChildrens: s.have_childrens === true ? 1 : (s.have_childrens === false ? 0 : s.have_childrens), })); dispatch( updateFamilyDetails({ fatherName: fd.father_name || "", fatherOccupation: fd.father_occupation || "", motherName: fd.mother_name || "", motherOccupation: fd.mother_occupation || "", familyStatus: fd.family_status_id || "", nativePlace: fd.native_place || "", brotherCount: fd.brother_count || 0, sisterCount: fd.sister_count || 0, brothers: mappedBrothers, sisters: mappedSisters, }) ); } },[familyData,dispatch]) // Fetch Lifestyle Details const { data: lifestyleData } = useQuery({ queryKey: ["lifestyleDetails"], queryFn: async () => { const response = await axiosInstance.get(API_ENDPOINTS.EDIT_LIFESTYLE_DETAILS); return response.data; }, enabled: isAuth, retry: false, refetchOnWindowFocus: false, }); useEffect(() => { if (lifestyleData?.status === "success" && lifestyleData?.lifestyle_details) { const ld = lifestyleData.lifestyle_details; const horoscope = ld.horoscope || {}; const mapChart = (prefix) => { const chart = {}; for (let i = 1; i <= 12; i++) { const key = `${prefix}_${i}`; const val = horoscope[key]; chart[i] = val ? val.split(",") : []; } return chart; }; dispatch( updateLifestyleDetails({ diets: ld.diet_id || "", hobbies: ld.hobbies_ids || [], dob: ld.time_of_birth || "", tob: ld.date_of_birth ? ld.date_of_birth.substring(0, 5) : "", placeOfBirth: ld.place_of_birth || "", graha: mapChart("graha"), amsam: mapChart("amsam"), }) ); } }, [lifestyleData, dispatch]); // Fetch Partner Preferences const { data: partnerData } = useQuery({ queryKey: ["partnerPreferences"], queryFn: async () => { const response = await axiosInstance.get(API_ENDPOINTS.EDIT_PREFERED_PARTNER_DETAILS); return response.data; }, enabled: isAuth, retry: false, refetchOnWindowFocus: false, }); useEffect(() => { if (partnerData?.status === "success" && partnerData?.partner_preferences) { const pp = partnerData.partner_preferences; dispatch( updatePartnerPreferences({ ageRange: pp.preferred_age_range_id || "", annualIncome: pp.preferred_annual_income_id || "", castes: pp.preferred_castes_ids || [], subCastes: pp.preferred_sub_castes_ids || [], occupations: pp.preferred_occupations_ids || [], educations: pp.preferred_educations_ids || [], hobbies: pp.preferred_hobbies_ids || [], states: pp.preferred_states_ids || [], districts: pp.preferred_districts_ids || [], }) ); } }, [partnerData, dispatch]); const validateStep = (step) => { const newErrors = {}; if (step === 1) { const required = [ "name", "mobileNumber", "gender", "dob", "height", "maritalStatus", "profileFor", "caste", "email", "state", "city", "pincode", ]; required.forEach((field) => { if (!personalDetails[field]) { const label = field .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); newErrors[field] = `${label} is required`; } }); if (!isStep1Update) { if (!personalDetails.password) newErrors.password = "Password is required"; if (!personalDetails.confirmPassword) newErrors.confirmPassword = "Confirm Password is required"; } if ( personalDetails.email && !/\S+@\S+\.\S+/.test(personalDetails.email) ) { newErrors.email = "Invalid email format"; } if ( personalDetails.mobileNumber && personalDetails.mobileNumber.length !== 10 ) { newErrors.mobileNumber = "Mobile number must be 10 digits"; } if (personalDetails.height && Number(personalDetails.height) > 10) { newErrors.height = "Height must be 10 or less"; } if (personalDetails.weight && Number(personalDetails.weight) > 300) { newErrors.weight = "Weight must be 300 or less"; } if ( personalDetails.password && personalDetails.confirmPassword && personalDetails.password !== personalDetails.confirmPassword ) { newErrors.confirmPassword = "Passwords do not match"; } } else if (step === 2) { const required = [ "qualification", "fieldOfStudy", ]; required.forEach((field) => { if (!educationalDetails[field]) { const label = field .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); newErrors[field] = `${label} is required`; } }); } else if (step === 3) { const required = [ "fatherName", "motherName", "familyStatus", ]; required.forEach((field) => { if (!familyDetails[field]) { // newErrors[field] = "This field is required"; const label = field .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); newErrors[field] = `${label} is required`; } }); if (familyDetails.fatherName && !/^[a-zA-Z\s]*$/.test(familyDetails.fatherName)) { newErrors.fatherName = "Father Name must contain only alphabets"; } if (familyDetails.motherName && !/^[a-zA-Z\s]*$/.test(familyDetails.motherName)) { newErrors.motherName = "Mother Name must contain only alphabets"; } } else if (step === 4) { const required = ["diets", "hobbies", "dob", "tob"]; required.forEach((field) => { const value = lifestyleDetails[field]; if (Array.isArray(value)) { if (value.length === 0) { if (field === "hobbies") { newErrors[field] = "Hobbies and Interests is required"; } else { newErrors[field] = "This field is required"; } } } else if (!value) { if (field === "dob") { newErrors[field] = "Date of Birth is required"; } else if (field === "tob") { newErrors[field] = "Time of Birth is required"; } else if (field === "diets") { newErrors[field] = "Diet is required"; } else { const label = field .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); newErrors[field] = `${label} is required`; } } }); } else if (step === 5) { const required = [ "ageRange", "castes", "subCastes", "occupations", "educations", "hobbies", "annualIncome", "states", "districts", ]; required.forEach((field) => { const value = partnerPreferences[field]; if (Array.isArray(value)) { if (value.length === 0) { // newErrors[field] = "This field is required"; const label = field .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); newErrors[field] = `${label} is required`; } return; } if (!value) { // newErrors[field] = "This field is required"; const label = field .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); newErrors[field] = `${label} is required`; } }); } setErrors(newErrors); if (Object.keys(newErrors).length > 0) { focusFirstError(newErrors, STEP_FIELD_ORDER[step] || []); } return Object.keys(newErrors).length === 0; }; const buildRegisterStep1Payload = async () => { const formData = new FormData(); formData.append("name", personalDetails.name); formData.append("mobile", personalDetails.mobileNumber); formData.append("email", personalDetails.email); formData.append("pincode", personalDetails.pincode); formData.append("gender", personalDetails.gender); formData.append("dob", personalDetails.dob); formData.append("height", personalDetails.height || ""); formData.append("weight", personalDetails.weight || ""); formData.append("marital_status", personalDetails.maritalStatus); formData.append("religion", personalDetails.religion); formData.append("profile_for", personalDetails.profileFor || ""); formData.append("caste", personalDetails.caste); formData.append("sub_caste", personalDetails.subCaste || ""); formData.append("gothram", personalDetails.gothram || ""); formData.append("raasi", personalDetails.raasi || ""); formData.append("star", personalDetails.star || ""); formData.append("state", personalDetails.state); formData.append("district", personalDetails.city); formData.append("password", personalDetails.password || ""); formData.append("web_fcm_token", localStorage.getItem("fcm_token") || ""); if (personalDetails.profiles && Array.isArray(personalDetails.profiles)) { await Promise.all( personalDetails.profiles.map(async (item, index) => { let fileToAppend = item.file; // Check if it's a valid File/Blob. Redux might turn it into {} const isValidFile = fileToAppend && (fileToAppend instanceof Blob || (typeof fileToAppend === "object" && fileToAppend.name)); if (!isValidFile && item.preview && typeof item.preview === "string") { try { const response = await fetch(item.preview); const blob = await response.blob(); const mimeType = blob.type || "image/jpeg"; const ext = mimeType.split("/")[1] || "jpg"; const fileName = item.name || `profile_image_${index}.${ext}`; const fileType = item.type || mimeType; fileToAppend = new File([blob], fileName, { type: fileType }); } catch (e) { console.error(`Could not recover file from URL: ${item.preview}`, e); fileToAppend = null; } } else if (!isValidFile) { fileToAppend = null; } if (fileToAppend) { formData.append(`profile_images[${index}]`, fileToAppend); } }) ); } return formData; }; const buildRegisterStep2Payload = () => { const formData = new FormData(); formData.append("college_name", educationalDetails.collegeName || ""); formData.append("study_field", educationalDetails.fieldOfStudy || ""); formData.append("education", educationalDetails.qualification || ""); formData.append("occupation", educationalDetails.occupation || ""); formData.append("company_name", educationalDetails.organization || ""); formData.append("employee_type", educationalDetails.employeeType || ""); formData.append("annual_income", educationalDetails.income || ""); formData.append("work_location", educationalDetails.workLocation || ""); return formData; }; const buildRegisterStep3Payload = () => { const formData = new FormData(); formData.append("father_name", familyDetails.fatherName); formData.append("father_occupation", familyDetails.fatherOccupation || ""); formData.append("mother_name", familyDetails.motherName); formData.append("mother_occupation", familyDetails.motherOccupation || ""); formData.append("family_status", familyDetails.familyStatus); formData.append("native_place", familyDetails.nativePlace || ""); formData.append("brother_count", familyDetails.brotherCount || 0); formData.append("sister_count", familyDetails.sisterCount || 0); (familyDetails.brothers || []).forEach((brother, index) => { formData.append(`brothers[${index}][name]`, brother?.name || ""); formData.append(`brothers[${index}][occupation]`, brother?.occupation || ""); formData.append(`brothers[${index}][marital_status]`, brother?.maritalStatus || ""); formData.append(`brothers[${index}][have_childrens]`, brother?.haveChildrens ?? ""); }); (familyDetails.sisters || []).forEach((sister, index) => { formData.append(`sisters[${index}][name]`, sister?.name || ""); formData.append(`sisters[${index}][occupation]`, sister?.occupation || ""); formData.append(`sisters[${index}][marital_status]`, sister?.maritalStatus || ""); formData.append(`sisters[${index}][have_childrens]`, sister?.haveChildrens ?? ""); }); return formData; }; const buildRegisterStep4Payload = () => { const formData = new FormData(); formData.append("dob", lifestyleDetails.dob || ""); formData.append("tob", lifestyleDetails.tob || ""); formData.append("place_of_birth", lifestyleDetails.placeOfBirth || ""); formData.append("diet", lifestyleDetails.diets || ""); (lifestyleDetails.hobbies || []).forEach((id, index) => { formData.append(`hobbies[${index}]`, id); }); const graha = lifestyleDetails.graha || {}; Object.keys(graha).forEach((house) => { const values = graha[house] || []; values.forEach((value, index) => { formData.append(`graha_${house}[${index}]`, value); }); }); const amsam = lifestyleDetails.amsam || {}; Object.keys(amsam).forEach((house) => { const values = amsam[house] || []; values.forEach((value, index) => { formData.append(`amsam_${house}[${index}]`, value); }); }); return formData; }; const buildRegisterStep5Payload = () => { const formData = new FormData(); formData.append("age_range", partnerPreferences.ageRange || ""); formData.append("annual_income", partnerPreferences.annualIncome || ""); (partnerPreferences.castes || []).forEach((id, index) => { formData.append(`castes[${index}]`, id); }); (partnerPreferences.subCastes || []).forEach((id, index) => { formData.append(`sub_castes[${index}]`, id); }); (partnerPreferences.occupations || []).forEach((id, index) => { formData.append(`occupations[${index}]`, id); }); (partnerPreferences.educations || []).forEach((id, index) => { formData.append(`educations[${index}]`, id); }); (partnerPreferences.hobbies || []).forEach((id, index) => { formData.append(`hobbies[${index}]`, id); }); (partnerPreferences.states || []).forEach((id, index) => { formData.append(`states[${index}]`, id); }); (partnerPreferences.districts || []).forEach((id, index) => { formData.append(`districts[${index}]`, id); }); return formData; }; const extractAccessToken = (res) => res?.access_token || res?.accessToken || res?.token || res?.data?.access_token || res?.data?.accessToken || res?.data?.token || res?.result?.access_token || res?.result?.accessToken || res?.result?.token || null; const handleStepSubmit = async () => { const isValid = validateStep(currentStep); if (!isValid) return; try { let payload; let res; switch (currentStep) { case 1: payload = await buildRegisterStep1Payload(); if (isStep1Update) { res = await apiForFiles.post("/update_personal_details", payload); try { const previewData = await getPreviewDetails(); if (previewData?.personal_details) { const pd = previewData.personal_details; const images = pd.images || pd.profile_images; if (images && images.length > 0) { const formattedImages = images.map((img) => typeof img === "string" ? { url: img, preview: img } : img ); dispatch(updatePersonalDetails({ profiles: formattedImages })); } } queryClient.invalidateQueries({ queryKey: ["previewDetails"] }); } catch (error) { console.error("Error refreshing preview details:", error); } } else { res = await registerStep1.mutateAsync(payload); } const token = extractAccessToken(res.data || res); if (token) setAccessToken(token); break; case 2: payload = buildRegisterStep2Payload(); await registerStep2.mutateAsync(payload); break; case 3: payload = buildRegisterStep3Payload(); await registerStep3.mutateAsync(payload); break; case 4: payload = buildRegisterStep4Payload(); await registerStep4.mutateAsync(payload); break; case 5: payload = buildRegisterStep5Payload(); await registerStep5.mutateAsync(payload); break; default: break; } if (shouldHideStepper) { toast.success("Updated successfully", { position: "top-right" }); navigate("/profile"); return; } // Mark step completed (tick icon) setCompletedSteps((prev) => prev.includes(currentStep) ? prev : [...prev, currentStep] ); const nextStep = Math.min(currentStep + 1, 6); // Enable next step navigation setEnabledSteps((prev) => prev.includes(nextStep) ? prev : [...prev, nextStep] ); setErrors({}); setCurrentStep(nextStep); window.scrollTo(0, 0); } catch (e) { const serverErrors = mapServerErrors(e); let handled = false; if (Object.keys(serverErrors).length > 0) { const hasFieldErrors = Object.keys(serverErrors).some( (key) => key !== "_form" ); if (hasFieldErrors) { setErrors(serverErrors); focusFirstError(serverErrors, STEP_FIELD_ORDER[currentStep]); handled = true; } if (serverErrors._form) { toast.error(serverErrors._form, { position: "top-right" }); handled = true; } } if (!handled) { const msg = e?.response?.data?.message || e?.message || "Failed to submit step. Please try again."; toast.error(msg, { position: "top-right" }); } } }; const handleSkip = () => { setErrors({}); setCurrentStep((prev) => { const nextStep = Math.min(prev + 1, 6); setEnabledSteps((steps) => steps.includes(nextStep) ? steps : [...steps, nextStep] ); return nextStep; }); window.scrollTo(0, 0); }; const handleStepClick = (step) => { if (!enabledSteps.includes(step)) return; setCurrentStep(step); setErrors({}); window.scrollTo(0, 0); }; useEffect(() => { if (currentStep === 6) { setEnabledSteps([1, 2, 3, 4, 5, 6]); } }, [currentStep]); const handleEdit = (step) => { setCurrentStep(step); setErrors({}); window.scrollTo(0, 0); }; const handleFinalSubmit = async () => { const ok = validateStep(1); if (!ok) { setCurrentStep(1); return; } try { // final combined API call - replace with your final API await new Promise((resolve) => setTimeout(resolve, 500)); toast.success("Form submitted successfully!", { position: "top-right" }); localStorage.removeItem("registration_current_step"); navigate("/dashboard-home"); } catch (e) { toast.error("Failed to submit form.", { position: "top-right" }); } }; const renderStepContent = () => { switch (currentStep) { case 1: return ( ); case 2: return ( ); case 3: return ( ); case 4: return ( ); case 5: return ( ); case 6: return ; default: return null; } }; const getTitle = () => { const titles = { 1: "Personal Details", 2: "Educational & Professional Details", 3: "Family Details", 4: "Lifestyle & Habits", 5: "Partner Preferences", 6: "Details Preview", }; return titles[currentStep] || ""; }; return (
{/* Header */}
{!shouldHideStepper && ( )}
{/* {currentStep > 1 && currentStep < 6 && ( )} */}

{getTitle()}

{/* Content */}
{renderStepContent()}
); }; export default StepperForm;