form correction

This commit is contained in:
Meenadeveloper 2026-03-09 13:02:38 +05:30
parent 8f6ddbcb2c
commit 805c93b3f3
4 changed files with 225 additions and 34 deletions

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useRef } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { updateLifestyleDetails } from "../redux/registrationFormSlice"; import { updateLifestyleDetails } from "../redux/registrationFormSlice";
import { import {
@ -11,12 +11,18 @@ import {
TextField, TextField,
Checkbox, Checkbox,
ListItemText, ListItemText,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
} from "@mui/material"; } from "@mui/material";
import { LocalizationProvider } from "@mui/x-date-pickers"; import { LocalizationProvider } from "@mui/x-date-pickers";
import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { TimePicker } from "@mui/x-date-pickers/TimePicker"; import { TimePicker } from "@mui/x-date-pickers/TimePicker";
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
import { useLifestyleMasters } from "../hooks/useMasters"; import { useLifestyleMasters } from "../hooks/useMasters";
import horoscopeImg from "../assets/images/horoscopeimg.png";
const LifestyleDetailsForm = ({ const LifestyleDetailsForm = ({
onSubmitStep, onSubmitStep,
@ -53,6 +59,15 @@ const LifestyleDetailsForm = ({
return raw.grahas || raw.graha || []; return raw.grahas || raw.graha || [];
}, [lifestyleMasters]); }, [lifestyleMasters]);
const [confirmDialog, setConfirmDialog] = useState({
open: false,
type: "",
house: null,
item: "",
sourceHouse: null,
pendingValue: [],
});
useEffect(() => { useEffect(() => {
inputRef.current?.focus(); inputRef.current?.focus();
}, []); }, []);
@ -68,23 +83,74 @@ const LifestyleDetailsForm = ({
if (onFieldChange) onFieldChange(field); if (onFieldChange) onFieldChange(field);
}; };
const handleGrahaChange = (house, value) => { const handleChartChange = (type, house, newValue) => {
const next = { ...(data.graha || {}) }; const currentChart = type === "graha" ? data.graha : data.amsam;
next[house] = value; const currentHouseValue = currentChart?.[house] || [];
dispatch(updateLifestyleDetails({ graha: next }));
if (onFieldChange) onFieldChange("graha"); // Find added items
const addedItems = newValue.filter((item) => !currentHouseValue.includes(item));
if (addedItems.length > 0) {
for (const addedItem of addedItems) {
for (const [otherHouse, items] of Object.entries(currentChart || {})) {
if (String(otherHouse) !== String(house) && items && items.includes(addedItem)) {
setConfirmDialog({
open: true,
type,
house,
item: addedItem,
sourceHouse: otherHouse,
pendingValue: newValue,
});
return;
}
}
}
}
// No duplicates, proceed with update
const updates = {};
const nextChart = { ...(currentChart || {}) };
nextChart[house] = newValue;
if (type === "graha") {
updates.graha = nextChart;
} else {
updates.amsam = nextChart;
}
dispatch(updateLifestyleDetails(updates));
if (onFieldChange) onFieldChange(type);
}; };
const handleAmsamChange = (house, value) => { const handleConfirmMove = () => {
const next = { ...(data.amsam || {}) }; const { type, house, item, sourceHouse, pendingValue } = confirmDialog;
next[house] = value; const currentChart = type === "graha" ? data.graha : data.amsam;
dispatch(updateLifestyleDetails({ amsam: next })); const nextChart = { ...(currentChart || {}) };
if (onFieldChange) onFieldChange("amsam");
// Remove from source house
if (nextChart[sourceHouse]) {
nextChart[sourceHouse] = nextChart[sourceHouse].filter((i) => i !== item);
}
// Add to target house
nextChart[house] = pendingValue;
const updates = type === "graha" ? { graha: nextChart } : { amsam: nextChart };
dispatch(updateLifestyleDetails(updates));
if (onFieldChange) onFieldChange(type);
setConfirmDialog({ ...confirmDialog, open: false });
};
const handleCancelMove = () => {
setConfirmDialog({ ...confirmDialog, open: false });
}; };
const handleSubmit = () => { const handleSubmit = () => {
console.log("Submitting lifestyle details:", data); console.log("Submitting lifestyle details:", data);
onSubmitStep(); onSubmitStep();
}; };
const parseDateValue = (value) => { const parseDateValue = (value) => {
@ -151,9 +217,7 @@ const LifestyleDetailsForm = ({
const getValue = (house) => const getValue = (house) =>
(type === "graha" ? data.graha : data.amsam)?.[house] || []; (type === "graha" ? data.graha : data.amsam)?.[house] || [];
const onChange = (house, value) => const onChange = (house, value) =>
type === "graha" handleChartChange(type, house, value);
? handleGrahaChange(house, value)
: handleAmsamChange(house, value);
const label = type === "graha" ? "Rasi" : "Navamsam"; const label = type === "graha" ? "Rasi" : "Navamsam";
return ( return (
@ -165,7 +229,9 @@ const LifestyleDetailsForm = ({
{renderChartCell(label, getValue(5), (value) => onChange(5, value))} {renderChartCell(label, getValue(5), (value) => onChange(5, value))}
<div className="col-span-2 row-span-2 flex items-center justify-center"> <div className="col-span-2 row-span-2 flex items-center justify-center">
<div className="w-full aspect-square rounded-full overflow-hidden border-4 border-gray-200 shadow-lg bg-white" /> <div className="w-full aspect-square rounded-full overflow-hidden bg-white">
<img src={horoscopeImg} alt="Horoscope" className="w-full h-full object-contain" />
</div>
</div> </div>
{renderChartCell(label, getValue(6), (value) => onChange(6, value))} {renderChartCell(label, getValue(6), (value) => onChange(6, value))}
@ -403,6 +469,24 @@ const LifestyleDetailsForm = ({
{onSkipStep ? "Next" : "Update"} {onSkipStep ? "Next" : "Update"}
</Button> </Button>
</Grid> </Grid>
<Dialog
open={confirmDialog.open}
onClose={handleCancelMove}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Duplicate Selection"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
{confirmDialog.item} is already selected in House {confirmDialog.sourceHouse}. Do you want to move it to House {confirmDialog.house}?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleCancelMove}>Cancel</Button>
<Button onClick={handleConfirmMove} autoFocus>Move</Button>
</DialogActions>
</Dialog>
</form> </form>
</div> </div>
); );

View File

@ -51,6 +51,25 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const sendOtp = useSendOtp(); const sendOtp = useSendOtp();
const verifyOtp = useVerifyOtp(); const verifyOtp = useVerifyOtp();
const [verifiedMobileNumber, setVerifiedMobileNumber] = useState(
() => localStorage.getItem("registration_verified_mobile") || ""
);
const initializedVerifiedNumber = useRef(false);
useEffect(() => {
if (isStep1Update && data.mobileNumber && !initializedVerifiedNumber.current) {
setVerifiedMobileNumber(data.mobileNumber);
localStorage.setItem("registration_verified_mobile", data.mobileNumber);
setMobileOtpVerified(true);
initializedVerifiedNumber.current = true;
}
}, [isStep1Update, data.mobileNumber]);
useEffect(() => {
if (verifiedMobileNumber && data.mobileNumber === verifiedMobileNumber) {
setMobileOtpVerified(true);
}
}, [verifiedMobileNumber, data.mobileNumber]);
const { data: personalMasters, isLoading: isPersonalMastersLoading } = const { data: personalMasters, isLoading: isPersonalMastersLoading } =
usePersonalDetailsMasters(); usePersonalDetailsMasters();
@ -267,11 +286,17 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
const fieldsToClear = [field]; const fieldsToClear = [field];
if (field === "mobileNumber") { if (field === "mobileNumber") {
setMobileNumberError(""); setMobileNumberError("");
setShowOtp(false); if (verifiedMobileNumber && value === verifiedMobileNumber) {
setOtp(new Array(OTP_LENGTH).fill("")); setMobileOtpVerified(true);
setOtpError(""); setShowOtp(false);
setOtpTimer(0); setOtpError("");
setMobileOtpVerified(false); } else {
setShowOtp(false);
setOtp(new Array(OTP_LENGTH).fill(""));
setOtpError("");
setOtpTimer(0);
setMobileOtpVerified(false);
}
} }
if (field === "religion") { if (field === "religion") {
updates.caste = ""; updates.caste = "";
@ -348,6 +373,8 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
"OTP verified successfully"; "OTP verified successfully";
toast.success(successMessage, { position: "top-right" }); toast.success(successMessage, { position: "top-right" });
setMobileOtpVerified(true); setMobileOtpVerified(true);
setVerifiedMobileNumber(data.mobileNumber);
localStorage.setItem("registration_verified_mobile", data.mobileNumber);
setMobileNumberError(""); setMobileNumberError("");
setOtpError(""); setOtpError("");
} catch (error) { } catch (error) {
@ -505,6 +532,7 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
label="Mobile Number" label="Mobile Number"
type="tel" type="tel"
value={data.mobileNumber} value={data.mobileNumber}
disabled={isStep1Update}
onChange={(e) => handleChange("mobileNumber", e.target.value)} onChange={(e) => handleChange("mobileNumber", e.target.value)}
error={ error={
Boolean(errors.mobileNumber) || Boolean(mobileNumberError) Boolean(errors.mobileNumber) || Boolean(mobileNumberError)

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useState } from "react";
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Swiper, SwiperSlide } from "swiper/react"; import { Swiper, SwiperSlide } from "swiper/react";
import { Navigation, Pagination } from "swiper/modules"; import { Navigation, Pagination } from "swiper/modules";
@ -17,9 +17,15 @@ import {
Button, Button,
Grid, Grid,
Tooltip, Tooltip,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
} from '@mui/material'; } from '@mui/material';
import { usePreviewDetails } from "../hooks/usePreview"; import { usePreviewDetails } from "../hooks/usePreview";
import { isAuthenticated } from "../utills/auth"; import { isAuthenticated } from "../utills/auth";
import horoscopeImg from "../assets/images/horoscopeimg.png";
const PreviewScreen = ({ onEdit, onSubmit }) => { const PreviewScreen = ({ onEdit, onSubmit }) => {
const formData = useSelector((state) => state.registerform); const formData = useSelector((state) => state.registerform);
@ -28,6 +34,21 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
const isLoading = isAuth && apiLoading; const isLoading = isAuth && apiLoading;
const isError = isAuth && apiError; const isError = isAuth && apiError;
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
const handleConfirmSubmit = () => {
setOpenConfirmDialog(true);
};
const handleProceedSubmit = () => {
setOpenConfirmDialog(false);
onSubmit();
};
const handleCancelSubmit = () => {
setOpenConfirmDialog(false);
};
const sections = previewData?.personal_details const sections = previewData?.personal_details
? [ ? [
{ {
@ -183,8 +204,8 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 0.5, maxWidth: '300px', mx: 'auto', p: 1, bgcolor: '#fff3e0', borderRadius: 2 }}> <Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 0.5, maxWidth: '300px', mx: 'auto', p: 1, bgcolor: '#fff3e0', borderRadius: 2 }}>
{renderCell(1)} {renderCell(2)} {renderCell(3)} {renderCell(4)} {renderCell(1)} {renderCell(2)} {renderCell(3)} {renderCell(4)}
{renderCell(5)} {renderCell(5)}
<Box sx={{ gridColumn: 'span 2', gridRow: 'span 2', bgcolor: '#fff', border: '1px solid #eee', display:'flex', alignItems:'center', justifyContent:'center', fontSize:'0.7rem', fontWeight:'bold', color:'#aaa' }}> <Box sx={{ gridColumn: 'span 2', gridRow: 'span 2', bgcolor: '#fff', border: '1px solid #eee', display:'flex', alignItems:'center', justifyContent:'center', fontSize:'0.7rem', fontWeight:'bold', color:'#aaa', overflow: 'hidden' }}>
{title.toUpperCase()} <img src={horoscopeImg} alt={title} style={{ width: '100%', height: '100%', objectFit: 'contain' }} />
</Box> </Box>
{renderCell(6)} {renderCell(6)}
{renderCell(7)} {renderCell(8)} {renderCell(7)} {renderCell(8)}
@ -224,7 +245,10 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
{!isLoading && {!isLoading &&
sections.map((section) => ( sections.map((section) => (
<Card key={section.title} variant="outlined" sx={{ borderRadius: 2, background:"#fff5ed" }}> <Card key={section.title} variant="outlined"
sx={{ borderRadius: 2,
// background:"#fff5ed"
}}>
<CardHeader <CardHeader
title={ title={
<Typography variant="h6" fontWeight="bold"> <Typography variant="h6" fontWeight="bold">
@ -243,11 +267,25 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
} }
sx={{padding:"15px 15px", background:"#f5fbff" }} sx={{padding:"15px 15px", background:"#f5fbff" }}
/> />
<Divider /> {/* <Divider /> */}
<CardContent sx={{ pt: 1, }}> <CardContent sx={{ pt: 1, }}>
{Object.entries(section.data || {}).map(([key, value]) => { {Object.entries(section.data || {}).map(([key, value]) => {
// Filter out ID fields // Filter out ID fields
if (key === 'id' || key.endsWith('_id') || key.endsWith('Id') || key.endsWith('_ids') || key.endsWith('Ids') || key === 'created_at' || key === 'updated_at') { const hiddenFields = [
"id",
"created_at",
"updated_at",
"phone_number_visibility",
"chat_alert_notification",
"chat_protection",
"profile_photo_protect",
"call_protection",
"match_alert_preference",
"who_can_message",
"who_can_message_categories",
"user_status",
];
if (hiddenFields.includes(key) || key.endsWith('_id') || key.endsWith('Id') || key.endsWith('_ids') || key.endsWith('Ids')) {
return null; return null;
} }
@ -304,14 +342,21 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
color: #d32f2f; color: #d32f2f;
width: 25px; width: 25px;
height: 25px; height: 25px;
overflow: 'hidden';
padding:5px;
display: 'flex';
align-items: 'center';
justify-content: 'center';
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
border-radius: 50%; border-radius: 50%;
box-shadow: 0 2px 4px rgba(0,0,0,0.1); box-shadow: 0 2px 4px rgba(0,0,0,0.1);
} }
.custom-swiper-${key} .swiper-button-next::after, .custom-swiper-${key} .swiper-button-next::after,
.custom-swiper-${key} .swiper-button-prev::after { .custom-swiper-${key} .swiper-button-prev::after {
font-size: 12px; font-size: 8px;
font-weight: bold; font-weight: bold;
width:20px;
} }
.custom-swiper-${key} .swiper-pagination-bullet-active { .custom-swiper-${key} .swiper-pagination-bullet-active {
background-color: #d32f2f; background-color: #d32f2f;
@ -329,7 +374,8 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
> >
{value.map((sibling, idx) => ( {value.map((sibling, idx) => (
<SwiperSlide key={idx}> <SwiperSlide key={idx}>
<Card variant="outlined" sx={{ bgcolor: '#fff', height: '100%' }}> <Card variant="outlined"
sx={{ bgcolor: '#fff', height: '100%' }}>
<CardContent sx={{ p: 2, '&:last-child': { pb: 2 } }}> <CardContent sx={{ p: 2, '&:last-child': { pb: 2 } }}>
{Object.entries(sibling).map(([sKey, sVal]) => { {Object.entries(sibling).map(([sKey, sVal]) => {
if (sKey === 'id' || sKey.endsWith('_id') || sKey.endsWith('Id') || sKey === 'created_at' || sKey === 'updated_at') return null; if (sKey === 'id' || sKey.endsWith('_id') || sKey.endsWith('Id') || sKey === 'created_at' || sKey === 'updated_at') return null;
@ -375,7 +421,7 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
<Box <Box
key={key} key={key}
py={0.7} py={0.7}
borderBottom="1px solid #e0e0e0" // borderBottom="1px solid #e0e0e0"
sx={{ sx={{
display: "grid", display: "grid",
gridTemplateColumns: { gridTemplateColumns: {
@ -434,13 +480,35 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
color="success" color="success"
size="large" size="large"
onClick={onSubmit} onClick={handleConfirmSubmit}
sx={{ borderRadius: 2 }} sx={{ borderRadius: 2 }}
> >
Submit full Completed Data Submit full Completed Data
</Button> </Button>
</Grid> </Grid>
<Dialog
open={openConfirmDialog}
onClose={handleCancelSubmit}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Confirm Submission"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Once you submit your details, you will not be able to edit the following fields: Place of Birth, Date of Birth, Rasi and Navamsam.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleCancelSubmit}>Cancel</Button>
<Button onClick={handleProceedSubmit} autoFocus>
OK
</Button>
</DialogActions>
</Dialog>
</Box> </Box>
); );
}; };

View File

@ -600,8 +600,8 @@ useEffect(()=>{
updateLifestyleDetails({ updateLifestyleDetails({
diets: ld.diet_id || "", diets: ld.diet_id || "",
hobbies: ld.hobbies_ids || [], hobbies: ld.hobbies_ids || [],
dob: ld.date_of_birth || "", dob: ld.time_of_birth || "",
tob: ld.time_of_birth ? ld.time_of_birth.substring(0, 5) : "", tob: ld.date_of_birth ? ld.date_of_birth.substring(0, 5) : "",
placeOfBirth: ld.place_of_birth || "", placeOfBirth: ld.place_of_birth || "",
graha: mapChart("graha"), graha: mapChart("graha"),
amsam: mapChart("amsam"), amsam: mapChart("amsam"),
@ -1009,6 +1009,12 @@ useEffect(()=>{
break; break;
} }
if (shouldHideStepper) {
toast.success("Updated successfully", { position: "top-right" });
navigate("/profile");
return;
}
// Mark step completed (tick icon) // Mark step completed (tick icon)
setCompletedSteps((prev) => setCompletedSteps((prev) =>
prev.includes(currentStep) ? prev : [...prev, currentStep] prev.includes(currentStep) ? prev : [...prev, currentStep]
@ -1189,15 +1195,20 @@ useEffect(() => {
enabledSteps={enabledSteps} enabledSteps={enabledSteps}
completedSteps={completedSteps} completedSteps={completedSteps}
/> )} /> )}
<div className="flex items-center p-4 justify-center"> <div className="flex items-center p-4 justify-center">
{currentStep > 1 && currentStep < 6 && ( {/* {currentStep > 1 && currentStep < 6 && (
<button <button
onClick={() => setCurrentStep((prev) => prev - 1)} onClick={() => setCurrentStep((prev) => prev - 1)}
className="mr-3" className="mr-3"
> >
<ChevronLeft size={24} /> <ChevronLeft size={24} />
</button> </button>
)} )} */}
<h1 className="text-[24px] font-semibold text-center uppercase py-2 px-3 rounded-5">{getTitle()}</h1> <h1 className="text-[24px] font-semibold text-center uppercase py-2 px-3 rounded-5">{getTitle()}</h1>
</div> </div>