Build and deployment update: Refined registration forms, stepper navigation, and chat synchronization fixes
This commit is contained in:
1 parent
68f97c40dc
commit
c467271927
27 files changed
+3461
-4178
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useMemo, useRef } from "react";
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { updateEducationalDetails } from "../redux/registrationFormSlice";
|
||||
import { updateEducationalDetails, clearAllStepsFrom } from "../redux/registrationFormSlice";
|
||||
import {
|
||||
TextField,
|
||||
Button,
|
||||
@@ -9,456 +9,412 @@ import {
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
FormHelperText,
|
||||
InputAdornment,
|
||||
Box,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useEducationMasters, useEducationList } from "../hooks/useMasters";
|
||||
import { useCityMasters } from "../hooks/useDependentMasters";
|
||||
import { toast } from "react-hot-toast";
|
||||
|
||||
const EducationalDetailsForm = ({
|
||||
onSubmitStep,
|
||||
onSkipStep,
|
||||
errors,
|
||||
onFieldChange,
|
||||
errors: externalErrors,
|
||||
isEditMode,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const data = useSelector((state) => state.registerform.educationalDetails);
|
||||
const inputRef = useRef(null);
|
||||
const [localErrors, setLocalErrors] = useState({});
|
||||
const requiredMark = <span style={{ color: "#d32f2f" }}> *</span>;
|
||||
|
||||
const { data: educationMasters, isLoading: isEducationMastersLoading } =
|
||||
useEducationMasters();
|
||||
const educationListQuery = useEducationList(data.fieldOfStudy);
|
||||
const educationListQuery = useEducationList(data.study_field);
|
||||
const districtQuery = useCityMasters(data.work_state);
|
||||
|
||||
const studyFieldOptions = useMemo(() => {
|
||||
const raw = educationMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.studyFields || raw.study_fields || raw.fieldOfStudy || [];
|
||||
}, [educationMasters]);
|
||||
const studyFieldOptions = educationMasters?.studyFields || [];
|
||||
const qualificationOptions = educationListQuery.data?.education || educationListQuery.data?.data || [];
|
||||
const occupationOptions = educationMasters?.occupation || [];
|
||||
const employeeTypeOptions = educationMasters?.employeeType || [];
|
||||
const countryOptions = educationMasters?.country || [];
|
||||
const stateOptions = educationMasters?.state || [];
|
||||
const districtOptions = districtQuery.data?.districts || districtQuery.data || [];
|
||||
|
||||
const qualificationOptions = useMemo(() => {
|
||||
const raw = educationListQuery.data;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.education || raw.data || [];
|
||||
}, [educationListQuery.data]);
|
||||
|
||||
const occupationOptions = useMemo(() => {
|
||||
const raw = educationMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.occupation || raw.occupations || [];
|
||||
}, [educationMasters]);
|
||||
|
||||
const employeeTypeOptions = useMemo(() => {
|
||||
const raw = educationMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.employeeType || raw.employee_type || [];
|
||||
}, [educationMasters]);
|
||||
|
||||
const annualIncomeOptions = useMemo(() => {
|
||||
const raw = educationMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.annualIncome || raw.annual_income || [];
|
||||
}, [educationMasters]);
|
||||
|
||||
const workLocationOptions = useMemo(() => {
|
||||
const raw = educationMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return [];
|
||||
return raw.workLocation || raw.work_location || raw.workLocations || [];
|
||||
}, [educationMasters]);
|
||||
|
||||
const getOptionLabel = (item, fallback = "") => {
|
||||
if (!item) return fallback;
|
||||
if (typeof item === "string") return item;
|
||||
return (
|
||||
item.study_field_name ||
|
||||
item.education_name ||
|
||||
item.occupation_name ||
|
||||
item.employee_type_name ||
|
||||
item.annual_income_name ||
|
||||
item.work_location_name ||
|
||||
item.name ||
|
||||
fallback
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus();
|
||||
}, []);
|
||||
const isUnemployed = data.employee_type === 11;
|
||||
const isIndia = Number(data.work_country) === 1;
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
const updates = { [field]: value };
|
||||
const fieldsToClear = [field];
|
||||
if (field === "fieldOfStudy") {
|
||||
updates.qualification = "";
|
||||
fieldsToClear.push("qualification");
|
||||
|
||||
if (field === "study_field") {
|
||||
updates.education = "";
|
||||
}
|
||||
if (field === "work_country") {
|
||||
updates.work_state = "";
|
||||
updates.work_district = "";
|
||||
updates.work_city = "";
|
||||
}
|
||||
if (field === "work_state") {
|
||||
updates.work_district = "";
|
||||
}
|
||||
if (field === "employee_type" && value === 11) {
|
||||
// Clear fields that will be hidden
|
||||
updates.occupation = "";
|
||||
updates.occupation_detail = "";
|
||||
updates.company_name = "";
|
||||
updates.annual_income = "";
|
||||
updates.work_country = "";
|
||||
updates.work_state = "";
|
||||
updates.work_district = "";
|
||||
updates.work_city = "";
|
||||
}
|
||||
|
||||
dispatch(updateEducationalDetails(updates));
|
||||
if (onFieldChange) onFieldChange(fieldsToClear);
|
||||
setLocalErrors((prev) => ({ ...prev, [field]: "" }));
|
||||
|
||||
if (!isEditMode) {
|
||||
dispatch(clearAllStepsFrom(3));
|
||||
}
|
||||
};
|
||||
|
||||
const validateForm = () => {
|
||||
const newErrors = {};
|
||||
if (!data.study_field) newErrors.study_field = "Required";
|
||||
if (!data.education) newErrors.education = "Required";
|
||||
if (!data.education_detail) newErrors.education_detail = "Required";
|
||||
if (!data.employee_type) newErrors.employee_type = "Required";
|
||||
|
||||
if (!isUnemployed) {
|
||||
if (!data.occupation) newErrors.occupation = "Required";
|
||||
if (!data.occupation_detail) newErrors.occupation_detail = "Required";
|
||||
if (!data.income_currency) newErrors.income_currency = "Required";
|
||||
if (!data.annual_income) newErrors.annual_income = "Required";
|
||||
if (!data.work_country) newErrors.work_country = "Required";
|
||||
|
||||
if (isIndia) {
|
||||
if (!data.work_state) newErrors.work_state = "Required";
|
||||
if (!data.work_district) newErrors.work_district = "Required";
|
||||
} else {
|
||||
if (!data.work_city) newErrors.work_city = "Required";
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.address) newErrors.address = "Required";
|
||||
|
||||
setLocalErrors(newErrors);
|
||||
return newErrors;
|
||||
};
|
||||
|
||||
const scrollToError = (errorMap) => {
|
||||
const errorFields = Object.keys(errorMap);
|
||||
if (errorFields.length > 0) {
|
||||
const fieldId = errorFields[0];
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
setTimeout(() => {
|
||||
const focusable = element.querySelector('[role="combobox"]') ||
|
||||
element.querySelector('[role="button"]') ||
|
||||
element.querySelector("input") ||
|
||||
element.querySelector("select") ||
|
||||
element;
|
||||
if (focusable && typeof focusable.focus === "function") {
|
||||
focusable.focus();
|
||||
}
|
||||
}, 300); // Reduced delay slightly for snappier feel
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log("Submitting educational details:", data);
|
||||
const freshErrors = validateForm();
|
||||
if (Object.keys(freshErrors).length > 0) {
|
||||
toast.error("Please fill all mandatory fields");
|
||||
scrollToError(freshErrors);
|
||||
return;
|
||||
}
|
||||
onSubmitStep();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
||||
<form noValidate autoComplete="off" style={{ padding: 16 }}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-20 gap-y-10 mb-6">
|
||||
{/* Field of Study */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Field of Study{requiredMark}
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.fieldOfStudy)}
|
||||
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
||||
<form noValidate autoComplete="off" style={{ padding: 16 }}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-20 gap-y-10 mb-6">
|
||||
{/* 1. Field of Study */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Field of Study{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.study_field)} id="study_field">
|
||||
<InputLabel>Select Field of Study</InputLabel>
|
||||
<Select
|
||||
value={data.study_field}
|
||||
label="Select Field of Study"
|
||||
onChange={(e) => handleChange("study_field", e.target.value)}
|
||||
>
|
||||
<InputLabel id="fieldOfStudy-label">
|
||||
Select Field of Study
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="fieldOfStudy-label"
|
||||
label="Select Field of Study"
|
||||
name="fieldOfStudy"
|
||||
value={data.fieldOfStudy}
|
||||
onChange={(e) => handleChange("fieldOfStudy", e.target.value)}
|
||||
inputRef={inputRef}
|
||||
disabled={isEducationMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{studyFieldOptions.map((field) => (
|
||||
<MenuItem key={field.id ?? field} value={field.id ?? field}>
|
||||
{getOptionLabel(field, "Field of Study")}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.fieldOfStudy && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.fieldOfStudy}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Highest Qualification */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Highest Educational Qualification{requiredMark}
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.qualification)}
|
||||
>
|
||||
<InputLabel id="qualification-label">
|
||||
Select Highest Qualification
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="qualification-label"
|
||||
label="Select Highest Qualification"
|
||||
name="qualification"
|
||||
value={data.qualification}
|
||||
onChange={(e) => handleChange("qualification", e.target.value)}
|
||||
disabled={
|
||||
!data.fieldOfStudy || educationListQuery.isLoading
|
||||
}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{qualificationOptions.map((item) => (
|
||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
||||
{getOptionLabel(item, "Qualification")}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.qualification && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.qualification}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* College Name */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
College Name
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="collegeName"
|
||||
label="College Name"
|
||||
value={data.collegeName}
|
||||
onChange={(e) => handleChange("collegeName", e.target.value)}
|
||||
error={Boolean(errors.collegeName)}
|
||||
helperText={errors.collegeName}
|
||||
placeholder="Enter College Name"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Occupation */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Occupation
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.occupation)}
|
||||
>
|
||||
<InputLabel id="occupation-label">Select Occupation</InputLabel>
|
||||
<Select
|
||||
labelId="occupation-label"
|
||||
label="Select Occupation"
|
||||
name="occupation"
|
||||
value={data.occupation}
|
||||
onChange={(e) => handleChange("occupation", e.target.value)}
|
||||
disabled={isEducationMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{occupationOptions.map((item) => (
|
||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
||||
{getOptionLabel(item, "Occupation")}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.occupation && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.occupation}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Company / Organization Name */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Company / Organization Name
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="organization"
|
||||
label="Company / Organization Name"
|
||||
value={data.organization}
|
||||
onChange={(e) => handleChange("organization", e.target.value)}
|
||||
error={Boolean(errors.organization)}
|
||||
helperText={errors.organization}
|
||||
placeholder="Enter Company / Organization Name"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Employee Type */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Employee Type
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.employeeType)}
|
||||
>
|
||||
<InputLabel id="employeeType-label">
|
||||
Select Employee Type
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="employeeType-label"
|
||||
label="Select Employee Type"
|
||||
name="employeeType"
|
||||
value={data.employeeType}
|
||||
onChange={(e) => handleChange("employeeType", e.target.value)}
|
||||
disabled={isEducationMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{employeeTypeOptions.map((item) => (
|
||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
||||
{getOptionLabel(item, "Employee Type")}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.employeeType && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.employeeType}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Annual Income */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Annual Income
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.income)}
|
||||
>
|
||||
<InputLabel id="income-label">Select Annual Income</InputLabel>
|
||||
<Select
|
||||
labelId="income-label"
|
||||
label="Select Annual Income"
|
||||
name="income"
|
||||
value={data.income}
|
||||
onChange={(e) => handleChange("income", e.target.value)}
|
||||
disabled={isEducationMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{annualIncomeOptions.map((item) => (
|
||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
||||
{getOptionLabel(item, "Annual Income")}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.income && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.income}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Work Location */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Work Location
|
||||
</label>
|
||||
{workLocationOptions.length > 0 ? (
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.workLocation)}
|
||||
>
|
||||
<InputLabel id="workLocation-label">
|
||||
Select Work Location
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="workLocation-label"
|
||||
label="Select Work Location"
|
||||
name="workLocation"
|
||||
value={data.workLocation}
|
||||
onChange={(e) =>
|
||||
handleChange("workLocation", e.target.value)
|
||||
}
|
||||
disabled={isEducationMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{workLocationOptions.map((item) => (
|
||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
||||
{getOptionLabel(item, "Work Location")}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.workLocation && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.workLocation}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
) : (
|
||||
<TextField
|
||||
fullWidth
|
||||
name="workLocation"
|
||||
label="Work Location"
|
||||
value={data.workLocation}
|
||||
onChange={(e) => handleChange("workLocation", e.target.value)}
|
||||
error={Boolean(errors.workLocation)}
|
||||
helperText={errors.workLocation}
|
||||
placeholder="Enter Work Location"
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{studyFieldOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.study_field_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.study_field && <FormHelperText>{localErrors.study_field}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
style={{
|
||||
marginTop: "40px",
|
||||
display: "flex",
|
||||
gap: 16,
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{onSkipStep && (
|
||||
<Button variant="outlined" onClick={onSkipStep}>
|
||||
Skip
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="contained" color="primary" onClick={handleSubmit}>
|
||||
{onSkipStep ? "Next" : "Update"}
|
||||
{/* 2. Highest Qualification */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Highest Qualification{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.education)} id="education" disabled={!data.study_field || educationListQuery.isLoading}>
|
||||
<InputLabel>Select Qualification</InputLabel>
|
||||
<Select
|
||||
value={data.education}
|
||||
label="Select Qualification"
|
||||
onChange={(e) => handleChange("education", e.target.value)}
|
||||
>
|
||||
{qualificationOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.education_name || opt.name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.education && <FormHelperText>{localErrors.education}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* 3. Education in Detail */}
|
||||
<div className="flex flex-col gap-2 md:col-span-2">
|
||||
<label className="text-gray-900 text-[15px]">Education in Detail{requiredMark}</label>
|
||||
<TextField
|
||||
id="education_detail"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
placeholder="Enter your education details"
|
||||
value={data.education_detail}
|
||||
onChange={(e) => handleChange("education_detail", e.target.value)}
|
||||
error={Boolean(localErrors.education_detail)}
|
||||
helperText={localErrors.education_detail}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 4. College Name */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Enter College Name</label>
|
||||
<TextField
|
||||
id="college_name"
|
||||
fullWidth
|
||||
placeholder="Enter College Name"
|
||||
value={data.college_name}
|
||||
onChange={(e) => handleChange("college_name", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 5. Employee Type */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Employee type{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.employee_type)} id="employee_type">
|
||||
<InputLabel>Select Employee Type</InputLabel>
|
||||
<Select
|
||||
value={data.employee_type}
|
||||
label="Select Employee Type"
|
||||
onChange={(e) => handleChange("employee_type", e.target.value)}
|
||||
>
|
||||
{employeeTypeOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.employee_type_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.employee_type && <FormHelperText>{localErrors.employee_type}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{!isUnemployed && (
|
||||
<>
|
||||
{/* 6. Occupation */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Occupation{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.occupation)} id="occupation">
|
||||
<InputLabel>Select Occupation</InputLabel>
|
||||
<Select
|
||||
value={data.occupation}
|
||||
label="Select Occupation"
|
||||
onChange={(e) => handleChange("occupation", e.target.value)}
|
||||
>
|
||||
{occupationOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.occupation_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.occupation && <FormHelperText>{localErrors.occupation}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* 7. Occupation in Detail */}
|
||||
<div className="flex flex-col gap-2 md:col-span-2">
|
||||
<label className="text-gray-900 text-[15px]">Occupation in Detail{requiredMark}</label>
|
||||
<TextField
|
||||
id="occupation_detail"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
placeholder="Enter your occupation details"
|
||||
value={data.occupation_detail}
|
||||
onChange={(e) => handleChange("occupation_detail", e.target.value)}
|
||||
error={Boolean(localErrors.occupation_detail)}
|
||||
helperText={localErrors.occupation_detail}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 8. Company / Organization Name */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Company / Organization Name</label>
|
||||
<TextField
|
||||
id="company_name"
|
||||
fullWidth
|
||||
placeholder="Enter Company Name"
|
||||
value={data.company_name}
|
||||
onChange={(e) => handleChange("company_name", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 9. Income Currency Type */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Income Currency Type{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.income_currency)} id="income_currency">
|
||||
<InputLabel>Select Currency</InputLabel>
|
||||
<Select
|
||||
value={data.income_currency}
|
||||
label="Select Currency"
|
||||
onChange={(e) => handleChange("income_currency", e.target.value)}
|
||||
>
|
||||
<MenuItem value="INR">INR</MenuItem>
|
||||
<MenuItem value="USD">USD</MenuItem>
|
||||
</Select>
|
||||
{localErrors.income_currency && <FormHelperText>{localErrors.income_currency}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* 10. Annual Income */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Annual Income{requiredMark}</label>
|
||||
<TextField
|
||||
id="annual_income"
|
||||
fullWidth
|
||||
placeholder="Enter Annual Income"
|
||||
value={data.annual_income}
|
||||
onChange={(e) => handleChange("annual_income", e.target.value)}
|
||||
error={Boolean(localErrors.annual_income)}
|
||||
helperText={localErrors.annual_income}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
{data.income_currency === "USD" ? "$" : "₹"}
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 11. Country */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Country{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.work_country)} id="work_country">
|
||||
<InputLabel>Select Country</InputLabel>
|
||||
<Select
|
||||
value={data.work_country}
|
||||
label="Select Country"
|
||||
onChange={(e) => handleChange("work_country", e.target.value)}
|
||||
>
|
||||
{countryOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.country_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.work_country && <FormHelperText>{localErrors.work_country}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* 12. City/Town (Only if NOT India) */}
|
||||
{!isIndia && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">City / Town{requiredMark}</label>
|
||||
<TextField
|
||||
id="work_city"
|
||||
fullWidth
|
||||
placeholder="Enter City / Town"
|
||||
value={data.work_city}
|
||||
onChange={(e) => handleChange("work_city", e.target.value)}
|
||||
error={Boolean(localErrors.work_city)}
|
||||
helperText={localErrors.work_city}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 13. State (Only if India) */}
|
||||
{isIndia && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">State{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.work_state)} id="work_state">
|
||||
<InputLabel>Select State</InputLabel>
|
||||
<Select
|
||||
value={data.work_state}
|
||||
label="Select State"
|
||||
onChange={(e) => handleChange("work_state", e.target.value)}
|
||||
>
|
||||
{stateOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.state_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.work_state && <FormHelperText>{localErrors.work_state}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 14. City (District) (Only if India) */}
|
||||
{isIndia && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">City{requiredMark}</label>
|
||||
<FormControl fullWidth error={Boolean(localErrors.work_district)} id="work_district" disabled={!data.work_state || districtQuery.isLoading}>
|
||||
<InputLabel>Select City</InputLabel>
|
||||
<Select
|
||||
value={data.work_district}
|
||||
label="Select City"
|
||||
onChange={(e) => handleChange("work_district", e.target.value)}
|
||||
>
|
||||
{districtOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.district_name || opt.name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.work_district && <FormHelperText>{localErrors.work_district}</FormHelperText>}
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 15. Address */}
|
||||
<div className="flex flex-col gap-2 md:col-span-2">
|
||||
<label className="text-gray-900 text-[15px]">Address{requiredMark}</label>
|
||||
<TextField
|
||||
id="address"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={2}
|
||||
placeholder="Enter your address"
|
||||
value={data.address}
|
||||
onChange={(e) => handleChange("address", e.target.value)}
|
||||
error={Boolean(localErrors.address)}
|
||||
helperText={localErrors.address}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Box sx={{ mt: 5, display: "flex", gap: 2, justifyContent: "center" }}>
|
||||
{onSkipStep && (
|
||||
<Button variant="outlined" size="large" onClick={onSkipStep} sx={{ minWidth: 120 }}>
|
||||
Skip
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Button variant="contained" size="large" onClick={handleSubmit} sx={{ minWidth: 120 }}>
|
||||
{onSkipStep ? "Next" : "Update"}
|
||||
</Button>
|
||||
</Box>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+284
-155
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useMemo, useRef } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { updateFamilyDetails } from "../redux/registrationFormSlice";
|
||||
import { updateFamilyDetails, clearAllStepsFrom } from "../redux/registrationFormSlice";
|
||||
import {
|
||||
Grid,
|
||||
TextField,
|
||||
@@ -12,46 +12,55 @@ import {
|
||||
Box,
|
||||
} from "@mui/material";
|
||||
import { useFamilyMasters } from "../hooks/useMasters";
|
||||
import { useCityMasters } from "../hooks/useDependentMasters";
|
||||
import { toast } from "react-hot-toast";
|
||||
|
||||
const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange }) => {
|
||||
const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange, isEditMode }) => {
|
||||
const dispatch = useDispatch();
|
||||
const data = useSelector((state) => state.registerform.familyDetails);
|
||||
const inputRef = useRef(null);
|
||||
const brotherSectionRef = useRef(null);
|
||||
const sisterSectionRef = useRef(null);
|
||||
const requiredMark = <span style={{ color: "#d32f2f" }}> *</span>;
|
||||
|
||||
const { data: familyMasters, isLoading: isFamilyMastersLoading } =
|
||||
useFamilyMasters();
|
||||
const { data: familyMasters, isLoading: isFamilyMastersLoading } = useFamilyMasters();
|
||||
|
||||
// District query for India
|
||||
const districtQuery = useCityMasters(data.familyState);
|
||||
|
||||
const occupationOptions = useMemo(() => {
|
||||
const raw = familyMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.occupation || raw.occupations || [];
|
||||
return raw.occupation || [];
|
||||
}, [familyMasters]);
|
||||
|
||||
const maritalStatusOptions = useMemo(() => {
|
||||
const raw = familyMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.maritalStatus || raw.marital_status || [];
|
||||
return raw.maritalStatus || [];
|
||||
}, [familyMasters]);
|
||||
|
||||
const familyStatusOptions = useMemo(() => {
|
||||
const raw = familyMasters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return [];
|
||||
return raw.familyStatus || raw.family_status || [];
|
||||
return raw.familyStatus || [];
|
||||
}, [familyMasters]);
|
||||
|
||||
const countryOptions = useMemo(() => familyMasters?.country || [], [familyMasters]);
|
||||
const stateOptions = useMemo(() => familyMasters?.state || [], [familyMasters]);
|
||||
const districtOptions = useMemo(() => districtQuery.data?.districts || districtQuery.data || [], [districtQuery.data]);
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const createSibling = () => ({
|
||||
type: "",
|
||||
name: "",
|
||||
occupation: "",
|
||||
maritalStatus: "",
|
||||
haveChildrens: "",
|
||||
hasChildren: "",
|
||||
details: "",
|
||||
});
|
||||
|
||||
const syncSiblingArray = (arr, count) => {
|
||||
@@ -72,20 +81,48 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
|
||||
if (field === "brotherCount") {
|
||||
const count = Number(value) || 0;
|
||||
updates.brotherCount = count;
|
||||
updates.brotherCount = value;
|
||||
updates.brothers = syncSiblingArray(data.brothers, count);
|
||||
fieldsToClear.push("brothers");
|
||||
if (count > 0) {
|
||||
setTimeout(() => {
|
||||
brotherSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
const firstInput = brotherSectionRef.current?.querySelector('.first-sibling-name');
|
||||
if (firstInput) firstInput.focus();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
if (field === "sisterCount") {
|
||||
const count = Number(value) || 0;
|
||||
updates.sisterCount = count;
|
||||
updates.sisterCount = value;
|
||||
updates.sisters = syncSiblingArray(data.sisters, count);
|
||||
fieldsToClear.push("sisters");
|
||||
if (count > 0) {
|
||||
setTimeout(() => {
|
||||
sisterSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
const firstInput = sisterSectionRef.current?.querySelector('.first-sibling-name');
|
||||
if (firstInput) firstInput.focus();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
if (field === "familyCountry") {
|
||||
updates.familyState = "";
|
||||
updates.familyDistrict = "";
|
||||
updates.familyCity = "";
|
||||
}
|
||||
|
||||
if (field === "familyState") {
|
||||
updates.familyDistrict = "";
|
||||
}
|
||||
|
||||
dispatch(updateFamilyDetails(updates));
|
||||
if (onFieldChange) onFieldChange(fieldsToClear);
|
||||
|
||||
if (!isEditMode) {
|
||||
dispatch(clearAllStepsFrom(4));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSiblingChange = (type, index, field, value) => {
|
||||
@@ -94,14 +131,40 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
list[index] = { ...list[index], [field]: value };
|
||||
dispatch(updateFamilyDetails({ [type]: list }));
|
||||
if (onFieldChange) onFieldChange(type);
|
||||
|
||||
if (!isEditMode) {
|
||||
dispatch(clearAllStepsFrom(4));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log("Submitting family details:", data);
|
||||
const scrollToError = (errorMap) => {
|
||||
const errorFields = Object.keys(errorMap);
|
||||
if (errorFields.length > 0) {
|
||||
const fieldId = errorFields[0];
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
setTimeout(() => {
|
||||
const focusable = element.querySelector('[role="combobox"]') ||
|
||||
element.querySelector('[role="button"]') ||
|
||||
element.querySelector("input") ||
|
||||
element.querySelector("select") ||
|
||||
element;
|
||||
if (focusable && typeof focusable.focus === "function") {
|
||||
focusable.focus();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
if (e) e.preventDefault();
|
||||
onSubmitStep();
|
||||
};
|
||||
|
||||
const countOptions = Array.from({ length: 11 }, (_, i) => i);
|
||||
const isIndia = Number(data.familyCountry) === 1;
|
||||
|
||||
const renderSiblingCard = (type, index) => {
|
||||
const sibling = (data[type] || [])[index] || createSibling();
|
||||
@@ -114,95 +177,88 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
borderRadius: 2,
|
||||
padding: 2,
|
||||
backgroundColor: "#fff",
|
||||
mb: 4
|
||||
}}
|
||||
>
|
||||
<div className="text-gray-900 text-[14px] font-semibold mb-3">
|
||||
{labelPrefix} {index + 1}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-4">
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel>Type</InputLabel>
|
||||
<Select
|
||||
label="Type"
|
||||
value={sibling.type}
|
||||
onChange={(e) => handleSiblingChange(type, index, "type", e.target.value)}
|
||||
>
|
||||
<MenuItem value=""><em>Select</em></MenuItem>
|
||||
<MenuItem value="Elder">Elder</MenuItem>
|
||||
<MenuItem value="Younger">Younger</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Name"
|
||||
placeholder="Enter Name"
|
||||
value={sibling.name}
|
||||
onChange={(e) =>
|
||||
handleSiblingChange(type, index, "name", e.target.value)
|
||||
}
|
||||
onChange={(e) => handleSiblingChange(type, index, "name", e.target.value)}
|
||||
variant="outlined"
|
||||
inputProps={{ className: index === 0 ? "first-sibling-name" : "" }}
|
||||
/>
|
||||
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id={`${type}-${index}-occupation-label`}>
|
||||
Occupation
|
||||
</InputLabel>
|
||||
<InputLabel>Occupation</InputLabel>
|
||||
<Select
|
||||
labelId={`${type}-${index}-occupation-label`}
|
||||
label="Occupation"
|
||||
value={sibling.occupation}
|
||||
onChange={(e) =>
|
||||
handleSiblingChange(type, index, "occupation", e.target.value)
|
||||
}
|
||||
disabled={isFamilyMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
onChange={(e) => handleSiblingChange(type, index, "occupation", e.target.value)}
|
||||
>
|
||||
<MenuItem value=""><em>Select</em></MenuItem>
|
||||
{occupationOptions.map((opt) => (
|
||||
<MenuItem key={opt} value={opt}>
|
||||
{opt}
|
||||
</MenuItem>
|
||||
<MenuItem key={opt} value={opt}>{opt}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id={`${type}-${index}-marital-label`}>
|
||||
Marital Status
|
||||
</InputLabel>
|
||||
<InputLabel>Marital Status</InputLabel>
|
||||
<Select
|
||||
labelId={`${type}-${index}-marital-label`}
|
||||
label="Marital Status"
|
||||
value={sibling.maritalStatus}
|
||||
onChange={(e) =>
|
||||
handleSiblingChange(type, index, "maritalStatus", e.target.value)
|
||||
}
|
||||
disabled={isFamilyMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
onChange={(e) => handleSiblingChange(type, index, "maritalStatus", e.target.value)}
|
||||
>
|
||||
<MenuItem value=""><em>Select</em></MenuItem>
|
||||
{maritalStatusOptions.map((opt) => (
|
||||
<MenuItem key={opt} value={opt}>
|
||||
{opt}
|
||||
</MenuItem>
|
||||
<MenuItem key={opt} value={opt}>{opt}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id={`${type}-${index}-children-label`}>
|
||||
Have Children
|
||||
</InputLabel>
|
||||
<InputLabel>Have Children</InputLabel>
|
||||
<Select
|
||||
labelId={`${type}-${index}-children-label`}
|
||||
label="Have Children"
|
||||
value={sibling.haveChildrens}
|
||||
onChange={(e) =>
|
||||
handleSiblingChange(
|
||||
type,
|
||||
index,
|
||||
"haveChildrens",
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
value={sibling.hasChildren}
|
||||
onChange={(e) => handleSiblingChange(type, index, "hasChildren", e.target.value)}
|
||||
>
|
||||
<MenuItem value={1}>Yes</MenuItem>
|
||||
<MenuItem value={0}>No</MenuItem>
|
||||
<MenuItem value=""><em>Select</em></MenuItem>
|
||||
<MenuItem value="Yes">Yes</MenuItem>
|
||||
<MenuItem value="No">No</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={2}
|
||||
label="Additional Details"
|
||||
value={sibling.details}
|
||||
onChange={(e) => handleSiblingChange(type, index, "details", e.target.value)}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
@@ -212,20 +268,18 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
||||
<form noValidate autoComplete="off" style={{ padding: 16 }}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-20 gap-y-10 mb-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-4" id="fatherName">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Father Name{requiredMark}
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
inputRef={inputRef}
|
||||
name="fatherName"
|
||||
label="Father Name"
|
||||
placeholder="Enter Father Name"
|
||||
value={data.fatherName}
|
||||
onChange={(e) => handleChange("fatherName", e.target.value)}
|
||||
error={Boolean(errors.fatherName)}
|
||||
helperText={errors.fatherName}
|
||||
placeholder="Enter Father Name"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
@@ -236,30 +290,24 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="fatherOccupation"
|
||||
label="Father Occupation"
|
||||
placeholder="Enter Father Occupation"
|
||||
value={data.fatherOccupation}
|
||||
onChange={(e) => handleChange("fatherOccupation", e.target.value)}
|
||||
error={Boolean(errors.fatherOccupation)}
|
||||
helperText={errors.fatherOccupation}
|
||||
placeholder="Enter Father Occupation"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-4" id="motherName">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Mother Name{requiredMark}
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="motherName"
|
||||
label="Mother Name"
|
||||
placeholder="Enter Mother Name"
|
||||
value={data.motherName}
|
||||
onChange={(e) => handleChange("motherName", e.target.value)}
|
||||
error={Boolean(errors.motherName)}
|
||||
helperText={errors.motherName}
|
||||
placeholder="Enter Mother Name"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
@@ -270,13 +318,9 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="motherOccupation"
|
||||
label="Mother Occupation"
|
||||
placeholder="Enter Mother Occupation"
|
||||
value={data.motherOccupation}
|
||||
onChange={(e) => handleChange("motherOccupation", e.target.value)}
|
||||
error={Boolean(errors.motherOccupation)}
|
||||
helperText={errors.motherOccupation}
|
||||
placeholder="Enter Mother Occupation"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
@@ -286,14 +330,13 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
Brother Count
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id="brotherCount-label">Select Brother Count</InputLabel>
|
||||
<InputLabel>Select Brother Count</InputLabel>
|
||||
<Select
|
||||
labelId="brotherCount-label"
|
||||
label="Select Brother Count"
|
||||
name="brotherCount"
|
||||
value={data.brotherCount}
|
||||
onChange={(e) => handleChange("brotherCount", e.target.value)}
|
||||
>
|
||||
<MenuItem value=""><em>Select</em></MenuItem>
|
||||
{countOptions.map((count) => (
|
||||
<MenuItem key={count} value={count}>
|
||||
{count}
|
||||
@@ -303,19 +346,27 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{Number(data.brotherCount) > 0 && (
|
||||
<div className="md:col-span-2 mt-2" ref={brotherSectionRef}>
|
||||
<div className="text-gray-900 text-[16px] font-semibold mb-3">
|
||||
Brother Details
|
||||
</div>
|
||||
{data.brothers.map((_, i) => renderSiblingCard("brothers", i))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Sister Count
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id="sisterCount-label">Select Sister Count</InputLabel>
|
||||
<InputLabel>Select Sister Count</InputLabel>
|
||||
<Select
|
||||
labelId="sisterCount-label"
|
||||
label="Select Sister Count"
|
||||
name="sisterCount"
|
||||
value={data.sisterCount}
|
||||
onChange={(e) => handleChange("sisterCount", e.target.value)}
|
||||
>
|
||||
<MenuItem value=""><em>Select</em></MenuItem>
|
||||
{countOptions.map((count) => (
|
||||
<MenuItem key={count} value={count}>
|
||||
{count}
|
||||
@@ -325,105 +376,183 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
{Number(data.sisterCount) > 0 && (
|
||||
<div className="md:col-span-2 mt-2" ref={sisterSectionRef}>
|
||||
<div className="text-gray-900 text-[16px] font-semibold mb-3">
|
||||
Sister Details
|
||||
</div>
|
||||
{data.sisters.map((_, i) => renderSiblingCard("sisters", i))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-4" id="familyStatus">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Family Status{requiredMark}
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.familyStatus)}
|
||||
>
|
||||
<InputLabel id="familyStatus-label">Select Family Status</InputLabel>
|
||||
<FormControl fullWidth variant="outlined" error={Boolean(errors.familyStatus)}>
|
||||
<InputLabel>Select Family Status</InputLabel>
|
||||
<Select
|
||||
labelId="familyStatus-label"
|
||||
label="Select Family Status"
|
||||
name="familyStatus"
|
||||
value={data.familyStatus}
|
||||
onChange={(e) => handleChange("familyStatus", e.target.value)}
|
||||
disabled={isFamilyMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{familyStatusOptions.map((item) => (
|
||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
||||
{item.family_type_name || item.name || item}
|
||||
<MenuItem key={item.id} value={item.id}>
|
||||
{item.family_type_name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.familyStatus && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.familyStatus}
|
||||
</p>
|
||||
<p className="text-[#d32f2f] text-[0.75rem] mt-1 ml-3">{errors.familyStatus}</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">Native Place</label>
|
||||
<div className="flex flex-col gap-4" id="nativePlace">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Native Place{requiredMark}
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="nativePlace"
|
||||
label="Native Place"
|
||||
placeholder="Enter Native Place"
|
||||
value={data.nativePlace}
|
||||
onChange={(e) => handleChange("nativePlace", e.target.value)}
|
||||
error={Boolean(errors.nativePlace)}
|
||||
helperText={errors.nativePlace}
|
||||
placeholder="Enter Native Place"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Country Living
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel>Select Country</InputLabel>
|
||||
<Select
|
||||
label="Select Country"
|
||||
value={data.familyCountry}
|
||||
onChange={(e) => handleChange("familyCountry", e.target.value)}
|
||||
>
|
||||
{countryOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.country_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{isIndia ? (
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Residing State
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined" disabled={!data.familyCountry}>
|
||||
<InputLabel>Select State</InputLabel>
|
||||
<Select
|
||||
label="Select State"
|
||||
value={data.familyState}
|
||||
onChange={(e) => handleChange("familyState", e.target.value)}
|
||||
>
|
||||
{stateOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.state_name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Residing City
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined" disabled={!data.familyState || districtQuery.isLoading}>
|
||||
<InputLabel>Select City</InputLabel>
|
||||
<Select
|
||||
label="Select City"
|
||||
value={data.familyDistrict}
|
||||
onChange={(e) => handleChange("familyDistrict", e.target.value)}
|
||||
>
|
||||
{districtOptions.map((opt) => (
|
||||
<MenuItem key={opt.id} value={opt.id}>{opt.district_name || opt.name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
</>
|
||||
) : data.familyCountry ? (
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
City / Town
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
placeholder="Enter City / Town"
|
||||
value={data.familyCity}
|
||||
onChange={(e) => handleChange("familyCity", e.target.value)}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex flex-col gap-4 md:col-span-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Address
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
placeholder="Enter complete address"
|
||||
value={data.address}
|
||||
onChange={(e) => handleChange("address", e.target.value)}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4 md:col-span-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Expectations / Requirements Details
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
placeholder="Describe your expectations"
|
||||
value={data.expectationDetails}
|
||||
onChange={(e) => handleChange("expectationDetails", e.target.value)}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Willing to go abroad
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel>Select Option</InputLabel>
|
||||
<Select
|
||||
label="Select Option"
|
||||
value={data.willingToGoAbroad}
|
||||
onChange={(e) => handleChange("willingToGoAbroad", e.target.value)}
|
||||
>
|
||||
<MenuItem value="Yes">Yes</MenuItem>
|
||||
<MenuItem value="No">No</MenuItem>
|
||||
<MenuItem value="Any">Any</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{Number(data.brotherCount) > 0 && (
|
||||
<div className="mt-6">
|
||||
<div className="text-gray-900 text-[16px] font-semibold mb-3">
|
||||
Brother Details
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{Array.from({ length: Number(data.brotherCount) }).map(
|
||||
(_, index) => renderSiblingCard("brothers", index)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{Number(data.sisterCount) > 0 && (
|
||||
<div className="mt-6">
|
||||
<div className="text-gray-900 text-[16px] font-semibold mb-3">
|
||||
Sister Details
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{Array.from({ length: Number(data.sisterCount) }).map(
|
||||
(_, index) => renderSiblingCard("sisters", index)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{ marginTop: 10, display: "flex", gap: 4, justifyContent: "center" }}
|
||||
>
|
||||
<div className="mt-10 flex gap-4 justify-center">
|
||||
{onSkipStep && (
|
||||
<Button variant="outlined" onClick={onSkipStep}>
|
||||
<Button variant="outlined" onClick={onSkipStep} sx={{ minWidth: 120 }}>
|
||||
Skip
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="contained" color="primary" onClick={handleSubmit}>
|
||||
{onSkipStep ? "Next" : "Update"}
|
||||
<Button variant="contained" color="primary" onClick={handleSubmit} sx={{ minWidth: 120 }}>
|
||||
{onSkipStep ? "Next" : "Update"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { updateLifestyleDetails } from "../redux/registrationFormSlice";
|
||||
import { updateLifestyleDetails, clearAllStepsFrom } from "../redux/registrationFormSlice";
|
||||
import {
|
||||
Grid,
|
||||
FormControl,
|
||||
@@ -30,6 +30,7 @@ const LifestyleDetailsForm = ({
|
||||
onSkipStep,
|
||||
errors,
|
||||
onFieldChange,
|
||||
isEditMode,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const data = useSelector((state) => state.registerform.lifestyleDetails);
|
||||
@@ -76,6 +77,10 @@ const LifestyleDetailsForm = ({
|
||||
const handleChange = (field, value) => {
|
||||
dispatch(updateLifestyleDetails({ [field]: value }));
|
||||
if (onFieldChange) onFieldChange(field);
|
||||
|
||||
if (!isEditMode) {
|
||||
dispatch(clearAllStepsFrom(5));
|
||||
}
|
||||
};
|
||||
|
||||
const handleMultiChange = (field, value) => {
|
||||
|
||||
+616
-1188
File diff suppressed because it is too large.
Load diff
@@ -397,10 +397,10 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
|
||||
{Object.entries(sibling).map(([sKey, sVal]) => {
|
||||
if (sKey === 'id' || sKey.endsWith('_id') || sKey.endsWith('Id') || sKey === 'created_at' || sKey === 'updated_at') return null;
|
||||
let displayValue = sVal;
|
||||
if (sKey === 'haveChildrens' || sKey === 'have_childrens') {
|
||||
if (sVal === true || sVal === 1 || sVal === '1') {
|
||||
if (sKey === 'haveChildrens' || sKey === 'have_childrens' || sKey === 'hasChildren' || sKey === 'has_children') {
|
||||
if (sVal === true || sVal === 1 || sVal === '1' || sVal === 'Yes') {
|
||||
displayValue = 'Yes';
|
||||
} else if (sVal === false || sVal === 0 || sVal === '0') {
|
||||
} else if (sVal === false || sVal === 0 || sVal === '0' || sVal === 'No') {
|
||||
displayValue = 'No';
|
||||
}
|
||||
}
|
||||
|
||||
+334
-188
@@ -8,6 +8,7 @@ import {
|
||||
updateFamilyDetails,
|
||||
updateLifestyleDetails,
|
||||
updatePartnerPreferences,
|
||||
clearAllStepsFrom,
|
||||
submitForm,
|
||||
} from "../redux/registrationFormSlice";
|
||||
import PersonalDetailsForm from "./PersonalDetailsForm";
|
||||
@@ -31,37 +32,47 @@ import { isAuthenticated } from "../utills/auth";
|
||||
import { getPreviewDetails } from "../api/preview.api";
|
||||
const STEP_FIELD_ORDER = {
|
||||
1: [
|
||||
"name",
|
||||
"profile_for",
|
||||
"gender",
|
||||
"mobileNumber",
|
||||
"dob",
|
||||
"height",
|
||||
"weight",
|
||||
"maritalStatus",
|
||||
"religion",
|
||||
"profileFor",
|
||||
"caste",
|
||||
"subCaste",
|
||||
"gothram",
|
||||
"raasi",
|
||||
"star",
|
||||
"name",
|
||||
"mobile",
|
||||
"email",
|
||||
"password",
|
||||
"confirmPassword",
|
||||
"state",
|
||||
"city",
|
||||
"pincode",
|
||||
"marital_status",
|
||||
"height",
|
||||
"weight",
|
||||
"complexion",
|
||||
"physical_status",
|
||||
"religion",
|
||||
"caste",
|
||||
"sub_caste",
|
||||
"willing_to_marry",
|
||||
"inter_caste_parents",
|
||||
"inter_caste_parents_details",
|
||||
"gothram",
|
||||
"do_you_speak_telugu",
|
||||
"about_us",
|
||||
"known_languages",
|
||||
"mother_language",
|
||||
"profiles",
|
||||
],
|
||||
2: [
|
||||
"fieldOfStudy",
|
||||
"qualification",
|
||||
"collegeName",
|
||||
"study_field",
|
||||
"education",
|
||||
"education_detail",
|
||||
"college_name",
|
||||
"employee_type",
|
||||
"occupation",
|
||||
"organization",
|
||||
"employeeType",
|
||||
"income",
|
||||
"workLocation",
|
||||
"occupation_detail",
|
||||
"company_name",
|
||||
"income_currency",
|
||||
"annual_income",
|
||||
"work_country",
|
||||
"work_city",
|
||||
"work_state",
|
||||
"work_district",
|
||||
"address",
|
||||
],
|
||||
3: [
|
||||
"fatherName",
|
||||
@@ -89,35 +100,29 @@ const STEP_FIELD_ORDER = {
|
||||
|
||||
const STEP1_SERVER_FIELD_MAP = {
|
||||
name: "name",
|
||||
mobile: "mobileNumber",
|
||||
mobile_number: "mobileNumber",
|
||||
mobileNumber: "mobileNumber",
|
||||
phone: "mobileNumber",
|
||||
mobile: "mobile",
|
||||
email: "email",
|
||||
gender: "gender",
|
||||
dob: "dob",
|
||||
height: "height",
|
||||
weight: "weight",
|
||||
marital_status: "maritalStatus",
|
||||
maritalStatus: "maritalStatus",
|
||||
marital_status: "marital_status",
|
||||
religion: "religion",
|
||||
profile_for: "profileFor",
|
||||
profileFor: "profileFor",
|
||||
profile_for: "profile_for",
|
||||
caste: "caste",
|
||||
sub_caste: "subCaste",
|
||||
subCaste: "subCaste",
|
||||
sub_caste: "sub_caste",
|
||||
willing_to_marry: "willing_to_marry",
|
||||
inter_caste_parents: "inter_caste_parents",
|
||||
inter_caste_parents_details: "inter_caste_parents_details",
|
||||
gothram: "gothram",
|
||||
raasi: "raasi",
|
||||
star: "star",
|
||||
state: "state",
|
||||
district: "city",
|
||||
city: "city",
|
||||
pincode: "pincode",
|
||||
do_you_speak_telugu: "do_you_speak_telugu",
|
||||
about_us: "about_us",
|
||||
known_languages: "known_languages",
|
||||
mother_language: "mother_language",
|
||||
complexion: "complexion",
|
||||
physical_status: "physical_status",
|
||||
password: "password",
|
||||
confirm_password: "confirmPassword",
|
||||
confirmPassword: "confirmPassword",
|
||||
profiles: "profiles",
|
||||
profile_images: "profiles",
|
||||
};
|
||||
|
||||
|
||||
@@ -171,8 +176,7 @@ const STEP1_SERVER_FIELD_MAP = {
|
||||
|
||||
import { Check } from "lucide-react";
|
||||
|
||||
const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick }) => {
|
||||
|
||||
const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick, checkStepValidity }) => {
|
||||
const steps = [
|
||||
{ num: 1, label: "Personal" },
|
||||
{ num: 2, label: "Educational" },
|
||||
@@ -183,40 +187,57 @@ const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick }) =>
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between px-4 py-6">
|
||||
<div className="flex items-center justify-between px-4 py-6 overflow-x-auto">
|
||||
{steps.map((step, index) => {
|
||||
const isEnabled = enabledSteps.includes(step.num);
|
||||
const isCompleted = completedSteps.includes(step.num);
|
||||
const isSkippable = currentStep > 1 && currentStep < 6 && step.num === currentStep + 1;
|
||||
const isEnabled = enabledSteps.includes(step.num) || isSkippable;
|
||||
const isActive = currentStep === step.num;
|
||||
|
||||
// Dynamic completion check: Green tick if all mandatory fields are filled
|
||||
const isValid = checkStepValidity && checkStepValidity(step.num);
|
||||
const isCompleted = completedSteps.includes(step.num) || isValid;
|
||||
|
||||
// A step is Blue (Skipped) ONLY if it's a previous step and NOT completed
|
||||
const isSkipped = isEnabled && !isCompleted && !isActive && step.num < currentStep;
|
||||
|
||||
return (
|
||||
<React.Fragment key={step.num}>
|
||||
<div
|
||||
className={`flex flex-col items-center ${
|
||||
isEnabled ? "cursor-pointer" : "cursor-not-allowed opacity-50"
|
||||
className={`flex flex-col items-center min-w-[70px] ${
|
||||
isEnabled ? "cursor-pointer" : "cursor-not-allowed opacity-60"
|
||||
}`}
|
||||
onClick={() => isEnabled && onStepClick(step.num)}
|
||||
>
|
||||
<div
|
||||
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold ${
|
||||
className={`w-9 h-9 rounded-full flex items-center justify-center text-sm font-bold transition-all duration-300 ${
|
||||
isCompleted
|
||||
? "bg-green-600 text-white"
|
||||
: currentStep === step.num
|
||||
? "bg-red-600 text-white"
|
||||
: "bg-gray-300 text-gray-600"
|
||||
? "bg-green-600 text-white shadow-md"
|
||||
: isActive
|
||||
? "bg-red-600 text-white ring-4 ring-red-100 shadow-md"
|
||||
: isSkipped
|
||||
? "bg-blue-500 text-white shadow-md"
|
||||
: "bg-gray-200 text-gray-500"
|
||||
}`}
|
||||
>
|
||||
{isCompleted ? <Check size={16} /> : step.num}
|
||||
{isCompleted ? <Check size={18} /> : step.num}
|
||||
</div>
|
||||
|
||||
<span className="text-xs mt-1">{step.label}</span>
|
||||
<span
|
||||
className={`text-[10px] mt-2 font-medium text-center uppercase tracking-wider ${
|
||||
isActive ? "text-red-600 font-bold" : isCompleted ? "text-green-600" : isSkipped ? "text-blue-500" : "text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{step.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{index < steps.length - 1 && (
|
||||
<div
|
||||
className={`flex-1 h-0.5 mx-1 ${
|
||||
completedSteps.includes(step.num)
|
||||
className={`flex-1 h-[2px] mx-1 mb-6 transition-colors duration-500 ${
|
||||
(completedSteps.includes(step.num) || (checkStepValidity && checkStepValidity(step.num)))
|
||||
? "bg-green-600"
|
||||
: "bg-gray-300"
|
||||
: (enabledSteps.includes(step.num) && enabledSteps.includes(step.num + 1))
|
||||
? "bg-blue-300"
|
||||
: "bg-gray-200"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
@@ -255,7 +276,14 @@ const shouldHideStepper = hideStepperRoutes.some((route) => location.pathname.st
|
||||
const savedStep = localStorage.getItem("registration_current_step");
|
||||
return savedStep ? Number(savedStep) : 1;
|
||||
});
|
||||
const [enabledSteps, setEnabledSteps] = useState([1]);
|
||||
const [enabledSteps, setEnabledSteps] = useState(() => {
|
||||
if (location.state?.step) {
|
||||
return Array.from({ length: 6 }, (_, i) => i + 1); // Enable all if coming from edit/preview
|
||||
}
|
||||
const savedStep = localStorage.getItem("registration_current_step");
|
||||
const step = savedStep ? Number(savedStep) : 1;
|
||||
return Array.from({ length: step }, (_, i) => i + 1);
|
||||
});
|
||||
const [completedSteps, setCompletedSteps] = useState([]);
|
||||
const [isStep1Update, setIsStep1Update] = useState(false);
|
||||
const [errors, setErrors] = useState({});
|
||||
@@ -362,24 +390,23 @@ const [completedSteps, setCompletedSteps] = useState([]);
|
||||
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 element = document.getElementById(firstKey) ||
|
||||
document.querySelector(`[name="${firstKey}"]`) ||
|
||||
document.querySelector(`[aria-labelledby~="${firstKey}-label"]`);
|
||||
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
|
||||
// Try to find a focusable element within the container
|
||||
const focusable = element.querySelector('input:not([type="hidden"]), select, textarea, [role="combobox"], [role="button"]') || element;
|
||||
|
||||
if (focusable && typeof focusable.focus === "function") {
|
||||
focusable.focus();
|
||||
}
|
||||
}
|
||||
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);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const clearFieldErrors = (fields) => {
|
||||
@@ -474,18 +501,27 @@ const [completedSteps, setCompletedSteps] = useState([]);
|
||||
dispatch(
|
||||
updatePersonalDetails({
|
||||
name: pd.name || "",
|
||||
mobileNumber: pd.mobile || "",
|
||||
mobile: pd.mobile || "",
|
||||
email: pd.email || "",
|
||||
gender: pd.gender || "",
|
||||
dob: formattedDob,
|
||||
height: pd.height || "",
|
||||
height: pd.height_id || "",
|
||||
weight: pd.weight || "",
|
||||
maritalStatus: pd.marital_status_id || "",
|
||||
marital_status: pd.marital_status_id || "",
|
||||
religion: pd.religion_id || "",
|
||||
profileFor: pd.profile_for_id || "",
|
||||
profile_for: pd.profile_for_id || "",
|
||||
caste: pd.caste_id || "",
|
||||
subCaste: pd.sub_caste_id || "",
|
||||
gothram: pd.gothram_id || "",
|
||||
sub_caste: pd.sub_caste_id || "",
|
||||
willing_to_marry: pd.willing_to_marry || "",
|
||||
inter_caste_parents: pd.inter_caste_parents || 0,
|
||||
inter_caste_parents_details: pd.inter_caste_parents_details || "",
|
||||
gothram: pd.gothram || "",
|
||||
do_you_speak_telugu: pd.do_you_speak_telugu || 0,
|
||||
about_us: pd.about_us || "",
|
||||
known_languages: pd.known_language_ids || [],
|
||||
mother_language: pd.mother_language_id || "",
|
||||
complexion: pd.complexion_id || "",
|
||||
physical_status: pd.physical_status_id || "",
|
||||
raasi: pd.raasi_id || "",
|
||||
star: pd.star_id || "",
|
||||
state: pd.state_id || "",
|
||||
@@ -518,14 +554,21 @@ useEffect(() => {
|
||||
const ed = educationalData.educational_details;
|
||||
dispatch(
|
||||
updateEducationalDetails({
|
||||
fieldOfStudy: ed.study_field_id || "",
|
||||
qualification: ed.education_id || "",
|
||||
collegeName: ed.college_name || "",
|
||||
study_field: ed.study_field_id || "",
|
||||
education: ed.education_id || "",
|
||||
education_detail: ed.education_detail || "",
|
||||
college_name: ed.college_name || "",
|
||||
employee_type: ed.employee_type_id || "",
|
||||
occupation: ed.occupation_id || "",
|
||||
organization: ed.company_name || "",
|
||||
employeeType: ed.employee_type_id || "",
|
||||
income: ed.annual_income_id || "",
|
||||
workLocation: ed.work_location || "",
|
||||
occupation_detail: ed.occupation_detail || "",
|
||||
company_name: ed.company_name || "",
|
||||
income_currency: ed.income_currency || "INR",
|
||||
annual_income: ed.annual_income || "",
|
||||
work_country: ed.work_country_id || "",
|
||||
work_state: ed.work_state_id || "",
|
||||
work_district: ed.work_district_id || "",
|
||||
work_city: ed.work_city || "",
|
||||
address: ed.address || ed.work_location || "",
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -546,41 +589,46 @@ const {data:familyData} = useQuery({
|
||||
});
|
||||
|
||||
|
||||
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])
|
||||
useEffect(() => {
|
||||
if (familyData?.status === "success" && familyData?.family_details) {
|
||||
const fd = familyData.family_details;
|
||||
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 || "",
|
||||
familyCountry: fd.family_country_id || "",
|
||||
familyState: fd.family_state_id || "",
|
||||
familyDistrict: fd.family_district_id || "",
|
||||
familyCity: fd.family_city || "",
|
||||
address: fd.address || "",
|
||||
expectationDetails: fd.expectation_details || "",
|
||||
willingToGoAbroad: fd.willing_to_go_abroad || "",
|
||||
brotherCount: fd.brother_count || 0,
|
||||
sisterCount: fd.sister_count || 0,
|
||||
brothers: (fd.brothers || []).map((b) => ({
|
||||
name: b.name || "",
|
||||
occupation: b.occupation_name || "",
|
||||
maritalStatus: b.marital_status || "",
|
||||
type: b.type || "",
|
||||
hasChildren: b.has_children || "",
|
||||
details: b.additional_details || ""
|
||||
})),
|
||||
sisters: (fd.sisters || []).map((s) => ({
|
||||
name: s.name || "",
|
||||
occupation: s.occupation_name || "",
|
||||
maritalStatus: s.marital_status || "",
|
||||
type: s.type || "",
|
||||
hasChildren: s.has_children || "",
|
||||
details: s.additional_details || ""
|
||||
})),
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [familyData, dispatch]);
|
||||
|
||||
// Fetch Lifestyle Details
|
||||
const { data: lifestyleData } = useQuery({
|
||||
@@ -668,23 +716,24 @@ useEffect(()=>{
|
||||
if (step === 1) {
|
||||
const required = [
|
||||
"name",
|
||||
"mobileNumber",
|
||||
"mobile",
|
||||
"gender",
|
||||
"dob",
|
||||
"height",
|
||||
"maritalStatus",
|
||||
"profileFor",
|
||||
"marital_status",
|
||||
"profile_for",
|
||||
"caste",
|
||||
"email",
|
||||
"state",
|
||||
"city",
|
||||
"pincode",
|
||||
"mother_language",
|
||||
"complexion",
|
||||
"physical_status",
|
||||
"inter_caste_parents",
|
||||
"do_you_speak_telugu",
|
||||
];
|
||||
|
||||
required.forEach((field) => {
|
||||
if (!personalDetails[field]) {
|
||||
if (!personalDetails[field] && personalDetails[field] !== 0) {
|
||||
const label = field
|
||||
.replace(/([A-Z])/g, " $1")
|
||||
.replace(/_/g, " ")
|
||||
.replace(/^./, (str) => str.toUpperCase());
|
||||
newErrors[field] = `${label} is required`;
|
||||
}
|
||||
@@ -702,16 +751,10 @@ useEffect(()=>{
|
||||
newErrors.email = "Invalid email format";
|
||||
}
|
||||
if (
|
||||
personalDetails.mobileNumber &&
|
||||
personalDetails.mobileNumber.length !== 10
|
||||
personalDetails.mobile &&
|
||||
personalDetails.mobile.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";
|
||||
newErrors.mobile = "Mobile number must be 10 digits";
|
||||
}
|
||||
if (
|
||||
personalDetails.password &&
|
||||
@@ -721,16 +764,24 @@ useEffect(()=>{
|
||||
newErrors.confirmPassword = "Passwords do not match";
|
||||
}
|
||||
} else if (step === 2) {
|
||||
const required = [
|
||||
"qualification",
|
||||
"fieldOfStudy",
|
||||
|
||||
|
||||
];
|
||||
const isUnemployed = educationalDetails.employee_type === 11;
|
||||
const isIndia = educationalDetails.work_country === 1;
|
||||
const required = ["study_field", "education", "education_detail", "employee_type"];
|
||||
|
||||
if (!isUnemployed) {
|
||||
required.push("occupation", "occupation_detail", "income_currency", "annual_income", "work_country");
|
||||
if (isIndia) {
|
||||
required.push("work_state", "work_district");
|
||||
} else {
|
||||
required.push("work_city");
|
||||
}
|
||||
}
|
||||
required.push("address");
|
||||
|
||||
required.forEach((field) => {
|
||||
if (!educationalDetails[field]) {
|
||||
const label = field
|
||||
.replace(/([A-Z])/g, " $1")
|
||||
.replace(/_/g, " ")
|
||||
.replace(/^./, (str) => str.toUpperCase());
|
||||
newErrors[field] = `${label} is required`;
|
||||
}
|
||||
@@ -740,6 +791,7 @@ useEffect(()=>{
|
||||
"fatherName",
|
||||
"motherName",
|
||||
"familyStatus",
|
||||
"nativePlace",
|
||||
];
|
||||
required.forEach((field) => {
|
||||
if (!familyDetails[field]) {
|
||||
@@ -836,24 +888,33 @@ useEffect(()=>{
|
||||
const buildRegisterStep1Payload = async () => {
|
||||
const formData = new FormData();
|
||||
formData.append("name", personalDetails.name);
|
||||
formData.append("mobile", personalDetails.mobileNumber);
|
||||
formData.append("mobile", personalDetails.mobile);
|
||||
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("marital_status", personalDetails.marital_status);
|
||||
formData.append("religion", personalDetails.religion);
|
||||
formData.append("profile_for", personalDetails.profileFor || "");
|
||||
formData.append("profile_for", personalDetails.profile_for || "");
|
||||
formData.append("caste", personalDetails.caste);
|
||||
formData.append("sub_caste", personalDetails.subCaste || "");
|
||||
formData.append("sub_caste", personalDetails.sub_caste || "");
|
||||
formData.append("willing_to_marry", personalDetails.willing_to_marry || "");
|
||||
formData.append("inter_caste_parents", personalDetails.inter_caste_parents);
|
||||
formData.append("inter_caste_parents_details", personalDetails.inter_caste_parents_details || "");
|
||||
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("do_you_speak_telugu", personalDetails.do_you_speak_telugu);
|
||||
formData.append("about_us", personalDetails.about_us || "");
|
||||
formData.append("mother_language", personalDetails.mother_language || "");
|
||||
formData.append("complexion", personalDetails.complexion || "");
|
||||
formData.append("physical_status", personalDetails.physical_status || "");
|
||||
|
||||
(personalDetails.known_languages || []).forEach((id, index) => {
|
||||
formData.append(`known_languages[${index}]`, id);
|
||||
});
|
||||
|
||||
if (!isStep1Update) {
|
||||
formData.append("password", personalDetails.password || "");
|
||||
}
|
||||
formData.append("web_fcm_token", localStorage.getItem("fcm_token") || "");
|
||||
|
||||
if (personalDetails.profiles && Array.isArray(personalDetails.profiles)) {
|
||||
@@ -895,14 +956,23 @@ useEffect(()=>{
|
||||
|
||||
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("study_field", educationalDetails.study_field || "");
|
||||
formData.append("education", educationalDetails.education || "");
|
||||
formData.append("education_detail", educationalDetails.education_detail || "");
|
||||
formData.append("college_name", educationalDetails.college_name || "");
|
||||
formData.append("employee_type", educationalDetails.employee_type || "");
|
||||
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 || "");
|
||||
formData.append("occupation_detail", educationalDetails.occupation_detail || "");
|
||||
formData.append("company_name", educationalDetails.company_name || "");
|
||||
formData.append("income_currency", educationalDetails.income_currency || "INR");
|
||||
formData.append("annual_income", educationalDetails.annual_income || "");
|
||||
formData.append("work_country", educationalDetails.work_country || "");
|
||||
formData.append("work_city", educationalDetails.work_city || "");
|
||||
formData.append("work_state", educationalDetails.work_state || "");
|
||||
formData.append("work_district", educationalDetails.work_district || "");
|
||||
formData.append("address", educationalDetails.address || "");
|
||||
// Also append work_location as some APIs might use it for address/city
|
||||
formData.append("work_location", educationalDetails.address || "");
|
||||
return formData;
|
||||
};
|
||||
|
||||
@@ -916,19 +986,30 @@ useEffect(()=>{
|
||||
formData.append("native_place", familyDetails.nativePlace || "");
|
||||
formData.append("brother_count", familyDetails.brotherCount || 0);
|
||||
formData.append("sister_count", familyDetails.sisterCount || 0);
|
||||
formData.append("family_country", familyDetails.familyCountry || "");
|
||||
formData.append("family_state", familyDetails.familyState || "");
|
||||
formData.append("family_district", familyDetails.familyDistrict || "");
|
||||
formData.append("family_city", familyDetails.familyCity || "");
|
||||
formData.append("address", familyDetails.address || "");
|
||||
formData.append("expectation_details", familyDetails.expectationDetails || "");
|
||||
formData.append("willing_to_go_abroad", familyDetails.willingToGoAbroad || "");
|
||||
|
||||
(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 ?? "");
|
||||
formData.append(`brothers[${index}][type]`, brother?.type || "");
|
||||
formData.append(`brothers[${index}][has_children]`, brother?.hasChildren || "");
|
||||
formData.append(`brothers[${index}][details]`, brother?.details || "");
|
||||
});
|
||||
|
||||
(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 ?? "");
|
||||
formData.append(`sisters[${index}][type]`, sister?.type || "");
|
||||
formData.append(`sisters[${index}][has_children]`, sister?.hasChildren || "");
|
||||
formData.append(`sisters[${index}][details]`, sister?.details || "");
|
||||
});
|
||||
|
||||
return formData;
|
||||
@@ -1053,6 +1134,12 @@ useEffect(()=>{
|
||||
|
||||
const token = extractAccessToken(res.data || res);
|
||||
if (token) setAccessToken(token);
|
||||
|
||||
// Store profile_id and user_id for WebSocket channels
|
||||
const profileId = res.data?.profile_id || res?.profile_id || res.data?.data?.profile_id;
|
||||
const userId = res.data?.user_id || res?.user_id || res.data?.data?.user_id;
|
||||
if (profileId) localStorage.setItem("profile_id", profileId);
|
||||
if (userId) localStorage.setItem("user_id", userId);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -1141,29 +1228,43 @@ useEffect(()=>{
|
||||
}
|
||||
};
|
||||
|
||||
const handleSkip = () => {
|
||||
setErrors({});
|
||||
const handleSkip = () => {
|
||||
setErrors({});
|
||||
|
||||
// Remove from completed if skipping (matching Flutter logic)
|
||||
setCompletedSteps((prev) => prev.filter(s => s !== currentStep));
|
||||
|
||||
setCurrentStep((prev) => {
|
||||
const nextStep = Math.min(prev + 1, 6);
|
||||
setCurrentStep((prev) => {
|
||||
const nextStep = Math.min(prev + 1, 6);
|
||||
|
||||
setEnabledSteps((steps) =>
|
||||
steps.includes(nextStep) ? steps : [...steps, nextStep]
|
||||
);
|
||||
setEnabledSteps((steps) =>
|
||||
steps.includes(nextStep) ? steps : [...steps, nextStep]
|
||||
);
|
||||
|
||||
return nextStep;
|
||||
});
|
||||
return nextStep;
|
||||
});
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
|
||||
const handleStepClick = (step) => {
|
||||
if (!enabledSteps.includes(step)) return;
|
||||
const handleStepClick = (step) => {
|
||||
// If clicking next step and current is skippable (not Step 1), trigger handleSkip
|
||||
if (step === currentStep + 1 && currentStep > 1 && currentStep < 6) {
|
||||
handleSkip();
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentStep(step);
|
||||
setErrors({});
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
if (!enabledSteps.includes(step)) return;
|
||||
|
||||
// If moving backwards during registration, clear the unsaved data of the step we are leaving
|
||||
if (step < currentStep && !shouldHideStepper) {
|
||||
dispatch(clearAllStepsFrom(currentStep));
|
||||
}
|
||||
|
||||
setCurrentStep(step);
|
||||
setErrors({});
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (currentStep === 6) {
|
||||
@@ -1203,7 +1304,7 @@ useEffect(() => {
|
||||
onSubmitStep={handleStepSubmit}
|
||||
errors={errors}
|
||||
onFieldChange={clearFieldErrors}
|
||||
isStep1Update={isStep1Update}
|
||||
isEditMode={isStep1Update || shouldHideStepper}
|
||||
/>
|
||||
);
|
||||
case 2:
|
||||
@@ -1213,6 +1314,7 @@ useEffect(() => {
|
||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||
errors={errors}
|
||||
onFieldChange={clearFieldErrors}
|
||||
isEditMode={shouldHideStepper}
|
||||
/>
|
||||
);
|
||||
case 3:
|
||||
@@ -1222,6 +1324,7 @@ useEffect(() => {
|
||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||
errors={errors}
|
||||
onFieldChange={clearFieldErrors}
|
||||
isEditMode={shouldHideStepper}
|
||||
/>
|
||||
);
|
||||
case 4:
|
||||
@@ -1231,6 +1334,7 @@ useEffect(() => {
|
||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||
errors={errors}
|
||||
onFieldChange={clearFieldErrors}
|
||||
isEditMode={shouldHideStepper}
|
||||
/>
|
||||
);
|
||||
case 5:
|
||||
@@ -1240,6 +1344,7 @@ useEffect(() => {
|
||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||
errors={errors}
|
||||
onFieldChange={clearFieldErrors}
|
||||
isEditMode={shouldHideStepper}
|
||||
/>
|
||||
);
|
||||
case 6:
|
||||
@@ -1249,6 +1354,46 @@ useEffect(() => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkStepValidity = (stepNum) => {
|
||||
if (stepNum === 1) {
|
||||
const required = ["name", "mobile", "gender", "height", "marital_status", "profile_for", "caste", "email", "mother_language", "complexion", "physical_status"];
|
||||
return required.every(field => personalDetails[field] || personalDetails[field] === 0);
|
||||
}
|
||||
if (stepNum === 2) {
|
||||
const required = ["study_field", "education", "education_detail", "employee_type", "address"];
|
||||
if (!educationalDetails.study_field || !educationalDetails.education || !educationalDetails.education_detail || !educationalDetails.employee_type || !educationalDetails.address) return false;
|
||||
if (educationalDetails.employee_type !== 11) {
|
||||
const workReq = ["occupation", "occupation_detail", "income_currency", "annual_income", "work_country"];
|
||||
if (!workReq.every(f => educationalDetails[f])) return false;
|
||||
if (educationalDetails.work_country === 1) {
|
||||
if (!educationalDetails.work_state || !educationalDetails.work_district) return false;
|
||||
} else {
|
||||
if (!educationalDetails.work_city) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (stepNum === 3) {
|
||||
const required = ["fatherName", "motherName", "familyStatus", "nativePlace"];
|
||||
return required.every(field => familyDetails[field]);
|
||||
}
|
||||
if (stepNum === 4) {
|
||||
const required = ["diets", "hobbies", "dob", "tob"];
|
||||
return required.every(field => {
|
||||
const val = lifestyleDetails[field];
|
||||
return Array.isArray(val) ? val.length > 0 : !!val;
|
||||
});
|
||||
}
|
||||
if (stepNum === 5) {
|
||||
const required = ["ageRange", "castes", "subCastes", "occupations", "educations", "hobbies", "annualIncome", "states", "districts"];
|
||||
return required.every(field => {
|
||||
const val = partnerPreferences[field];
|
||||
return Array.isArray(val) ? val.length > 0 : !!val;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const getTitle = () => {
|
||||
const titles = {
|
||||
1: "Personal Details",
|
||||
@@ -1272,6 +1417,7 @@ useEffect(() => {
|
||||
onStepClick={handleStepClick}
|
||||
enabledSteps={enabledSteps}
|
||||
completedSteps={completedSteps}
|
||||
checkStepValidity={checkStepValidity}
|
||||
/> )}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user