form done
This commit is contained in:
1 parent
b1d9d46e4e
commit
d35bd08f5f
19 files changed
+3301
-14
No files matched your search
@@ -0,0 +1,777 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { updatePersonalDetails } from "../redux/registrationFormSlice";
|
||||
import {
|
||||
Grid,
|
||||
TextField,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
Button,
|
||||
Box,
|
||||
Typography,
|
||||
Link,
|
||||
} from "@mui/material";
|
||||
import AdvancedDropzone from "./AdvancedDropzone";
|
||||
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
|
||||
|
||||
import { LocalizationProvider } from "@mui/x-date-pickers";
|
||||
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
|
||||
const OTP_LENGTH = 4;
|
||||
const OTP_TIMER_SEC = 120; // 2 minutes
|
||||
|
||||
const PersonalDetailsForm = ({ onSubmitStep, onSkipStep, errors }) => {
|
||||
const dispatch = useDispatch();
|
||||
const data = useSelector((state) => state.registerform.personalDetails);
|
||||
const nameInputRef = useRef(null);
|
||||
|
||||
const [showOtp, setShowOtp] = useState(false);
|
||||
const [otp, setOtp] = useState(new Array(OTP_LENGTH).fill(""));
|
||||
const [otpTimer, setOtpTimer] = useState(0);
|
||||
const [otpError, setOtpError] = useState("");
|
||||
const [mobileOtpVerified, setMobileOtpVerified] = useState(false);
|
||||
const [mobileNumberError, setMobileNumberError] = useState("");
|
||||
|
||||
const startOtpTimer = useCallback(() => {
|
||||
setOtpTimer(OTP_TIMER_SEC);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (otpTimer <= 0) return;
|
||||
const timerId = setInterval(() => {
|
||||
setOtpTimer((sec) => sec - 1);
|
||||
}, 1000);
|
||||
return () => clearInterval(timerId);
|
||||
}, [otpTimer]);
|
||||
|
||||
useEffect(() => {
|
||||
nameInputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const handleOtpChange = (index, value) => {
|
||||
if (!/^\d*$/.test(value)) return;
|
||||
const newOtp = [...otp];
|
||||
newOtp[index] = value.slice(-1);
|
||||
setOtp(newOtp);
|
||||
if (value && index < OTP_LENGTH - 1) {
|
||||
const next = document.getElementById(`otp-${index + 1}`);
|
||||
if (next) next.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const resetOtp = () => {
|
||||
setOtp(new Array(OTP_LENGTH).fill(""));
|
||||
setOtpError("");
|
||||
startOtpTimer();
|
||||
};
|
||||
|
||||
const handleMobileSubmit = () => {
|
||||
if (!data.mobileNumber || data.mobileNumber.length !== 10) {
|
||||
setMobileNumberError(
|
||||
"Please enter a valid 10-digit mobile number before sending OTP"
|
||||
);
|
||||
return;
|
||||
}
|
||||
setMobileNumberError("");
|
||||
setShowOtp(true);
|
||||
resetOtp();
|
||||
setMobileOtpVerified(false);
|
||||
};
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
dispatch(updatePersonalDetails({ [field]: value }));
|
||||
if (field === "mobileNumber") {
|
||||
setMobileNumberError("");
|
||||
setShowOtp(false);
|
||||
setOtp(new Array(OTP_LENGTH).fill(""));
|
||||
setOtpError("");
|
||||
setOtpTimer(0);
|
||||
setMobileOtpVerified(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isOtpComplete = otp.every((digit) => digit !== "");
|
||||
|
||||
// Simulated API OTP verification (replace with actual)
|
||||
const verifyOtpApi = async (mobile, otpValue) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
if (otpValue === "1234") resolve(true);
|
||||
else reject("Invalid OTP");
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
const handleOtpSubmit = async () => {
|
||||
if (!isOtpComplete) {
|
||||
setOtpError("Complete OTP is required");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await verifyOtpApi(data.mobileNumber, otp.join(""));
|
||||
setMobileOtpVerified(true);
|
||||
setMobileNumberError("");
|
||||
} catch (error) {
|
||||
setOtpError(error || "OTP verification failed");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// file upload
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// const handleSubmit = async () => {
|
||||
// if (showOtp && !isOtpComplete) {
|
||||
// setOtpError("OTP is required and must be complete");
|
||||
// return;
|
||||
// }
|
||||
// if (showOtp && !mobileOtpVerified) {
|
||||
// try {
|
||||
// await verifyOtpApi(data.mobileNumber, otp.join(""));
|
||||
// setMobileOtpVerified(true);
|
||||
// setOtpError("");
|
||||
// onSubmitStep();
|
||||
// console.log("OTP verified on submit");
|
||||
// } catch (err) {
|
||||
// setOtpError(err || "OTP verification failed");
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// onSubmitStep();
|
||||
|
||||
// };
|
||||
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (showOtp && !isOtpComplete) {
|
||||
setOtpError("OTP is required and must be complete");
|
||||
return;
|
||||
}
|
||||
|
||||
if (showOtp && !mobileOtpVerified) {
|
||||
try {
|
||||
await verifyOtpApi(data.mobileNumber, otp.join(""));
|
||||
setMobileOtpVerified(true);
|
||||
setOtpError("");
|
||||
console.log("Submitting personal details:", data); // log here
|
||||
onSubmitStep();
|
||||
console.log("OTP verified on submit");
|
||||
} catch (err) {
|
||||
setOtpError(err || "OTP verification failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// no OTP or already verified
|
||||
console.log("Submitting personal details:", data); // log here
|
||||
onSubmitStep();
|
||||
};
|
||||
|
||||
|
||||
const formatTimer = (sec) => {
|
||||
const m = Math.floor(sec / 60)
|
||||
.toString()
|
||||
.padStart(2, "0");
|
||||
const s = (sec % 60).toString().padStart(2, "0");
|
||||
return `${m}:${s}`;
|
||||
};
|
||||
const parseDobValue = data.dob ? new Date(data.dob) : null;
|
||||
return (
|
||||
<>
|
||||
<div className="w-full max-w-[1200px] mx-auto bg-[#fff2f2] 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">
|
||||
{/* Name */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-gray-900 text-[17px]">
|
||||
Enter the Name
|
||||
</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
inputRef={nameInputRef}
|
||||
name="name"
|
||||
label="Name"
|
||||
value={data.name}
|
||||
onChange={(e) => handleChange("name", e.target.value)}
|
||||
error={Boolean(errors.name)}
|
||||
helperText={errors.name}
|
||||
placeholder="Enter Name"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Gender */}
|
||||
<div className="flex flex-col gap-6">
|
||||
<label className="text-gray-900 text-[17px]">
|
||||
Enter the Gender
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.gender)}
|
||||
>
|
||||
<InputLabel id="gender-label">Gender</InputLabel>
|
||||
<Select
|
||||
labelId="gender-label"
|
||||
label="Gender"
|
||||
name="gender"
|
||||
value={data.gender}
|
||||
onChange={(e) => handleChange("gender", e.target.value)}
|
||||
>
|
||||
<MenuItem value="Male">Male</MenuItem>
|
||||
<MenuItem value="Female">Female</MenuItem>
|
||||
</Select>
|
||||
{errors.gender && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.gender}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Mobile Number and Send OTP Button */}
|
||||
<div className="flex flex-col gap-6 relative">
|
||||
<TextField
|
||||
fullWidth
|
||||
name="mobileNumber"
|
||||
label="Mobile Number"
|
||||
type="tel"
|
||||
value={data.mobileNumber}
|
||||
onChange={(e) => handleChange("mobileNumber", e.target.value)}
|
||||
error={
|
||||
Boolean(errors.mobileNumber) || Boolean(mobileNumberError)
|
||||
}
|
||||
helperText={mobileNumberError || errors.mobileNumber}
|
||||
placeholder="Enter Mobile Number"
|
||||
inputProps={{ maxLength: 10 }}
|
||||
variant="outlined"
|
||||
disabled={mobileOtpVerified}
|
||||
// sx={{ maxWidth: "430px" }}
|
||||
/>
|
||||
<Box sx={{ position: "absolute", right: 0 }}>
|
||||
{!showOtp && !mobileOtpVerified && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleMobileSubmit}
|
||||
sx={{
|
||||
padding: "15px 10px",
|
||||
background: "green",
|
||||
color: "#fff",
|
||||
}}
|
||||
>
|
||||
Send OTP
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
{/* OTP Inputs */}
|
||||
<div className="flex flex-col gap-6">
|
||||
{showOtp && !mobileOtpVerified && (
|
||||
<>
|
||||
<Box display="flex" gap={1} alignItems="center">
|
||||
{otp.map((digit, index) => (
|
||||
<TextField
|
||||
key={index}
|
||||
id={`otp-${index}`}
|
||||
inputProps={{
|
||||
maxLength: 1,
|
||||
style: {
|
||||
textAlign: "center",
|
||||
width: 40,
|
||||
fontSize: 20,
|
||||
},
|
||||
}}
|
||||
value={digit}
|
||||
onChange={(e) => handleOtpChange(index, e.target.value)}
|
||||
error={Boolean(otpError)}
|
||||
autoFocus={index === 0}
|
||||
variant="outlined"
|
||||
/>
|
||||
))}
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={handleOtpSubmit} // new handler to verify OTP
|
||||
sx={{ height: 40, ml: 2 }}
|
||||
disabled={!isOtpComplete}
|
||||
>
|
||||
Submit OTP
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Typography sx={{ ml: 2, minWidth: 56 }}>
|
||||
{otpTimer > 0 ? (
|
||||
formatTimer(otpTimer)
|
||||
) : (
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
onClick={resetOtp}
|
||||
disabled={otpTimer > 0}
|
||||
>
|
||||
Resend OTP
|
||||
</Link>
|
||||
)}
|
||||
</Typography>
|
||||
|
||||
{otpError && (
|
||||
<Typography color="error" variant="caption" sx={{ mt: 1 }}>
|
||||
{otpError}
|
||||
</Typography>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{mobileOtpVerified && (
|
||||
<Typography
|
||||
color="primary"
|
||||
variant="body2"
|
||||
sx={{
|
||||
background: "green",
|
||||
padding: "17px 15px",
|
||||
width: "fit-content",
|
||||
borderRadius: "5px",
|
||||
color: "#fff",
|
||||
fontSize: "18px",
|
||||
}}
|
||||
>
|
||||
Mobile number verified
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Other fields like DOB, height, marital status, etc. */}
|
||||
{/* Your other inputs here */}
|
||||
{/* DOB */}
|
||||
{/* <div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Date of Birth</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="dob"
|
||||
type="date"
|
||||
value={data.dob}
|
||||
onChange={(e) => handleChange("dob", e.target.value)}
|
||||
error={Boolean(errors.dob)}
|
||||
helperText={errors.dob}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div> */}
|
||||
|
||||
{/* DOB with MUI DatePicker */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Date of Birth</label>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DatePicker
|
||||
format="dd/MM/yyyy"
|
||||
value={parseDobValue}
|
||||
onChange={(value) => {
|
||||
let formatted = "";
|
||||
if (value instanceof Date && !isNaN(value)) {
|
||||
const y = value.getFullYear();
|
||||
const m = String(value.getMonth() + 1).padStart(2, "0");
|
||||
const d = String(value.getDate()).padStart(2, "0");
|
||||
formatted = `${y}-${m}-${d}`;
|
||||
}
|
||||
handleChange("dob", formatted);
|
||||
}}
|
||||
slotProps={{
|
||||
textField: {
|
||||
fullWidth: true,
|
||||
error: Boolean(errors.dob),
|
||||
helperText: errors.dob,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
|
||||
{/* Height */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Height</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="height"
|
||||
label="Enter Height"
|
||||
value={data.height}
|
||||
onChange={(e) => handleChange("height", e.target.value)}
|
||||
error={Boolean(errors.height)}
|
||||
helperText={errors.height}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Weight */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Weight</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="weight"
|
||||
label="Enter Weight"
|
||||
value={data.weight}
|
||||
onChange={(e) => handleChange("weight", e.target.value)}
|
||||
error={Boolean(errors.weight)}
|
||||
helperText={errors.weight}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Marital Status */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Marital Status</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.maritalStatus)}
|
||||
>
|
||||
<InputLabel id="maritalStatus-label">
|
||||
Select Marital Status
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="maritalStatus-label"
|
||||
label="Select Marital Status"
|
||||
name="maritalStatus"
|
||||
value={data.maritalStatus}
|
||||
onChange={(e) =>
|
||||
handleChange("maritalStatus", e.target.value)
|
||||
}
|
||||
>
|
||||
<MenuItem value="Single">Single</MenuItem>
|
||||
<MenuItem value="Divorced">Divorced</MenuItem>
|
||||
<MenuItem value="Widowed">Widowed</MenuItem>
|
||||
</Select>
|
||||
{errors.maritalStatus && (
|
||||
<Typography
|
||||
color="error"
|
||||
variant="caption"
|
||||
sx={{ mt: 0.5, ml: 1.8 }}
|
||||
>
|
||||
{errors.maritalStatus}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Religion */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Religion</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.religion)}
|
||||
>
|
||||
<InputLabel id="religion-label">Select Religion</InputLabel>
|
||||
<Select
|
||||
labelId="religion-label"
|
||||
label="Select Religion"
|
||||
name="religion"
|
||||
value={data.religion}
|
||||
onChange={(e) => handleChange("religion", e.target.value)}
|
||||
>
|
||||
<MenuItem value="Hindu">Hindu</MenuItem>
|
||||
<MenuItem value="Muslim">Muslim</MenuItem>
|
||||
<MenuItem value="Christian">Christian</MenuItem>
|
||||
<MenuItem value="Others">Others</MenuItem>
|
||||
</Select>
|
||||
{errors.religion && (
|
||||
<Typography
|
||||
color="error"
|
||||
variant="caption"
|
||||
sx={{ mt: 0.5, ml: 1.8 }}
|
||||
>
|
||||
{errors.religion}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Caste / Community */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Caste / Community
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.caste)}
|
||||
>
|
||||
<InputLabel id="caste-label">Select Caste / Community</InputLabel>
|
||||
<Select
|
||||
labelId="caste-label"
|
||||
label="Select Caste / Community"
|
||||
name="caste"
|
||||
value={data.caste}
|
||||
onChange={(e) => handleChange("caste", e.target.value)}
|
||||
>
|
||||
<MenuItem value="Agamudayar">Agamudayar</MenuItem>
|
||||
<MenuItem value="Brahmin">Brahmin</MenuItem>
|
||||
<MenuItem value="Others">Others</MenuItem>
|
||||
</Select>
|
||||
{errors.caste && (
|
||||
<Typography
|
||||
color="error"
|
||||
variant="caption"
|
||||
sx={{ mt: 0.5, ml: 1.8 }}
|
||||
>
|
||||
{errors.caste}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Sub-Caste (optional) */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Sub-Caste (optional)
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id="subCaste-label">
|
||||
Select Sub-Caste (optional)
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="subCaste-label"
|
||||
label="Select Sub-Caste (optional)"
|
||||
name="subCaste"
|
||||
value={data.subCaste}
|
||||
onChange={(e) => handleChange("subCaste", e.target.value)}
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>None</em>
|
||||
</MenuItem>
|
||||
<MenuItem value="Thuluva vellala">Thuluva vellala</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Gothram (optional) */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Gothram (optional)
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id="gothram-label">
|
||||
Select Gothram (optional)
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="gothram-label"
|
||||
label="Select Gothram (optional)"
|
||||
name="gothram"
|
||||
value={data.gothram}
|
||||
onChange={(e) => handleChange("gothram", e.target.value)}
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>None</em>
|
||||
</MenuItem>
|
||||
<MenuItem value="Siva Gotheram">Siva Gotheram</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Blood Group (optional) */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Blood Group (optional)
|
||||
</label>
|
||||
<FormControl fullWidth variant="outlined">
|
||||
<InputLabel id="blood-label">
|
||||
Select Blood Group (optional)
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="blood-label"
|
||||
label="Select Blood Group (optional)"
|
||||
name="bloodGroup"
|
||||
value={data.bloodGroup}
|
||||
onChange={(e) => handleChange("bloodGroup", e.target.value)}
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>None</em>
|
||||
</MenuItem>
|
||||
<MenuItem value="O+">O+</MenuItem>
|
||||
<MenuItem value="A+">A+</MenuItem>
|
||||
<MenuItem value="B+">B+</MenuItem>
|
||||
<MenuItem value="AB+">AB+</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Email Id */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Email Id</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="email"
|
||||
label="Enter Email Id"
|
||||
value={data.email}
|
||||
onChange={(e) => handleChange("email", e.target.value)}
|
||||
error={Boolean(errors.email)}
|
||||
helperText={errors.email}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* State */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">State</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.state)}
|
||||
>
|
||||
<InputLabel id="state-label">Select State</InputLabel>
|
||||
<Select
|
||||
labelId="state-label"
|
||||
label="Select State"
|
||||
name="state"
|
||||
value={data.state}
|
||||
onChange={(e) => handleChange("state", e.target.value)}
|
||||
>
|
||||
<MenuItem value="Tamil Nadu">Tamil Nadu</MenuItem>
|
||||
<MenuItem value="Kerala">Kerala</MenuItem>
|
||||
<MenuItem value="Karnataka">Karnataka</MenuItem>
|
||||
</Select>
|
||||
{errors.state && (
|
||||
<Typography
|
||||
color="error"
|
||||
variant="caption"
|
||||
sx={{ mt: 0.5, ml: 1.8 }}
|
||||
>
|
||||
{errors.state}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* City */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">City</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.city)}
|
||||
>
|
||||
<InputLabel id="city-label">Select City</InputLabel>
|
||||
<Select
|
||||
labelId="city-label"
|
||||
label="Select City"
|
||||
name="city"
|
||||
value={data.city}
|
||||
onChange={(e) => handleChange("city", e.target.value)}
|
||||
>
|
||||
<MenuItem value="Chennai">Chennai</MenuItem>
|
||||
<MenuItem value="Coimbatore">Coimbatore</MenuItem>
|
||||
<MenuItem value="Madurai">Madurai</MenuItem>
|
||||
</Select>
|
||||
{errors.city && (
|
||||
<Typography
|
||||
color="error"
|
||||
variant="caption"
|
||||
sx={{ mt: 0.5, ml: 1.8 }}
|
||||
>
|
||||
{errors.city}
|
||||
</Typography>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{/* Pin code */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Pin code</label>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="pincode"
|
||||
label="Enter Pin code"
|
||||
value={data.pincode}
|
||||
onChange={(e) => handleChange("pincode", e.target.value)}
|
||||
error={Boolean(errors.pincode)}
|
||||
helperText={errors.pincode}
|
||||
inputProps={{ maxLength: 6 }}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
{/* Upload Profile (UI only) */}
|
||||
{/* <div className="flex flex-col gap-2 md:col-span-2 w-full max-w-[900px] ">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Upload Profile (Multi - Select)
|
||||
</label>
|
||||
<div className=" border-2 border-dashed border-gray-300 rounded-lg p-6 text-center bg-white">
|
||||
<div className="text-3xl mb-2">⬆</div>
|
||||
<p className="text-sm text-gray-600">Upload PDF, IMG, JPG</p>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
|
||||
<div className="flex flex-col gap-2 md:col-span-2 w-full">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Upload Profile (Multi - Select)
|
||||
</label>
|
||||
<AdvancedDropzone
|
||||
value={data.profiles || []}
|
||||
onChange={(files) => {
|
||||
// if you want to keep in Redux as plain metadata
|
||||
dispatch(updatePersonalDetails({ profiles: files }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
style={{
|
||||
marginTop: "40px",
|
||||
display: "flex",
|
||||
gap: 16,
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={onSkipStep}
|
||||
disabled={mobileOtpVerified}
|
||||
>
|
||||
Skip
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSubmit}
|
||||
// disabled={!mobileOtpVerified}
|
||||
>
|
||||
Submit & Next
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PersonalDetailsForm;
|
||||
Reference in new issue
Block a user