bug fixing

This commit is contained in:
Meenadeveloper 2026-03-09 18:16:38 +05:30
parent 805c93b3f3
commit 5392a4211e
8 changed files with 171 additions and 52 deletions

View File

@ -28,12 +28,13 @@ import axiosInstance, { logoutAPI } from "../../api/axiosInstance";
import toast from "react-hot-toast";
import { API_ENDPOINTS } from "../../api/apiEndpoints";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useSelector } from "react-redux";
const NAV_LINKS = [
// { label: "Home", path: "/" },
{ label: "Matches", path: "/matches" },
// { label: "ProfileCard", path: "/profile-card" },
{ label: "Interest", path: "/interest" },
{ label: "Horoscope", path: "/horoscoper-generate" },
// { label: "Horoscope", path: "/horoscoper-generate" },
{ label: "Messages", path: "/chat" },
{ label: "Search", path: "/matches" },
{ label: "Notifications", path: "/notifications" }
@ -159,6 +160,14 @@ const ProfileHeader = () => {
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [logoutModalOpen, setLogoutModalOpen] = useState(false);
const { personalDetails } = useSelector((state) => state.registerform);
const profileImage =
personalDetails?.profiles?.[0]?.preview ||
personalDetails?.profiles?.[0]?.url ||
personalDetails?.profiles?.[0] ||
userimg;
const theme = useTheme();
const isDesktop = useMediaQuery(theme.breakpoints.up("md"));
@ -200,7 +209,7 @@ const ProfileHeader = () => {
const deleteAccountMutation = useMutation({
mutationFn: async () => {
return await axiosInstance.delete(API_ENDPOINTS.DELETE_ACCOUNT);
return await axiosInstance.post(API_ENDPOINTS.DELETE_ACCOUNT);
},
onSuccess: (response) => {
toast.success(response?.data?.message || "Account deleted successfully");
@ -372,7 +381,7 @@ const ProfileHeader = () => {
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Account Menu">
<IconButton onClick={toggleProfileDrawer(true)}>
<Avatar sx={{width:"50px", height:"50px"}} src={userimg || "/static/images/avatar/2.jpg" }/>
<Avatar sx={{width:"50px", height:"50px"}} src={profileImage || userimg || "/static/images/avatar/2.jpg" }/>
</IconButton>

View File

@ -75,12 +75,12 @@ const AdvancedDropzone = ({ value, onChange }) => {
<>
<Dropzone
onChange={updateFiles}
minHeight="195px"
minHeight="200px"
value={extFiles}
accept="image/*"
maxFiles={3}
maxFileSize={10 * 1024 * 1024}
label="Drag'n drop up to 3 images (max 10 MB each)"
label={<span style={{ fontSize: "16px" }}>Drag'n drop up to 3 images (max 10 MB each)</span>}
uploadConfig={{
url: BASE_URL + "/file",
cleanOnUpload: true,
@ -107,14 +107,14 @@ const AdvancedDropzone = ({ value, onChange }) => {
<FileMosaic
{...file}
onDelete={onDelete}
onSee={handleSee}
onWatch={handleWatch}
// onSee={handleSee}
// onWatch={handleWatch}
onAbort={handleAbort}
onCancel={handleCancel}
resultOnTooltip
alwaysActive
preview
info={false}
// info={false}
/>
{hoveredId === file.id && (
<div
@ -155,9 +155,9 @@ const AdvancedDropzone = ({ value, onChange }) => {
}}
aria-label="Move left"
>
<ArrowLeftIcon fontSize="small" />
<ArrowLeftIcon fontSize="small" sx={{fontSize:"30px"}} />
</button>
<span
{/* <span
style={{
color: "#fff",
fontSize: 12,
@ -170,7 +170,7 @@ const AdvancedDropzone = ({ value, onChange }) => {
title={file.name}
>
{file.name}
</span>
</span> */}
<button
type="button"
onClick={(e) => {
@ -197,7 +197,7 @@ const AdvancedDropzone = ({ value, onChange }) => {
}}
aria-label="Move right"
>
<ArrowRightIcon fontSize="small" />
<ArrowRightIcon fontSize="small" sx={{fontSize:"30px"}} />
</button>
</div>
)}

View File

@ -33,7 +33,7 @@ import {
} from "../hooks/useDependentMasters";
import { useSendOtp, useVerifyOtp } from "../hooks/useAuth";
const OTP_LENGTH = 4;
const OTP_TIMER_SEC = 120; // 2 minutes
const OTP_TIMER_SEC = 60; // 1 minute
const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Update }) => {
const dispatch = useDispatch();
@ -51,25 +51,19 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const sendOtp = useSendOtp();
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);
if (isStep1Update && data.mobileNumber && !data.verifiedMobileNumber) {
dispatch(updatePersonalDetails({ verifiedMobileNumber: data.mobileNumber }));
setMobileOtpVerified(true);
initializedVerifiedNumber.current = true;
}
}, [isStep1Update, data.mobileNumber]);
}, [isStep1Update, data.mobileNumber, data.verifiedMobileNumber, dispatch]);
useEffect(() => {
if (verifiedMobileNumber && data.mobileNumber === verifiedMobileNumber) {
if (data.verifiedMobileNumber && data.mobileNumber === data.verifiedMobileNumber) {
setMobileOtpVerified(true);
}
}, [verifiedMobileNumber, data.mobileNumber]);
}, [data.verifiedMobileNumber, data.mobileNumber]);
const { data: personalMasters, isLoading: isPersonalMastersLoading } =
usePersonalDetailsMasters();
@ -282,11 +276,15 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
};
const handleChange = (field, value) => {
if (field === "name" && !/^[a-zA-Z\s]*$/.test(value)) {
return;
}
const updates = { [field]: value };
const fieldsToClear = [field];
if (field === "mobileNumber") {
setMobileNumberError("");
if (verifiedMobileNumber && value === verifiedMobileNumber) {
if (data.verifiedMobileNumber && value === data.verifiedMobileNumber) {
setMobileOtpVerified(true);
setShowOtp(false);
setOtpError("");
@ -373,8 +371,7 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
"OTP verified successfully";
toast.success(successMessage, { position: "top-right" });
setMobileOtpVerified(true);
setVerifiedMobileNumber(data.mobileNumber);
localStorage.setItem("registration_verified_mobile", data.mobileNumber);
dispatch(updatePersonalDetails({ verifiedMobileNumber: data.mobileNumber }));
setMobileNumberError("");
setOtpError("");
} catch (error) {
@ -387,6 +384,13 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
}
};
useEffect(() => {
if (showOtp && !mobileOtpVerified && isOtpComplete) {
handleOtpSubmit();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [otp]);
// file upload
@ -583,7 +587,7 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
</div>
{/* OTP Inputs */}
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-4">
{showOtp && !mobileOtpVerified && (
<>
<Box display="flex" gap={1} alignItems="center">
@ -595,7 +599,8 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
maxLength: 1,
style: {
textAlign: "center",
width: 40,
width: 20,
height:20,
fontSize: 20,
borderRadius: 4,
backgroundColor: digit
@ -628,14 +633,14 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
{otpTimer > 0 ? (
` ${formatTimer(otpTimer) } Seconds`
) : (
<Link
<button
component="button"
variant="body2"
onClick={resetOtp}
onClick={handleMobileSubmit}
disabled={otpTimer > 0}
>
Resend OTP
</Link>
</button>
)}
</Typography>
@ -1290,6 +1295,11 @@ const PersonalDetailsForm = ({ onSubmitStep, errors, onFieldChange, isStep1Updat
dispatch(updatePersonalDetails({ profiles: files }));
}}
/>
{errors.profiles && (
<p style={{ color: "#d32f2f", fontSize: "0.75rem", margin: "3px 14px 0 14px" }}>
{errors.profiles}
</p>
)}
</div>

View File

@ -1,5 +1,5 @@
import React, { useState } from "react";
import { useSelector } from 'react-redux';
import React, { useState, useEffect } from "react";
import { useSelector, useDispatch } from 'react-redux';
import { Swiper, SwiperSlide } from "swiper/react";
import { Navigation, Pagination } from "swiper/modules";
import "swiper/css";
@ -26,6 +26,7 @@ import {
import { usePreviewDetails } from "../hooks/usePreview";
import { isAuthenticated } from "../utills/auth";
import horoscopeImg from "../assets/images/horoscopeimg.png";
import { updatePersonalDetails } from "../redux/registrationFormSlice";
const PreviewScreen = ({ onEdit, onSubmit }) => {
const formData = useSelector((state) => state.registerform);
@ -34,6 +35,22 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
const isLoading = isAuth && apiLoading;
const isError = isAuth && apiError;
const dispatch = useDispatch();
useEffect(() => {
const pd = previewData?.personal_details;
if (pd) {
const images = pd.images || pd.profile_images;
if (images && images.length > 0) {
// Map images to ensure they have a consistent format for Redux
const formattedImages = images.map(img =>
typeof img === 'string' ? { url: img, preview: img } : img
);
dispatch(updatePersonalDetails({ profiles: formattedImages }));
}
}
}, [previewData, dispatch]);
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
const handleConfirmSubmit = () => {

View File

@ -1,8 +1,9 @@
import { Swiper, SwiperSlide } from "swiper/react";
import { Navigation, Autoplay } from "swiper/modules";
import { ChevronLeft, ChevronRight, Edit2 } from "lucide-react";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useDispatch } from "react-redux";
import "swiper/css";
import "swiper/css/navigation";
import LazyImage from "../components/common/LazyImage";
@ -28,6 +29,7 @@ import {
} from "@mui/material";
import { Info } from "@mui/icons-material";
import { usePreviewDetails } from "../hooks/usePreview";
import { updatePersonalDetails } from "../redux/registrationFormSlice";
const images = [
weddingpromo1, // bride in saree
@ -44,8 +46,22 @@ const images = [
const ProfilePreviewPage = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const { data, isLoading } = usePreviewDetails();
useEffect(() => {
if (data?.personal_details) {
const pd = data.personal_details;
const images = pd.images || pd.profile_images;
if (images && images.length > 0) {
const formattedImages = images.map((img) =>
typeof img === "string" ? { url: img, preview: img } : img
);
dispatch(updatePersonalDetails({ profiles: formattedImages }));
}
}
}, [data, dispatch]);
const personalDetails = data?.personal_details
? {
name: data.personal_details.name,

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { ChevronLeft } from "lucide-react";
import { useDispatch, useSelector } from "react-redux";
import {
@ -28,6 +28,7 @@ import axiosInstance, { apiForFiles, setAccessToken } from "../api/axiosInstance
import toast from "react-hot-toast";
import { API_ENDPOINTS } from "../api/apiEndpoints";
import { isAuthenticated } from "../utills/auth";
import { getPreviewDetails } from "../api/preview.api";
const STEP_FIELD_ORDER = {
1: [
"name",
@ -228,6 +229,7 @@ const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick }) =>
const StepperForm = () => {
const dispatch = useDispatch();
const queryClient = useQueryClient();
const location = useLocation();
const navigate = useNavigate();
const hideStepperRoutes = ["/profile-edit"];
@ -434,10 +436,16 @@ const [completedSteps, setCompletedSteps] = useState([]);
rawImages.map(async (url, index) => {
const imageUrl = typeof url === "string" ? url : url?.url;
let file = null;
let mimeType = "image/jpeg";
let fileName = `image-${index}.jpg`;
try {
const response = await fetch(imageUrl);
const blob = await response.blob();
file = new File([blob], `image-${index}.png`, { type: "image/png" });
if (blob.type) mimeType = blob.type;
const ext = mimeType.split("/")[1] || "jpg";
fileName = `image-${index}.${ext}`;
file = new File([blob], fileName, { type: mimeType });
} catch (error) {
console.error("Error converting image URL to File:", error);
}
@ -446,8 +454,8 @@ const [completedSteps, setCompletedSteps] = useState([]);
preview: imageUrl,
imageUrl: imageUrl,
file: file,
name: `image-${index}.png`,
type: "image/png",
name: fileName,
type: mimeType,
valid: true,
};
})
@ -669,13 +677,16 @@ useEffect(()=>{
required.forEach((field) => {
if (!personalDetails[field]) {
newErrors[field] = "This field is required";
const label = field
.replace(/([A-Z])/g, " $1")
.replace(/^./, (str) => str.toUpperCase());
newErrors[field] = `${label} is required`;
}
});
if (!isStep1Update) {
if (!personalDetails.password) newErrors.password = "This field is required";
if (!personalDetails.confirmPassword) newErrors.confirmPassword = "This field is required";
if (!personalDetails.password) newErrors.password = "Password is required";
if (!personalDetails.confirmPassword) newErrors.confirmPassword = "Confirm Password is required";
}
if (
@ -733,19 +744,44 @@ useEffect(()=>{
newErrors[field] = `${label} is required`;
}
});
if (familyDetails.fatherName && !/^[a-zA-Z\s]*$/.test(familyDetails.fatherName)) {
newErrors.fatherName = "Father Name must contain only alphabets";
}
if (familyDetails.motherName && !/^[a-zA-Z\s]*$/.test(familyDetails.motherName)) {
newErrors.motherName = "Mother Name must contain only alphabets";
}
} else if (step === 4) {
const required = ["diets", "hobbies", "dob", "tob"];
required.forEach((field) => {
const value = lifestyleDetails[field];
if (Array.isArray(value)) {
if (value.length === 0) newErrors[field] = "This field is required";
if (value.length === 0) {
if (field === "hobbies") {
newErrors[field] = "Hobbies and Interests is required";
} else {
newErrors[field] = "This field is required";
}
}
} else if (!value) {
// newErrors[field] = "This field is required";
if (field === "dob") {
newErrors[field] = "Date of Birth is required";
}
else if (field === "tob") {
newErrors[field] = "Time of Birth is required";
}
else if (field === "diets") {
newErrors[field] = "Diet is required";
}
else {
const label = field
.replace(/([A-Z])/g, " $1")
.replace(/^./, (str) => str.toUpperCase());
newErrors[field] = `${label} is required`;
}
}
});
} else if (step === 5) {
@ -764,7 +800,11 @@ useEffect(()=>{
const value = partnerPreferences[field];
if (Array.isArray(value)) {
if (value.length === 0) {
newErrors[field] = "This field is required";
// newErrors[field] = "This field is required";
const label = field
.replace(/([A-Z])/g, " $1")
.replace(/^./, (str) => str.toUpperCase());
newErrors[field] = `${label} is required`;
}
return;
}
@ -823,8 +863,10 @@ useEffect(()=>{
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 mimeType = blob.type || "image/jpeg";
const ext = mimeType.split("/")[1] || "jpg";
const fileName = item.name || `profile_image_${index}.${ext}`;
const fileType = item.type || mimeType;
fileToAppend = new File([blob], fileName, { type: fileType });
} catch (e) {
console.error(`Could not recover file from URL: ${item.preview}`, e);
@ -977,6 +1019,23 @@ useEffect(()=>{
if (isStep1Update) {
res = await apiForFiles.post("/update_personal_details", payload);
try {
const previewData = await getPreviewDetails();
if (previewData?.personal_details) {
const pd = previewData.personal_details;
const images = pd.images || pd.profile_images;
if (images && images.length > 0) {
const formattedImages = images.map((img) =>
typeof img === "string" ? { url: img, preview: img } : img
);
dispatch(updatePersonalDetails({ profiles: formattedImages }));
}
}
queryClient.invalidateQueries({ queryKey: ["previewDetails"] });
} catch (error) {
console.error("Error refreshing preview details:", error);
}
} else {
res = await registerStep1.mutateAsync(payload);
}

View File

@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import { getContactUs } from '../api/contact.api';
import LazyImage from '../components/common/LazyImage';
import InstagramIcon from '@mui/icons-material/Instagram';
import WhatsAppIcon from '@mui/icons-material/WhatsApp';
import FacebookIcon from '@mui/icons-material/Facebook';
import SvgIcon from '@mui/material/SvgIcon';
import { Phone, Mail, ChevronRight } from 'lucide-react';
@ -39,7 +40,13 @@ const ContactUsPage = () => {
icon: <XIcon fontSize="large" />,
color: "from-gray-800 to-black",
url: contact.x_url
}
},
{
name: "WhatsApp",
icon: <WhatsAppIcon fontSize="large" />,
color: "from-green-500 to-green-600",
url: contact.whatsapp_mobile ? `https://wa.me/${contact.whatsapp_mobile}` : null
},
];
if (isLoading) {

View File

@ -19,9 +19,10 @@ const PublicRoutes = () => {
<>
<Route element={<HomeLayout />}>
<Route path="/" element={<HomePage />} />
<Route element={<PublicGuard />}>
{/* <Route element={<PublicGuard />}>
</Route> */}
<Route path="/registration" element={<StepperForm />} />
</Route>
</Route>
<Route element={<PublicGuard />}>