reg complete

This commit is contained in:
meena committed 2026-03-02 17:02:47 +05:30
1 parent 653055debc
commit 81c014f94c
6 files changed
+225 -193

No files matched your search

+2 -2
View File
@@ -1,11 +1,11 @@
import axiosInstance from "./axiosInstance";
import axiosInstance, { apiForFiles } from "./axiosInstance";
import { API_ENDPOINTS } from "./apiEndpoints";
/**
* STEP 1 – Personal Details
*/
export const registerStep1API = async (payload) => {
const res = await axiosInstance.post(API_ENDPOINTS.REGISTER_STEP1, payload);
const res = await apiForFiles.post(API_ENDPOINTS.REGISTER_STEP1, payload);
return res.data;
};
+4
View File
@@ -17,6 +17,10 @@ const AdvancedDropzone = ({ value, onChange }) => {
const [videoSrc, setVideoSrc] = React.useState(undefined);
const [hoveredId, setHoveredId] = React.useState(null);
React.useEffect(() => {
setExtFiles(value || []);
}, [value]);
const updateFiles = (incomingFiles) => {
console.log("incoming files", incomingFiles);
setExtFiles(incomingFiles);
+10
View File
@@ -372,6 +372,11 @@ const LifestyleDetailsForm = ({
Add Rasi
</h3>
{renderChartGrid("graha")}
{errors.graha_duplicate && (
<p style={{ color: "#d32f2f", fontSize: "0.75rem", marginTop: "4px" }}>
{errors.graha_duplicate}
</p>
)}
</div>
</div>
@@ -381,6 +386,11 @@ const LifestyleDetailsForm = ({
Add Navamsam
</h3>
{renderChartGrid("amsam")}
{errors.amsam_duplicate && (
<p style={{ color: "#d32f2f", fontSize: "0.75rem", marginTop: "4px" }}>
{errors.amsam_duplicate}
</p>
)}
</div>
</div>
</div>
+73 -8
View File
@@ -1,5 +1,10 @@
import React from "react";
import { useSelector } from 'react-redux';
import { Swiper, SwiperSlide } from "swiper/react";
import { Navigation, Pagination } from "swiper/modules";
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
import { Edit2,Info } from 'lucide-react';
import {
Card,
@@ -75,10 +80,10 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
];
const renderValue = (key, value) => {
if (key === "profiles" || key === "profile") {
const list = Array.isArray(value) ? value : [];
if (key === "profiles" || key === "profile" || key === "profile_images" || key === "images") {
const list = Array.isArray(value) ? value : (value ? [value] : []);
return (
<Box display="flex" gap={0} flexWrap="wrap">
<Box display="flex" gap={1} flexWrap="wrap">
{list.length > 0 ? (
list.map((imgObj, index) => {
const src =
@@ -99,7 +104,7 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
objectFit: "cover",
borderRadius: "50%",
border: "1px solid #ccc",
marginLeft: "-20px",
// marginLeft: "-20px",
}}
/>
);
@@ -183,9 +188,69 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
<Divider />
<CardContent sx={{ pt: 1, }}>
{Object.entries(section.data || {}).map(([key, value]) => {
// if (value && key !== 'profiles') {
// Handle brothers and sisters arrays specifically
if ((key === 'brothers' || key === 'sisters') && Array.isArray(value) && value.length > 0) {
return (
<Box key={key} sx={{ py: 2, borderBottom: "1px solid #e0e0e0" }}>
<Typography color="text.secondary" sx={{ fontWeight: 600, mb: 1 }}>
{key === 'brothers' ? 'Brothers Details' : 'Sisters Details'}
</Typography>
<style>
{`
.custom-swiper-${key} .swiper-button-next,
.custom-swiper-${key} .swiper-button-prev {
color: #d32f2f;
width: 25px;
height: 25px;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.custom-swiper-${key} .swiper-button-next::after,
.custom-swiper-${key} .swiper-button-prev::after {
font-size: 12px;
font-weight: bold;
}
.custom-swiper-${key} .swiper-pagination-bullet-active {
background-color: #d32f2f;
}
`}
</style>
<Swiper
className={`custom-swiper-${key}`}
modules={[Navigation, Pagination]}
spaceBetween={15}
slidesPerView={1}
navigation
pagination={{ clickable: true }}
style={{ padding: "4px 4px 30px 4px" }}
>
{value.map((sibling, idx) => (
<SwiperSlide key={idx}>
<Card variant="outlined" sx={{ bgcolor: '#fff', height: '100%' }}>
<CardContent sx={{ p: 2, '&:last-child': { pb: 2 } }}>
{Object.entries(sibling).map(([sKey, sVal]) => (
<Box key={sKey} display="grid" gridTemplateColumns="45% 55%" gap={1} mb={0.8} alignItems="start">
<Typography variant="caption" color="text.secondary" sx={{ fontWeight: 500 }}>
{sKey
.replace(/([A-Z])/g, ' $1')
.replace(/_/g, ' ')
.replace(/\b\w/g, (l) => l.toUpperCase())
.trim()}
</Typography>
<Typography variant="body2" fontWeight={600} sx={{ wordBreak: 'break-word' }}>
{sVal || '-'}
</Typography>
</Box>
))}
</CardContent>
</Card>
</SwiperSlide>
))}
</Swiper>
</Box>
);
}
// Convert camelCase or camel_Snake_case to readable words
const formattedKey = key
.replace(/([A-Z])/g, ' $1')
@@ -214,7 +279,7 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
</Typography>
{/* Special Case: Profiles Image Preview */}
{key === "profiles" || key === "profile" ? (
{key === "profiles" || key === "profile" || key === "profile_images" || key === "images" ? (
content
) : value ? (
<Typography
+131 -95
View File
@@ -114,6 +114,7 @@ const STEP1_SERVER_FIELD_MAP = {
confirm_password: "confirmPassword",
confirmPassword: "confirmPassword",
profiles: "profiles",
profile_images: "profiles",
};
const Stepper = ({ currentStep, onStepClick }) => {
@@ -191,6 +192,12 @@ const StepperForm = () => {
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()] ||
@@ -446,92 +453,117 @@ const StepperForm = () => {
return Object.keys(newErrors).length === 0;
};
const buildRegisterStep1Payload = () => ({
name: personalDetails.name,
mobile: personalDetails.mobileNumber,
email: personalDetails.email,
pincode: personalDetails.pincode,
gender: personalDetails.gender,
dob: personalDetails.dob,
height: personalDetails.height || "",
weight: personalDetails.weight || "",
marital_status: personalDetails.maritalStatus,
religion: personalDetails.religion,
profile_for: personalDetails.profileFor || "",
caste: personalDetails.caste,
sub_caste: personalDetails.subCaste || "",
gothram: personalDetails.gothram || "",
raasi: personalDetails.raasi || "",
star: personalDetails.star || "",
state: personalDetails.state,
district: personalDetails.city,
password: personalDetails.password || "",
fcm_token: localStorage.getItem("fcm_token") || "",
});
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("fcm_token", localStorage.getItem("fcm_token") || "");
const buildRegisterStep2Payload = () => ({
college_name: educationalDetails.collegeName || "",
study_field: educationalDetails.fieldOfStudy,
education: educationalDetails.qualification,
occupation: educationalDetails.occupation,
company_name: educationalDetails.organization || "",
employee_type: educationalDetails.employeeType,
annual_income: educationalDetails.income,
work_location: educationalDetails.workLocation || "",
});
if (personalDetails.profiles && Array.isArray(personalDetails.profiles)) {
for (const [index, item] of personalDetails.profiles.entries()) {
// If the file object is intact (e.g., just added), use it directly.
if (item.file && (item.file instanceof Blob || (typeof item.file === 'object' && item.file !== null && item.file.name))) {
formData.append(`profile_images[${index}]`, item.file);
}
// If the file object was lost due to Redux serialization,
// try to recover it from the blob URL preview.
else if (
item.preview &&
typeof item.preview === "string"
) {
try {
const response = await fetch(item.preview);
const blob = await response.blob();
const fileName = item.name || `profile_image_${index}.jpg`;
const fileType = item.type || "image/jpeg";
const recoveredFile = new File([blob], fileName, { type: fileType });
formData.append(`profile_images[${index}]`, recoveredFile);
} catch (e) {
console.error(`Could not recover file from blob URL: ${item.preview}`, e);
}
}
}
}
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 payload = {
father_name: familyDetails.fatherName,
father_occupation: familyDetails.fatherOccupation || "",
mother_name: familyDetails.motherName,
mother_occupation: familyDetails.motherOccupation || "",
family_status: familyDetails.familyStatus,
native_place: familyDetails.nativePlace || "",
brother_count: familyDetails.brotherCount || 0,
sister_count: familyDetails.sisterCount || 0,
};
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) => {
payload[`brothers[${index}][name]`] = brother?.name || "";
payload[`brothers[${index}][occupation]`] = brother?.occupation || "";
payload[`brothers[${index}][marital_status]`] =
brother?.maritalStatus || "";
payload[`brothers[${index}][have_childrens]`] =
brother?.haveChildrens ?? "";
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) => {
payload[`sisters[${index}][name]`] = sister?.name || "";
payload[`sisters[${index}][occupation]`] = sister?.occupation || "";
payload[`sisters[${index}][marital_status]`] =
sister?.maritalStatus || "";
payload[`sisters[${index}][have_childrens]`] =
sister?.haveChildrens ?? "";
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 payload;
return formData;
};
const buildRegisterStep4Payload = () => {
const payload = {
dob: lifestyleDetails.dob,
tob: lifestyleDetails.tob,
};
const formData = new FormData();
formData.append("dob", lifestyleDetails.dob || "");
formData.append("tob", lifestyleDetails.tob || "");
formData.append("place_of_birth", lifestyleDetails.placeOfBirth || "");
(lifestyleDetails.diets || []).forEach((id, index) => {
payload[`diets[${index}]`] = id;
formData.append(`diets[${index}]`, id);
});
(lifestyleDetails.hobbies || []).forEach((id, index) => {
payload[`hobbies[${index}]`] = id;
formData.append(`hobbies[${index}]`, id);
});
const graha = lifestyleDetails.graha || {};
Object.keys(graha).forEach((house) => {
const values = graha[house] || [];
values.forEach((value, index) => {
payload[`graha_${house}[${index}]`] = value;
formData.append(`graha_${house}[${index}]`, value);
});
});
@@ -539,48 +571,47 @@ const StepperForm = () => {
Object.keys(amsam).forEach((house) => {
const values = amsam[house] || [];
values.forEach((value, index) => {
payload[`amsam_${house}[${index}]`] = value;
formData.append(`amsam_${house}[${index}]`, value);
});
});
return payload;
return formData;
};
const buildRegisterStep5Payload = () => {
const payload = {
age_range: partnerPreferences.ageRange,
annual_income: partnerPreferences.annualIncome,
};
const formData = new FormData();
formData.append("age_range", partnerPreferences.ageRange || "");
formData.append("annual_income", partnerPreferences.annualIncome || "");
(partnerPreferences.castes || []).forEach((id, index) => {
payload[`castes[${index}]`] = id;
formData.append(`castes[${index}]`, id);
});
(partnerPreferences.subCastes || []).forEach((id, index) => {
payload[`sub_castes[${index}]`] = id;
formData.append(`sub_castes[${index}]`, id);
});
(partnerPreferences.occupations || []).forEach((id, index) => {
payload[`occupations[${index}]`] = id;
formData.append(`occupations[${index}]`, id);
});
(partnerPreferences.educations || []).forEach((id, index) => {
payload[`educations[${index}]`] = id;
formData.append(`educations[${index}]`, id);
});
(partnerPreferences.hobbies || []).forEach((id, index) => {
payload[`hobbies[${index}]`] = id;
formData.append(`hobbies[${index}]`, id);
});
(partnerPreferences.states || []).forEach((id, index) => {
payload[`states[${index}]`] = id;
formData.append(`states[${index}]`, id);
});
(partnerPreferences.districts || []).forEach((id, index) => {
payload[`districts[${index}]`] = id;
formData.append(`districts[${index}]`, id);
});
return payload;
return formData;
};
const extractAccessToken = (res) =>
@@ -601,7 +632,7 @@ const StepperForm = () => {
try {
if (currentStep === 1) {
const payload = buildRegisterStep1Payload();
const payload = await buildRegisterStep1Payload();
const res = await registerStep1.mutateAsync(payload);
const token = extractAccessToken(res);
if (token) {
@@ -624,24 +655,29 @@ const StepperForm = () => {
setCurrentStep((prev) => Math.min(prev + 1, 6));
window.scrollTo(0, 0);
} catch (e) {
if (currentStep === 1) {
const serverErrors = mapServerErrors(e);
if (Object.keys(serverErrors).length > 0) {
const hasFieldErrors = Object.keys(serverErrors).some(
(key) => key !== "_form"
);
if (hasFieldErrors) {
setErrors(serverErrors);
focusFirstError(serverErrors, STEP_FIELD_ORDER[1]);
return;
}
if (serverErrors._form) {
toast.error(serverErrors._form, { position: "top-right" });
return;
}
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]);
// For step 1, we know mapping is correct so field errors are sufficient feedback
if (currentStep === 1) handled = true;
}
if (serverErrors._form) {
toast.error(serverErrors._form, { position: "top-right" });
handled = true;
}
}
alert("Failed to submit step. Please try again.");
if (!handled) {
const msg = e?.response?.data?.message || e?.message || "Failed to submit step. Please try again.";
toast.error(msg, { position: "top-right" });
}
}
};
@@ -675,9 +711,9 @@ const StepperForm = () => {
try {
// final combined API call - replace with your final API
await new Promise((resolve) => setTimeout(resolve, 500));
alert("Form submitted successfully!");
toast.success("Form submitted successfully!", { position: "top-right" });
} catch (e) {
alert("Failed to submit form.");
toast.error("Failed to submit form.", { position: "top-right" });
}
};