Build and deployment update: Refined registration forms, stepper navigation, and chat synchronization fixes
This commit is contained in:
parent
68f97c40dc
commit
c467271927
@ -1,65 +1,71 @@
|
|||||||
export const API_ENDPOINTS = {
|
export const API_ENDPOINTS = {
|
||||||
LOGOUT: "logout",
|
LOGOUT: "logout",
|
||||||
TERMS_AND_POLICIES_PRIVACY:"terms-and-policies",
|
TERMS_AND_POLICIES_PRIVACY: "terms-and-policies",
|
||||||
// registration api's
|
// registration api's
|
||||||
PERSONAL_DETAILS_MASTER :"personal_details_masters",
|
PERSONAL_DETAILS_MASTER: "personal_details_masters",
|
||||||
CASTE_MASTER : "get_caste_masters",
|
CASTE_MASTER: "get_caste_masters",
|
||||||
SUB_CASTE_MASTER : "get_sub_caste_masters",
|
SUB_CASTE_MASTER: "get_sub_caste_masters",
|
||||||
CITY_MASTER : "get_district_masters",
|
CITY_MASTER: "get_district_masters",
|
||||||
STAR_MASTER : "get_star_masters",
|
STAR_MASTER: "get_star_masters",
|
||||||
MOBILE_SEND_OTP: "send_otp",
|
MOBILE_SEND_OTP: "send_otp",
|
||||||
MOBILE_VERIFY_OTP: "verify_otp",
|
MOBILE_VERIFY_OTP: "verify_otp",
|
||||||
|
|
||||||
EDUCATION_DETAILS_MASTER: "educational_details_masters",
|
EDUCATION_DETAILS_MASTER: "educational_details_masters",
|
||||||
EDUCATION_LIST_API:"get_education",
|
EDUCATION_LIST_API: "get_education",
|
||||||
|
|
||||||
FAMILY_DETAILS_MASTER: "family_details_masters", // family details master api
|
FAMILY_DETAILS_MASTER: "family_details_masters", // family details master api
|
||||||
|
|
||||||
LIFESTYLE_DETAILS_MASTER:"lifetstyle_details_masters",
|
LIFESTYLE_DETAILS_MASTER: "lifetstyle_details_masters",
|
||||||
|
|
||||||
PREFERED_PARTNER_DETAILS_MASTER:"prefered_details_masters",
|
PREFERED_PARTNER_DETAILS_MASTER: "prefered_details_masters",
|
||||||
|
|
||||||
REGISTER_STEP1: "register", // register api
|
REGISTER_STEP1: "register", // register api
|
||||||
REGISTER_STEP2:"update_educational_details", // educational details updated api
|
REGISTER_STEP2: "update_educational_details", // educational details updated api
|
||||||
REGSITER_STEP3:"update_family_details", // family details updated api
|
REGSITER_STEP3: "update_family_details", // family details updated api
|
||||||
REGISTER_STEP4:"update_lifestyle_details", // lifestyle details updated api
|
REGISTER_STEP4: "update_lifestyle_details", // lifestyle details updated api
|
||||||
REGISTER_STEP5:"update_preferred_details", // partner preference details updated api
|
REGISTER_STEP5: "update_preferred_details", // partner preference details updated api
|
||||||
PREVIEW_DETAILS: "get_preview_details",
|
PREVIEW_DETAILS: "get_preview_details",
|
||||||
REVIEWS: "reviews",
|
REVIEWS: "reviews",
|
||||||
|
|
||||||
// edit api's autopapulated
|
// edit api's autopapulated
|
||||||
|
|
||||||
EDIT_PERSONAL_DETAILS: "get_personal_details",
|
EDIT_PERSONAL_DETAILS: "get_personal_details",
|
||||||
EDIT_EDUCATION_DETAILS: "get_educational_details",
|
EDIT_EDUCATION_DETAILS: "get_educational_details",
|
||||||
EDIT_FAMILY_DETAILS: "get_family_details",
|
EDIT_FAMILY_DETAILS: "get_family_details",
|
||||||
EDIT_LIFESTYLE_DETAILS: "get_lifestyle_details",
|
EDIT_LIFESTYLE_DETAILS: "get_lifestyle_details",
|
||||||
EDIT_PREFERED_PARTNER_DETAILS: "get_preferred_details",
|
EDIT_PREFERED_PARTNER_DETAILS: "get_preferred_details",
|
||||||
|
|
||||||
// delete api
|
// delete api
|
||||||
|
|
||||||
DELETE_ACCOUNT: "delete_account",
|
DELETE_ACCOUNT: "delete_account",
|
||||||
PHONE_NUMBER_VISIBILITY: "get_phone_number_visibility",
|
PHONE_NUMBER_VISIBILITY: "get_phone_number_visibility",
|
||||||
UPDATE_PHONE_NUMBER_VISIBILITY: "update_phone_number_visibility",
|
UPDATE_PHONE_NUMBER_VISIBILITY: "update_phone_number_visibility",
|
||||||
CHAT_ALERT_NOTIFICATION:"get_chat_alert_notification",
|
CHAT_ALERT_NOTIFICATION: "get_chat_alert_notification",
|
||||||
UPDATE_CHAT_ALERT_NOTIFICATION:"update_chat_alert_notification",
|
UPDATE_CHAT_ALERT_NOTIFICATION: "update_chat_alert_notification",
|
||||||
PROFILE_PROTECT_API:"get_profile_protection",
|
PROFILE_PROTECT_API: "get_profile_protection",
|
||||||
UPDATE_PROFILE_PROTECT_API:"update_profile_protection",
|
UPDATE_PROFILE_PROTECT_API: "update_profile_protection",
|
||||||
MATCH_ALERT:"get_match_alert",
|
MATCH_ALERT: "get_match_alert",
|
||||||
UPDATE_MATCH_ALERT:"update_match_alert",
|
UPDATE_MATCH_ALERT: "update_match_alert",
|
||||||
WHO_CAN_VIEW_MESSAGE:"get_who_can_message_me",
|
WHO_CAN_VIEW_MESSAGE: "get_who_can_message_me",
|
||||||
UPDATE_WHO_CAN_VIEW_MESSAGE:"update_who_can_message_me",
|
UPDATE_WHO_CAN_VIEW_MESSAGE: "update_who_can_message_me",
|
||||||
CONTACT_US:"get_contact_us",
|
CONTACT_US: "get_contact_us",
|
||||||
BE_SAFE_ONLINE:"get_be_safe_online",
|
BE_SAFE_ONLINE: "get_be_safe_online",
|
||||||
NOTIFICATION_LIST:"notification/lists",
|
NOTIFICATION_LIST: "notification/lists",
|
||||||
NOTIFICATION_COUNT:"notification/un_read_count",
|
NOTIFICATION_COUNT: "notification/un_read_count",
|
||||||
|
|
||||||
// filter with profiles list api's
|
// filter with profiles list api's
|
||||||
PROFILES_FILTER_LIST:"profiles/lists",
|
PROFILES_FILTER_LIST: "profiles/lists",
|
||||||
PROFILES_FILTER_MASTER:"profiles/filter/masters",
|
PROFILES_FILTER_MASTER: "profiles/filter/masters",
|
||||||
|
|
||||||
|
|
||||||
DASHBOARD_API:"dashboard",
|
|
||||||
HEADER_API:"header_data",
|
|
||||||
SHORTLIST_API:"shortlist_profile",
|
|
||||||
|
|
||||||
|
DASHBOARD_API: "dashboard",
|
||||||
|
HEADER_API: "header_data",
|
||||||
|
SHORTLIST_API: "shortlist_profile",
|
||||||
|
BLOCK_PROFILE_LIST: "block_profile_list",
|
||||||
|
REPORT_PROFILE_LIST: "report_profile_list",
|
||||||
|
PROFILE_DETAIL: "profiles/detail",
|
||||||
|
INTEREST_LIST: "interest_lists",
|
||||||
|
UPDATE_INTEREST_STATUS: "update_interest_status",
|
||||||
|
CHAT_LIST: "chat/lists",
|
||||||
|
CHAT_MESSAGES: (id) => `chat/${id}/messages`,
|
||||||
|
UNREAD_CHAT_COUNT: "chat/un_read_chat_count",
|
||||||
};
|
};
|
||||||
|
|||||||
@ -242,7 +242,7 @@ const navigate = useNavigate();
|
|||||||
>
|
>
|
||||||
<div onClick={(e) => e.stopPropagation()} className="bg-white rounded-2xl shadow-xl overflow-hidden select-none">
|
<div onClick={(e) => e.stopPropagation()} className="bg-white rounded-2xl shadow-xl overflow-hidden select-none">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div classname=" relative bg-gray-200 overflow-hidden w-full max-w-sm h-[300px]" style={{height:"300px"}}>
|
<div className=" relative bg-gray-200 overflow-hidden w-full max-w-sm h-[300px]" style={{height:"300px"}}>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
src={profile.image}
|
src={profile.image}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import Toolbar from "@mui/material/Toolbar";
|
|||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
|
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
|
||||||
|
import { useWebSocket } from "../../hooks/useWebSocket";
|
||||||
import List from "@mui/material/List";
|
import List from "@mui/material/List";
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from "@mui/material/ListItem";
|
||||||
import ListItemButton from "@mui/material/ListItemButton";
|
import ListItemButton from "@mui/material/ListItemButton";
|
||||||
@ -19,7 +20,7 @@ import Button from "@mui/material/Button";
|
|||||||
import LazyImage from "./LazyImage";
|
import LazyImage from "./LazyImage";
|
||||||
import Logo from "../../assets/images/logo.png";
|
import Logo from "../../assets/images/logo.png";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import { useState, useRef, useEffect } from "react";
|
import { useState, useRef, useEffect, useMemo } from "react";
|
||||||
import { useTheme, useMediaQuery, ListItemIcon } from "@mui/material";
|
import { useTheme, useMediaQuery, ListItemIcon } from "@mui/material";
|
||||||
import { Home, Users, Heart, MessageCircle, Search, Bell } from "lucide-react";
|
import { Home, Users, Heart, MessageCircle, Search, Bell } from "lucide-react";
|
||||||
import { isAuthenticated } from "../../utills/auth";
|
import { isAuthenticated } from "../../utills/auth";
|
||||||
@ -27,7 +28,7 @@ import userimg from "../../assets/images/bride1.jpg"
|
|||||||
import axiosInstance, { logoutAPI } from "../../api/axiosInstance";
|
import axiosInstance, { logoutAPI } from "../../api/axiosInstance";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { API_ENDPOINTS } from "../../api/apiEndpoints";
|
import { API_ENDPOINTS } from "../../api/apiEndpoints";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { getHeaderDetails } from "../../api/preview.api";
|
import { getHeaderDetails } from "../../api/preview.api";
|
||||||
const NAV_LINKS = [
|
const NAV_LINKS = [
|
||||||
@ -160,6 +161,7 @@ const ProfileHeader = () => {
|
|||||||
const [profileDrawerOpen, setProfileDrawerOpen] = useState(false);
|
const [profileDrawerOpen, setProfileDrawerOpen] = useState(false);
|
||||||
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
||||||
const [logoutModalOpen, setLogoutModalOpen] = useState(false);
|
const [logoutModalOpen, setLogoutModalOpen] = useState(false);
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const { personalDetails } = useSelector((state) => state.registerform);
|
const { personalDetails } = useSelector((state) => state.registerform);
|
||||||
|
|
||||||
@ -189,17 +191,104 @@ const ProfileHeader = () => {
|
|||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
enabled: !!auth,
|
enabled: !!auth,
|
||||||
|
refetchInterval: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// WebSocket for real-time updates - Match the robust strategy from ChatPage
|
||||||
|
const profileId = localStorage.getItem("profile_id");
|
||||||
|
const userId = localStorage.getItem("user_id");
|
||||||
|
|
||||||
|
const wsChannels = useMemo(() => {
|
||||||
|
const channels = [];
|
||||||
|
if (profileId && profileId !== "null") {
|
||||||
|
channels.push(`user-chat-notification${profileId}`);
|
||||||
|
channels.push(`user-chat-notification.${profileId}`);
|
||||||
|
channels.push(`partner-chat${profileId}`);
|
||||||
|
channels.push(`partner-chat.${profileId}`);
|
||||||
|
}
|
||||||
|
if (userId && userId !== "null") {
|
||||||
|
channels.push(`user-notification${userId}`);
|
||||||
|
channels.push(`user-notification.${userId}`);
|
||||||
|
}
|
||||||
|
return [...new Set(channels.filter(Boolean))];
|
||||||
|
}, [profileId, userId]);
|
||||||
|
|
||||||
|
const { messages: wsMessages, isConnected } = useWebSocket(wsChannels);
|
||||||
|
const processedMsgCount = useRef(wsMessages.length);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected) {
|
||||||
|
console.log("[HEADER-WS] Connected, refreshing badges...");
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["notificationCount"] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["unreadChatCount"] });
|
||||||
|
}
|
||||||
|
}, [isConnected, queryClient]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (wsMessages.length > processedMsgCount.current) {
|
||||||
|
const newWsMsgs = wsMessages.slice(processedMsgCount.current);
|
||||||
|
console.log(`[HEADER-WS] Detected ${newWsMsgs.length} new signals.`);
|
||||||
|
|
||||||
|
let shouldRefresh = false;
|
||||||
|
|
||||||
|
newWsMsgs.forEach(lastMsg => {
|
||||||
|
if (lastMsg.event?.startsWith('pusher:')) return;
|
||||||
|
|
||||||
|
// Lenient detection matching ChatPage
|
||||||
|
const isMessageEvent = lastMsg.event?.toLowerCase().includes('message') ||
|
||||||
|
lastMsg.event?.toLowerCase().includes('chat') ||
|
||||||
|
lastMsg.event?.toLowerCase().includes('notification');
|
||||||
|
|
||||||
|
if (isMessageEvent) {
|
||||||
|
console.log(`[HEADER-WS] Relevant event detected: ${lastMsg.event}, refreshing counts...`);
|
||||||
|
shouldRefresh = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldRefresh) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["unreadChatCount"] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["notificationCount"] });
|
||||||
|
}
|
||||||
|
|
||||||
|
processedMsgCount.current = wsMessages.length;
|
||||||
|
}
|
||||||
|
}, [wsMessages, queryClient]);
|
||||||
|
|
||||||
|
const { data: chatCountData } = useQuery({
|
||||||
|
queryKey: ["unreadChatCount"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const res = await axiosInstance.get(API_ENDPOINTS.UNREAD_CHAT_COUNT);
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
enabled: !!auth,
|
||||||
|
refetchInterval: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const notificationCount = notificationData?.count || 0;
|
const notificationCount = notificationData?.count || 0;
|
||||||
|
const chatCount = chatCountData?.count || 0;
|
||||||
|
|
||||||
|
|
||||||
const { data: headerData } = useQuery({
|
const { data: headerData } = useQuery({
|
||||||
queryKey: ["headerDetails"],
|
queryKey: ["headerDetails"],
|
||||||
queryFn: getHeaderDetails,
|
queryFn: getHeaderDetails,
|
||||||
enabled: !!auth,
|
enabled: !!auth,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// AUTO-SYNC: Recover missing IDs from Header API data
|
||||||
|
useEffect(() => {
|
||||||
|
if (headerData?.myDetails) {
|
||||||
|
const myId = headerData.myDetails.id || headerData.myDetails.profile_id;
|
||||||
|
const uId = headerData.myDetails.user_id;
|
||||||
|
if (myId && (localStorage.getItem("profile_id") === "null" || !localStorage.getItem("profile_id"))) {
|
||||||
|
localStorage.setItem("profile_id", myId);
|
||||||
|
console.log("Header API auto-synced profileId:", myId);
|
||||||
|
}
|
||||||
|
if (uId && (localStorage.getItem("user_id") === "null" || !localStorage.getItem("user_id"))) {
|
||||||
|
localStorage.setItem("user_id", uId);
|
||||||
|
console.log("Header API auto-synced userId:", uId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [headerData]);
|
||||||
|
|
||||||
const apiProfileImage = headerData?.myDetails?.profile;
|
const apiProfileImage = headerData?.myDetails?.profile;
|
||||||
|
|
||||||
const handleMenuClick = (item) => {
|
const handleMenuClick = (item) => {
|
||||||
@ -327,10 +416,17 @@ const ProfileHeader = () => {
|
|||||||
{getNavIcon(index)}
|
{getNavIcon(index)}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={
|
<ListItemText primary={
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between w-full pr-4">
|
||||||
{label}
|
<span>{label}</span>
|
||||||
{label === "Notifications" && notificationCount > 0 && (
|
{label === "Notifications" && notificationCount > 0 && (
|
||||||
<span className="bg-red-600 text-white text-xs px-2 py-0.5 rounded-full">{notificationCount}</span>
|
<span className="bg-red-600 text-white text-[10px] font-bold px-1.5 py-0.5 rounded-full min-w-[18px] flex items-center justify-center ml-2">
|
||||||
|
{notificationCount}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{label === "Messages" && chatCount > 0 && (
|
||||||
|
<span className="bg-red-600 text-white text-[10px] font-bold px-1.5 py-0.5 rounded-full min-w-[18px] flex items-center justify-center ml-2">
|
||||||
|
{chatCount}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
} />
|
} />
|
||||||
@ -376,7 +472,10 @@ const ProfileHeader = () => {
|
|||||||
items={NAV_LINKS.map(link => link.label)}
|
items={NAV_LINKS.map(link => link.label)}
|
||||||
color="#034E08"
|
color="#034E08"
|
||||||
activeItem={currentLabel}
|
activeItem={currentLabel}
|
||||||
badges={{ "Notifications": notificationCount }}
|
badges={{
|
||||||
|
"Notifications": notificationCount,
|
||||||
|
"Messages": chatCount
|
||||||
|
}}
|
||||||
onItemClick={(item) => {
|
onItemClick={(item) => {
|
||||||
setSelectedItem(item);
|
setSelectedItem(item);
|
||||||
const link = NAV_LINKS.find(l => l.label === item);
|
const link = NAV_LINKS.find(l => l.label === item);
|
||||||
@ -386,7 +485,7 @@ const ProfileHeader = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{(auth ? (
|
{(auth ? (
|
||||||
<Box sx={{ flexGrow: 0 }}>
|
<Box key="user-menu-box" sx={{ flexGrow: 0 }}>
|
||||||
<Tooltip title="Account Menu">
|
<Tooltip title="Account Menu">
|
||||||
<IconButton onClick={toggleProfileDrawer(true)}>
|
<IconButton onClick={toggleProfileDrawer(true)}>
|
||||||
<Avatar sx={{width:"50px", height:"50px"}} src={apiProfileImage || profileImage || userimg || "/static/images/avatar/2.jpg" }/>
|
<Avatar sx={{width:"50px", height:"50px"}} src={apiProfileImage || profileImage || userimg || "/static/images/avatar/2.jpg" }/>
|
||||||
@ -395,7 +494,7 @@ const ProfileHeader = () => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
):( <button className="ml-1 bg-red-900 text-white px-4 py-2 rounded-md hover:bg-red-800 transition-colors"
|
):( <button key="sign-in-btn" className="ml-1 bg-red-900 text-white px-4 py-2 rounded-md hover:bg-red-800 transition-colors"
|
||||||
onClick={() => navigate("/login")}>Sign In / Sign Up</button>))}
|
onClick={() => navigate("/login")}>Sign In / Sign Up</button>))}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -125,7 +125,7 @@ const AppPromoteSection = () => {
|
|||||||
className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-16 max-w-6xl mx-auto"
|
className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-16 max-w-6xl mx-auto"
|
||||||
>
|
>
|
||||||
{features.map((feature, index) => (
|
{features.map((feature, index) => (
|
||||||
<div className="relative overflow-hidden bg-white rounded-2xl p-2 shadow-xl hover:shadow-2xl transition-all duration-300 overflow-hidden">
|
<div key={index} className="relative overflow-hidden bg-white rounded-2xl p-2 shadow-xl hover:shadow-2xl transition-all duration-300 overflow-hidden">
|
||||||
<BorderBeam
|
<BorderBeam
|
||||||
colorFrom="#ff0000ff"
|
colorFrom="#ff0000ff"
|
||||||
colorTo="#338105ff"
|
colorTo="#338105ff"
|
||||||
|
|||||||
@ -379,7 +379,7 @@ const DailyRecommendedCard = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Custom Swiper Styles */}
|
{/* Custom Swiper Styles */}
|
||||||
<style jsx global>{`
|
<style>{`
|
||||||
.swiper-pagination-bullet {
|
.swiper-pagination-bullet {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|||||||
@ -307,7 +307,7 @@ const MatchingList = ({ matches }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Custom Swiper Styles */}
|
{/* Custom Swiper Styles */}
|
||||||
<style jsx global>{`
|
<style>{`
|
||||||
.swiper-pagination-bullet {
|
.swiper-pagination-bullet {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|||||||
@ -84,14 +84,6 @@ const ProfileCard = ({ profile }) => {
|
|||||||
const zodiac2 = profile.star_name || profile.zodiac2 || null;
|
const zodiac2 = profile.star_name || profile.zodiac2 || null;
|
||||||
const isPremium = profile.is_paid_member !== undefined ? profile.is_paid_member === 1 : profile.isPremium;
|
const isPremium = profile.is_paid_member !== undefined ? profile.is_paid_member === 1 : profile.isPremium;
|
||||||
|
|
||||||
const NewJoinedProfile = ({ profiles }) => {
|
|
||||||
const swiperRef = useRef(null);
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
const displayProfiles = profiles || [];
|
|
||||||
if (displayProfiles.length === 0) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, scale: 0.9 }}
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
@ -167,7 +159,7 @@ const NewJoinedProfile = ({ profiles }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-4 mt-[15px] justify-center">
|
<div className="flex gap-4 mt-[15px] justify-center">
|
||||||
<button
|
{/* <button
|
||||||
className={`px-2 py-1 rounded-[20px] border border-red-200 bg-red-50 flex items-center gap-1.5 font-semibold text-red-900 hover:bg-red-100 transition-colors ${declineMutation.isPending ? "opacity-50 cursor-wait" : ""}`}
|
className={`px-2 py-1 rounded-[20px] border border-red-200 bg-red-50 flex items-center gap-1.5 font-semibold text-red-900 hover:bg-red-100 transition-colors ${declineMutation.isPending ? "opacity-50 cursor-wait" : ""}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -176,7 +168,7 @@ const NewJoinedProfile = ({ profiles }) => {
|
|||||||
disabled={declineMutation.isPending}
|
disabled={declineMutation.isPending}
|
||||||
>
|
>
|
||||||
<X size={18} /> {declineMutation.isPending ? "..." : "Decline"}
|
<X size={18} /> {declineMutation.isPending ? "..." : "Decline"}
|
||||||
</button>
|
</button> */}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className={`px-2 py-1 rounded-[20px] border border-green-200 bg-green-50 text-green-900 flex items-center gap-1.5 font-semibold hover:bg-green-100 transition-colors ${interestMutation.isPending ? "opacity-50 cursor-wait" : ""}`}
|
className={`px-2 py-1 rounded-[20px] border border-green-200 bg-green-50 text-green-900 flex items-center gap-1.5 font-semibold hover:bg-green-100 transition-colors ${interestMutation.isPending ? "opacity-50 cursor-wait" : ""}`}
|
||||||
@ -191,9 +183,17 @@ const NewJoinedProfile = ({ profiles }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NewJoinedProfile = ({ profiles }) => {
|
||||||
|
const swiperRef = useRef(null);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const displayProfiles = profiles || [];
|
||||||
|
if (displayProfiles.length === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ const NewJoinedProfile = ({ profiles }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Custom Swiper Styles */}
|
{/* Custom Swiper Styles */}
|
||||||
<style jsx global>{`
|
<style>{`
|
||||||
.swiper-pagination-bullet {
|
.swiper-pagination-bullet {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|||||||
@ -216,7 +216,7 @@ const VideoSwiperGallery = ({ videos }) => {
|
|||||||
{selectedVideo && <VideoModal />}
|
{selectedVideo && <VideoModal />}
|
||||||
|
|
||||||
{/* Custom Swiper Styles */}
|
{/* Custom Swiper Styles */}
|
||||||
<style jsx global>{`
|
<style>{`
|
||||||
.swiper-pagination-bullet {
|
.swiper-pagination-bullet {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import React, { useState, useRef } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
Heart,
|
Heart,
|
||||||
X,
|
X,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
SkipForward,
|
|
||||||
Bookmark,
|
Bookmark,
|
||||||
MessageCircle,
|
MessageCircle,
|
||||||
Ban,
|
Ban,
|
||||||
@ -19,8 +18,10 @@ import "swiper/css/navigation";
|
|||||||
import "swiper/css/pagination";
|
import "swiper/css/pagination";
|
||||||
import "swiper/css/thumbs";
|
import "swiper/css/thumbs";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { sendInterest, shortlistProfile } from "../../services/shortlistapi";
|
||||||
|
import { toast } from "react-hot-toast";
|
||||||
|
|
||||||
const MatrimonyProfile = () => {
|
const MatrimonyProfile = ({ data }) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
@ -28,26 +29,17 @@ const MatrimonyProfile = () => {
|
|||||||
const mainSwiperRef = useRef(null);
|
const mainSwiperRef = useRef(null);
|
||||||
const modalSwiperRef = useRef(null);
|
const modalSwiperRef = useRef(null);
|
||||||
|
|
||||||
const profile = {
|
if (!data) return null;
|
||||||
name: "Sudharshan M",
|
|
||||||
id: "M8355880",
|
const profile = data.profile;
|
||||||
verified: true,
|
const personal = data.personalDetails;
|
||||||
lastSeen: "Last seen few hour ago",
|
const family = data.familyDetails;
|
||||||
age: "30 yrs",
|
const education = data.educationalDetails;
|
||||||
height: "5'5\"",
|
const lifestyle = data.lifestyleDetails;
|
||||||
caste: "Brahmin",
|
|
||||||
education: "Engineer - Non IT",
|
const profileImages = personal.images && personal.images.length > 0
|
||||||
location: "Chennai",
|
? personal.images
|
||||||
maritalStatus: "Never Married",
|
: [profile.profile_picture || "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png"];
|
||||||
createdBy: "Profile created by sibling",
|
|
||||||
images: [
|
|
||||||
"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=600&h=800&fit=crop",
|
|
||||||
"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=600&h=800&fit=crop",
|
|
||||||
"https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=600&h=800&fit=crop",
|
|
||||||
"https://images.unsplash.com/photo-1519085360753-af0119f7cbe7?w=600&h=800&fit=crop",
|
|
||||||
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=600&h=800&fit=crop",
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const openModal = (index) => {
|
const openModal = (index) => {
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
@ -58,6 +50,31 @@ const MatrimonyProfile = () => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSendInterest = async () => {
|
||||||
|
try {
|
||||||
|
const res = await sendInterest(profile.id);
|
||||||
|
toast.success(res.message || "Interest sent successfully");
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(error.message || "Failed to send interest");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShortlist = async () => {
|
||||||
|
try {
|
||||||
|
const res = await shortlistProfile(profile.id);
|
||||||
|
toast.success(res.message || "Profile shortlisted successfully");
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(error.message || "Failed to shortlist");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const safeVal = (val, key) => {
|
||||||
|
if (typeof val === 'object' && val !== null) {
|
||||||
|
return val[key] || "N/A";
|
||||||
|
}
|
||||||
|
return val || "N/A";
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="">
|
<div className="">
|
||||||
<div
|
<div
|
||||||
@ -76,16 +93,12 @@ const MatrimonyProfile = () => {
|
|||||||
prevEl: ".swiper-button-prev-custom",
|
prevEl: ".swiper-button-prev-custom",
|
||||||
nextEl: ".swiper-button-next-custom",
|
nextEl: ".swiper-button-next-custom",
|
||||||
}}
|
}}
|
||||||
pagination={{
|
|
||||||
type: "fraction",
|
|
||||||
el: ".swiper-pagination-custom",
|
|
||||||
}}
|
|
||||||
onSwiper={(swiper) => {
|
onSwiper={(swiper) => {
|
||||||
mainSwiperRef.current = swiper;
|
mainSwiperRef.current = swiper;
|
||||||
}}
|
}}
|
||||||
className="h-full w-full"
|
className="h-full w-full"
|
||||||
>
|
>
|
||||||
{profile.images.map((img, idx) => (
|
{profileImages.map((img, idx) => (
|
||||||
<SwiperSlide key={idx}>
|
<SwiperSlide key={idx}>
|
||||||
<div
|
<div
|
||||||
className="w-[320px] h-[330px] cursor-pointer"
|
className="w-[320px] h-[330px] cursor-pointer"
|
||||||
@ -95,35 +108,21 @@ const MatrimonyProfile = () => {
|
|||||||
src={img}
|
src={img}
|
||||||
alt={`${profile.name} ${idx + 1}`}
|
alt={`${profile.name} ${idx + 1}`}
|
||||||
className="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
className="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
||||||
|
onError={(e) => {
|
||||||
|
e.target.src = "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png";
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
{/* Swiper Navigation Buttons */}
|
|
||||||
<button className="swiper-button-prev-custom absolute left-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 text-white p-2 rounded-full hover:bg-black/70 transition-colors">
|
<button className="swiper-button-prev-custom absolute left-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 text-white p-2 rounded-full hover:bg-black/70 transition-colors">
|
||||||
<ChevronLeft className="w-5 h-5" />
|
<ChevronLeft className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
<button className="swiper-button-next-custom absolute right-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 text-white p-2 rounded-full hover:bg-black/70 transition-colors">
|
<button className="swiper-button-next-custom absolute right-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 text-white p-2 rounded-full hover:bg-black/70 transition-colors">
|
||||||
<ChevronRight className="w-5 h-5" />
|
<ChevronRight className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Pagination */}
|
|
||||||
{/* <div className="swiper-pagination-custom absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black/50 text-white px-3 py-1 rounded-full text-sm z-10"></div> */}
|
|
||||||
|
|
||||||
{/* Thumbnail Navigation */}
|
|
||||||
{/* <div className="absolute bottom-0 right-3 flex flex-row gap-2 z-10">
|
|
||||||
{profile.images.slice(0, 4).map((img, idx) => (
|
|
||||||
<div
|
|
||||||
key={idx}
|
|
||||||
className="w-12 h-12 rounded-lg overflow-hidden border-2 border-white cursor-pointer hover:scale-110 transition-transform shadow-lg"
|
|
||||||
onClick={() => mainSwiperRef.current?.slideTo(idx)}
|
|
||||||
>
|
|
||||||
<img src={img} alt="" className="w-full h-full object-cover" />
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -144,7 +143,7 @@ const MatrimonyProfile = () => {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-[#034E08] font-semibold">ID verified</span>
|
<span className="text-[#034E08] font-semibold">{profile.approved ? "ID verified" : "Pending Verification"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<button
|
<button
|
||||||
@ -161,10 +160,16 @@ const MatrimonyProfile = () => {
|
|||||||
</button>
|
</button>
|
||||||
{showMenu && (
|
{showMenu && (
|
||||||
<div className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-xl border z-10">
|
<div className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-xl border z-10">
|
||||||
<button className="w-full px-4 py-3 text-left hover:bg-gray-50 flex items-center gap-3">
|
<button
|
||||||
|
onClick={() => { setShowMenu(false); handleShortlist(); }}
|
||||||
|
className="w-full px-4 py-3 text-left hover:bg-gray-50 flex items-center gap-3"
|
||||||
|
>
|
||||||
<Bookmark className="w-4 h-4" /> Shortlist
|
<Bookmark className="w-4 h-4" /> Shortlist
|
||||||
</button>
|
</button>
|
||||||
<button className="w-full px-4 py-3 text-left hover:bg-gray-50 flex items-center gap-3">
|
<button
|
||||||
|
onClick={() => { setShowMenu(false); navigate("/chat"); }}
|
||||||
|
className="w-full px-4 py-3 text-left hover:bg-gray-50 flex items-center gap-3"
|
||||||
|
>
|
||||||
<MessageCircle className="w-4 h-4" /> Send Message
|
<MessageCircle className="w-4 h-4" /> Send Message
|
||||||
</button>
|
</button>
|
||||||
<button className="w-full px-4 py-3 text-left hover:bg-gray-50 flex items-center gap-3">
|
<button className="w-full px-4 py-3 text-left hover:bg-gray-50 flex items-center gap-3">
|
||||||
@ -182,44 +187,47 @@ const MatrimonyProfile = () => {
|
|||||||
{profile.name}
|
{profile.name}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-gray-500 text-sm mb-4">
|
<p className="text-gray-500 text-sm mb-4">
|
||||||
{profile.id} | {profile.lastSeen}
|
{profile.member_id} | {profile.last_seen_at}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="space-y-2 mb-6 text-gray-700">
|
<div className="space-y-2 mb-6 text-gray-700">
|
||||||
<p className="flex flex-wrap gap-2">
|
<p className="flex flex-wrap gap-2 items-center">
|
||||||
<span className="font-semibold">{profile.maritalStatus}</span>
|
|
||||||
<span>•</span>
|
|
||||||
<span className="text-sm text-gray-500">
|
<span className="text-sm text-gray-500">
|
||||||
{profile.createdBy}
|
Profile created by {personal.profile_for || "N/A"}
|
||||||
</span>
|
</span>
|
||||||
<span>•</span>
|
{(personal.age || profile.age) && (
|
||||||
<span>{profile.age}</span>
|
<>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<span>{profile.height}</span>
|
<span className="text-sm">{personal.age || profile.age} yrs</span>
|
||||||
<span>•</span>
|
</>
|
||||||
<span>{profile.caste}</span>
|
)}
|
||||||
</p>
|
{(profile.religion || profile.caste || profile.sub_caste || profile.college_name) && (
|
||||||
<p>
|
<>
|
||||||
<span className="font-semibold">{profile.education}</span>
|
<span>•</span>
|
||||||
<span> • </span>
|
<span className="text-sm">
|
||||||
<span>{profile.location}</span>
|
{[
|
||||||
|
safeVal(profile.religion, 'religion_name'),
|
||||||
|
safeVal(profile.caste, 'caste_name'),
|
||||||
|
safeVal(profile.sub_caste, 'sub_caste_name'),
|
||||||
|
profile.college_name
|
||||||
|
].filter(v => v !== "N/A" && v !== undefined).join(" / ")}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Action Buttons */}
|
{/* Action Buttons */}
|
||||||
<div className="flex justify-start gap-3">
|
<div className="flex justify-start gap-3">
|
||||||
<button
|
<button
|
||||||
// onClick={()=>{
|
className="w-[fit-content] border-2 border-gray-300 text-gray-700 py-2 px-6 rounded-full hover:bg-gray-50 transition-colors flex items-center justify-center gap-2 text-sm"
|
||||||
// navigate("/chat")
|
>
|
||||||
// }}
|
|
||||||
className="w-[fit-content] border-2 border-gray-300 text-gray-700 py-2 px-6 rounded-full hover:bg-gray-50 transition-colors flex items-center justify-center gap-2 text-sm">
|
|
||||||
<X className="w-5 h-5" /> Don't Show
|
<X className="w-5 h-5" /> Don't Show
|
||||||
{/* Message */}
|
|
||||||
</button>
|
</button>
|
||||||
{/* <button className="w-[fit-content] border-2 border-orange-500 text-[#034E08] py-2 px-6 rounded-full hover:bg-orange-50 transition-colors flex items-center justify-center gap-2 text-sm">
|
<button
|
||||||
<SkipForward className="w-5 h-5" /> Skip
|
onClick={handleSendInterest}
|
||||||
</button> */}
|
className="w-[fit-content] bg-[#034E08] text-white py-2 px-6 rounded-full hover:bg-[#A70710] transition-colors flex items-center justify-center gap-2 font-semibold text-sm"
|
||||||
<button className="w-[fit-content] bg-[#034E08] text-white py-2 px-6 rounded-full hover:bg-[#A70710] transition-colors flex items-center justify-center gap-2 font-semibold text-sm">
|
>
|
||||||
<Heart className="w-5 h-5" /> Send Interest
|
<Heart className="w-5 h-5" /> Send Interest
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -227,7 +235,7 @@ const MatrimonyProfile = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Image Modal with Swiper */}
|
{/* Image Modal */}
|
||||||
{isModalOpen && (
|
{isModalOpen && (
|
||||||
<div
|
<div
|
||||||
style={{ backdropFilter: "blur(5px)" }}
|
style={{ backdropFilter: "blur(5px)" }}
|
||||||
@ -243,7 +251,6 @@ const MatrimonyProfile = () => {
|
|||||||
<div className="max-w-4xl w-full bg-white p-4 rounded-md">
|
<div className="max-w-4xl w-full bg-white p-4 rounded-md">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
{/* Main Modal Swiper */}
|
|
||||||
<div
|
<div
|
||||||
className="relative bg-gray-900 rounded-lg overflow-hidden"
|
className="relative bg-gray-900 rounded-lg overflow-hidden"
|
||||||
style={{ height: "65vh" }}
|
style={{ height: "65vh" }}
|
||||||
@ -271,20 +278,22 @@ const MatrimonyProfile = () => {
|
|||||||
}}
|
}}
|
||||||
className="h-full w-full"
|
className="h-full w-full"
|
||||||
>
|
>
|
||||||
{profile.images.map((img, idx) => (
|
{profileImages.map((img, idx) => (
|
||||||
<SwiperSlide key={idx}>
|
<SwiperSlide key={idx}>
|
||||||
<div className="w-full h-full flex items-center justify-center">
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
<img
|
<img
|
||||||
src={img}
|
src={img}
|
||||||
alt={`${profile.name} ${idx + 1}`}
|
alt={`${profile.name} ${idx + 1}`}
|
||||||
className="max-w-full max-h-full object-contain"
|
className="max-w-full max-h-full object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
e.target.src = "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png";
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
{/* Modal Navigation Buttons */}
|
|
||||||
<button className="modal-swiper-button-prev absolute left-4 top-1/2 -translate-y-1/2 z-10 bg-black/50 text-white p-3 rounded-full hover:bg-black/70 transition-colors">
|
<button className="modal-swiper-button-prev absolute left-4 top-1/2 -translate-y-1/2 z-10 bg-black/50 text-white p-3 rounded-full hover:bg-black/70 transition-colors">
|
||||||
<ChevronLeft className="w-6 h-6" />
|
<ChevronLeft className="w-6 h-6" />
|
||||||
</button>
|
</button>
|
||||||
@ -295,24 +304,13 @@ const MatrimonyProfile = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{/* Top Info Bar */}
|
|
||||||
<div className="bg-white rounded-t-lg p-4 mb-2">
|
<div className="bg-white rounded-t-lg p-4 mb-2">
|
||||||
<div className="flex items-center justify-between">
|
<h3 className="font-bold text-lg">{profile.name}</h3>
|
||||||
<div className="swiper-pagination-modal text-lg font-semibold"></div>
|
<p className="text-sm text-gray-600">
|
||||||
<div className="text-right">
|
{profile.member_id} | Profile created by {personal.profile_for}
|
||||||
<h3 className="font-bold text-lg">{profile.name}</h3>
|
</p>
|
||||||
<p className="text-sm text-gray-600">
|
|
||||||
{profile.id} | {profile.createdBy}
|
|
||||||
</p>
|
|
||||||
<p className="text-sm">
|
|
||||||
{profile.age} • {profile.height} • {profile.caste} • BE
|
|
||||||
• {profile.education} • {profile.location}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Thumbnail Swiper */}
|
|
||||||
<Swiper
|
<Swiper
|
||||||
modules={[Thumbs]}
|
modules={[Thumbs]}
|
||||||
watchSlidesProgress
|
watchSlidesProgress
|
||||||
@ -321,25 +319,28 @@ const MatrimonyProfile = () => {
|
|||||||
slidesPerView={5}
|
slidesPerView={5}
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
>
|
>
|
||||||
{profile.images.map((img, idx) => (
|
{profileImages.map((img, idx) => (
|
||||||
<SwiperSlide key={idx}>
|
<SwiperSlide key={idx}>
|
||||||
<div className="w-full h-16 rounded-lg overflow-hidden border-2 border-white cursor-pointer hover:border-orange-500 transition-colors">
|
<div className="w-full h-16 rounded-lg overflow-hidden border-2 border-white cursor-pointer hover:border-orange-500 transition-colors">
|
||||||
<img
|
<img
|
||||||
src={img}
|
src={img}
|
||||||
alt=""
|
alt=""
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
|
onError={(e) => {
|
||||||
|
e.target.src = "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png";
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
{/* Bottom Action Bar */}
|
|
||||||
<div className="bg-white p-4 rounded-b-lg mt-2 text-center">
|
<div className="bg-white p-4 rounded-b-lg mt-2 text-center">
|
||||||
<p className="text-sm text-gray-600 mb-2">
|
<p className="text-sm text-gray-600 mb-2">Like this member?</p>
|
||||||
Like this member?
|
<button
|
||||||
</p>
|
onClick={handleSendInterest}
|
||||||
<button className="bg-[#034E08] text-white px-8 py-2 rounded-full hover:bg-orange-700 transition-colors font-semibold">
|
className="bg-[#034E08] text-white px-8 py-2 rounded-full hover:bg-orange-700 transition-colors font-semibold"
|
||||||
|
>
|
||||||
Send Interest
|
Send Interest
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -351,19 +352,11 @@ const MatrimonyProfile = () => {
|
|||||||
|
|
||||||
<div className="w-[100%] max-w-[1200px] mx-auto my-10 grid grid-cols-1 gap-4 md:grid-cols-2">
|
<div className="w-[100%] max-w-[1200px] mx-auto my-10 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
{/* Personal Information Section */}
|
{/* Personal Information Section */}
|
||||||
<div className=" border border-gray-200 rounded-lg bg-pink-50/30">
|
<div className="border border-gray-200 rounded-lg bg-pink-50/30">
|
||||||
<div className="flex items-center gap-2 mb-4 p-3 py-3 bg-green-100">
|
<div className="flex items-center gap-2 mb-4 p-3 py-3 bg-green-100">
|
||||||
<div className="bg-pink-100 p-2 rounded-full">
|
<div className="bg-pink-100 p-2 rounded-full">
|
||||||
<svg
|
<svg className="w-5 h-5 text-[#A70710]" fill="currentColor" viewBox="0 0 20 20">
|
||||||
className="w-5 h-5 text-[#A70710]"
|
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-semibold text-lg">Personal Information</h3>
|
<h3 className="font-semibold text-lg">Personal Information</h3>
|
||||||
@ -371,188 +364,103 @@ const MatrimonyProfile = () => {
|
|||||||
|
|
||||||
<div className="p-5 mb-6 space-y-3 text-sm">
|
<div className="p-5 mb-6 space-y-3 text-sm">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Age</span>
|
<span className="text-gray-600 w-40">Name</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">30 Years and 8 months</span>
|
<span className="ml-3 text-gray-900">{profile.name}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Gender</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{personal.gender || profile.type || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Date of Birth</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{personal.dob || profile.dob || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Place of Birth</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.place_of_birth || personal.place_of_birth || profile.place_of_birth || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Time of Birth</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.time_of_birth || personal.time_of_birth || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Height</span>
|
<span className="text-gray-600 w-40">Height</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">5'5"</span>
|
<span className="ml-3 text-gray-900">{profile.height ? `${profile.height} ft` : "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Weight</span>
|
<span className="text-gray-600 w-40">Weight</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">97 Kg</span>
|
<span className="ml-3 text-gray-900">{profile.weight ? `${profile.weight} Kg` : "N/A"}</span>
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Body Type</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Average</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Spoken Languages</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">
|
|
||||||
Tamil (Mother Tongue), English, Hindi
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Profile Created By</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Sibling</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Marital Status</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Never Married</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Lives In</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Chennai, Tamil Nadu</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Eating Habits</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Vegetarian</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Religion</span>
|
<span className="text-gray-600 w-40">Religion</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Hindu</span>
|
<span className="ml-3 text-gray-900">{personal.religion || safeVal(profile.religion, 'religion_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Profile Created By</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{personal.profile_for || safeVal(profile.profile_for, 'profile_for_name')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Caste</span>
|
<span className="text-gray-600 w-40">Caste</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Brahmin - Iyer</span>
|
<span className="ml-3 text-gray-900">{personal.caste || safeVal(profile.caste, 'caste_name')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Subcaste</span>
|
<span className="text-gray-600 w-40">Sub Caste</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Brahacharmam</span>
|
<span className="ml-3 text-gray-900">{personal.sub_caste || safeVal(profile.sub_caste, 'sub_caste_name')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Gothra(m)</span>
|
<span className="text-gray-600 w-40">Gothram</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Kashyapa / Kaashyapa</span>
|
<span className="ml-3 text-gray-900">{personal.gothram || safeVal(profile.gothram, 'gothram_name')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Dosha(m)</span>
|
<span className="text-gray-600 w-40">Rasi</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Don't know</span>
|
<span className="ml-3 text-gray-900">{personal.raasi || safeVal(profile.raasi, 'raasi_name')}</span>
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<span className="text-gray-600 w-40">Date Of Birth</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900"> 23-12-1991</span>
|
|
||||||
{/* <button className="ml-3 text-[#034E08] hover:text-orange-700 flex items-center gap-1 text-xs font-medium">
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Upgrade to view
|
|
||||||
</button> */}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<span className="text-gray-600 w-40">Star</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Piscus</span>
|
|
||||||
{/* <button className="ml-3 text-[#034E08] hover:text-orange-700 flex items-center gap-1 text-xs font-medium">
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Upgrade to view
|
|
||||||
</button> */}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<span className="text-gray-600 w-40">Rassi</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900"> Revathy</span>
|
|
||||||
{/* <button className="ml-3 text-[#034E08] hover:text-orange-700 flex items-center gap-1 text-xs font-medium">
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Upgrade to view
|
|
||||||
</button> */}
|
|
||||||
</div>
|
|
||||||
{/* <div className="flex items-center">
|
|
||||||
<span className="text-gray-600 w-40">Horoscope</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<button className="ml-3 text-[#034E08] hover:text-orange-700 flex items-center gap-1 text-xs font-medium">
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Upgrade to view
|
|
||||||
</button>
|
|
||||||
</div> */}
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Employment</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">Employed in private</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Income</span>
|
<span className="text-gray-600 w-40">Birth Star</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">₹ 4 - 5 Lakhs</span>
|
<span className="ml-3 text-gray-900">{personal.star || safeVal(profile.star, 'star_name')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Education</span>
|
<span className="text-gray-600 w-40">Known Languages</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">BE</span>
|
<span className="ml-3 text-gray-900">{personal.known_languages || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Occupation</span>
|
<span className="text-gray-600 w-40">Speaks Telugu</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Engineer - Non IT</span>
|
<span className="ml-3 text-gray-900">{personal.do_you_speak_telugu === 1 ? "Yes" : personal.do_you_speak_telugu === 0 ? "No" : "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">City</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{personal.district || safeVal(profile.district, 'district_name') || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Pin Code</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{personal.pincode || profile.zip || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Family Information Section */}
|
{/* Family Information Section */}
|
||||||
<div className="border border-gray-200 rounded-lg bg-pink-50/30 ">
|
<div className="border border-gray-200 rounded-lg bg-pink-50/30">
|
||||||
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
||||||
<div className="bg-white p-2 rounded-full">
|
<div className="bg-white p-2 rounded-full">
|
||||||
<svg
|
<svg className="w-5 h-5 text-[#A70710]" fill="currentColor" viewBox="0 0 20 20">
|
||||||
className="w-5 h-5 text-[#A70710]"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z" />
|
<path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@ -561,104 +469,44 @@ const MatrimonyProfile = () => {
|
|||||||
|
|
||||||
<div className="p-5 space-y-3 text-sm">
|
<div className="p-5 space-y-3 text-sm">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Parents</span>
|
<span className="text-gray-600 w-40">Father Name</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">
|
<span className="ml-3 text-gray-900">{family.father_name || profile.father_name || "N/A"}</span>
|
||||||
Father Passed Away, Mother is a Home Maker
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Ancestral Origin</span>
|
<span className="text-gray-600 w-40">Father Occupation</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Rameshwaram</span>
|
<span className="ml-3 text-gray-900">{family.father_occupation || profile.father_occupation || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex">
|
||||||
{/* Contact Information Section */}
|
<span className="text-gray-600 w-40">Mother Name</span>
|
||||||
<div className="my-8">
|
<span className="text-gray-400">:</span>
|
||||||
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
<span className="ml-3 text-gray-900">{family.mother_name || profile.mother_name || "N/A"}</span>
|
||||||
<div className="bg-white p-2 rounded-full">
|
|
||||||
<svg
|
|
||||||
className="w-5 h-5 text-[#A70710]"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 className="font-semibold text-lg">Contact Information</h3>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex">
|
||||||
<div className="p-5 space-y-3 text-sm">
|
<span className="text-gray-600 w-40">Mother Occupation</span>
|
||||||
<div className="flex items-center">
|
<span className="text-gray-400">:</span>
|
||||||
<span className="text-gray-600 w-40">Mobile Number</span>
|
<span className="ml-3 text-gray-900">{family.mother_occupation || profile.mother_occupation || "N/A"}</span>
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<div className="ml-3 flex items-center gap-2">
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3 text-green-600"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3 text-red-600"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span className="text-gray-900">+91 99••••••••</span>
|
|
||||||
<button className="text-[#034E08] hover:text-orange-700 text-xs font-medium">
|
|
||||||
Upgrade to view
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Siblings</span>
|
||||||
{/* About Myself Section */}
|
<span className="text-gray-400">:</span>
|
||||||
<div className="my-8">
|
<span className="ml-3 text-gray-900">{family.brother_count || profile.brother_count} Brothers, {family.sister_count || profile.sister_count} Sisters</span>
|
||||||
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
|
||||||
<div className="bg-white p-2 rounded-full">
|
|
||||||
<svg
|
|
||||||
className="w-5 h-5 text-[#A70710]"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-6-3a2 2 0 11-4 0 2 2 0 014 0zm-2 4a5 5 0 00-4.546 2.916A5.986 5.986 0 0010 16a5.986 5.986 0 004.546-2.084A5 5 0 0010 11z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 className="font-semibold text-lg">About Myself</h3>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex">
|
||||||
<div className="p-5 space-y-4 text-sm">
|
<span className="text-gray-600 w-40">Family Type</span>
|
||||||
<div>
|
<span className="text-gray-400">:</span>
|
||||||
<h4 className="font-semibold text-gray-900 mb-2">
|
<span className="ml-3 text-gray-900">{family.family_status || safeVal(profile.family_type, 'family_type_name') || "N/A"}</span>
|
||||||
About Sudharshan M
|
</div>
|
||||||
</h4>
|
<div className="flex">
|
||||||
<p className="text-gray-700 leading-relaxed">
|
<span className="text-gray-600 w-40">Settled</span>
|
||||||
I am making this profile for my brother. He completed his
|
<span className="text-gray-400">:</span>
|
||||||
bachelor's degree and is now working as a project engineer -
|
<span className="ml-3 text-gray-900">{family.settled || "N/A"}</span>
|
||||||
non IT. We belong to a middle class, nuclear family with
|
</div>
|
||||||
traditional values, currently settled in Chennai.
|
<div className="flex">
|
||||||
</p>
|
<span className="text-gray-600 w-40">Native Place</span>
|
||||||
</div>
|
<span className="text-gray-400">:</span>
|
||||||
<div>
|
<span className="ml-3 text-gray-900">{family.native_place || profile.native_place || "N/A"}</span>
|
||||||
<h4 className="font-semibold text-gray-900 mb-2">
|
|
||||||
What we are looking for
|
|
||||||
</h4>
|
|
||||||
<p className="text-gray-700">
|
|
||||||
Traditional, homely girl with moderate values
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -666,11 +514,7 @@ const MatrimonyProfile = () => {
|
|||||||
<div className="my-8">
|
<div className="my-8">
|
||||||
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
||||||
<div className="bg-white p-2 rounded-full">
|
<div className="bg-white p-2 rounded-full">
|
||||||
<svg
|
<svg className="w-5 h-5 text-[#A70710]" fill="currentColor" viewBox="0 0 20 20">
|
||||||
className="w-5 h-5 text-[#A70710]"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M10.394 2.08a1 1 0 00-.788 0l-7 3a1 1 0 000 1.84L5.25 8.051a.999.999 0 01.356-.257l4-1.714a1 1 0 11.788 1.838L7.667 9.088l1.94.831a1 1 0 00.787 0l7-3a1 1 0 000-1.838l-7-3zM3.31 9.397L5 10.12v4.102a8.969 8.969 0 00-1.05-.174 1 1 0 01-.89-.89 11.115 11.115 0 01.25-3.762zM9.3 16.573A9.026 9.026 0 007 14.935v-3.957l1.818.78a3 3 0 002.364 0l5.508-2.361a11.026 11.026 0 01.25 3.762 1 1 0 01-.89.89 8.968 8.968 0 00-5.35 2.524 1 1 0 01-1.4 0zM6 18a1 1 0 001-1v-2.065a8.935 8.935 0 00-2-.712V17a1 1 0 001 1z" />
|
<path d="M10.394 2.08a1 1 0 00-.788 0l-7 3a1 1 0 000 1.84L5.25 8.051a.999.999 0 01.356-.257l4-1.714a1 1 0 11.788 1.838L7.667 9.088l1.94.831a1 1 0 00.787 0l7-3a1 1 0 000-1.838l-7-3zM3.31 9.397L5 10.12v4.102a8.969 8.969 0 00-1.05-.174 1 1 0 01-.89-.89 11.115 11.115 0 01.25-3.762zM9.3 16.573A9.026 9.026 0 007 14.935v-3.957l1.818.78a3 3 0 002.364 0l5.508-2.361a11.026 11.026 0 01.25 3.762 1 1 0 01-.89.89 8.968 8.968 0 00-5.35 2.524 1 1 0 01-1.4 0zM6 18a1 1 0 001-1v-2.065a8.935 8.935 0 00-2-.712V17a1 1 0 001 1z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@ -679,55 +523,108 @@ const MatrimonyProfile = () => {
|
|||||||
|
|
||||||
<div className="p-5 space-y-3 text-sm">
|
<div className="p-5 space-y-3 text-sm">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Cuisine</span>
|
<span className="text-gray-600 w-40">Diet</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.diet || safeVal(profile.diet, 'diet_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Place of Birth</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.place_of_birth || personal.place_of_birth || profile.place_of_birth || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Time of Birth</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.time_of_birth || personal.time_of_birth || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Panjangam Type</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.panjangam_type || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Dasa Balance</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{lifestyle.dasa_balance || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Dasa Period</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">
|
<span className="ml-3 text-gray-900">
|
||||||
Chinese, North Indian, South Indian
|
{lifestyle.dasa_years || "0"} Years, {lifestyle.dasa_months || "0"} Months, {lifestyle.dasa_days || "0"} Days
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Books</span>
|
<span className="text-gray-600 w-40">Age</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">
|
<span className="ml-3 text-gray-900">{(personal.age || profile.age || lifestyle.age) ? `${personal.age || profile.age || lifestyle.age} Years` : "N/A"}</span>
|
||||||
History, Philosophy / Spiritual
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-gray-600 w-40">Hobbies</span>
|
<span className="text-gray-600 w-40">Hobbies</span>
|
||||||
<span className="text-gray-400">:</span>
|
<span className="text-gray-400">:</span>
|
||||||
<span className="ml-3 text-gray-900">Cooking</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<span className="text-gray-600 w-40">Movies</span>
|
|
||||||
<span className="text-gray-400">:</span>
|
|
||||||
<span className="ml-3 text-gray-900">
|
<span className="ml-3 text-gray-900">
|
||||||
Anime, Comedy, Sci-Fi
|
{lifestyle.hobbies && lifestyle.hobbies.length > 0 ? lifestyle.hobbies.join(", ") : "N/A"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
</div>
|
||||||
<span className="text-gray-600 w-40">Sports</span>
|
</div>
|
||||||
<span className="text-gray-400">:</span>
|
</div>
|
||||||
<span className="ml-3 text-gray-900">Yoga / Meditation</span>
|
|
||||||
</div>
|
{/* Educational Details Section */}
|
||||||
<div className="flex">
|
<div className="border border-gray-200 rounded-lg bg-pink-50/30">
|
||||||
<span className="text-gray-600 w-40">Smoking Habits</span>
|
<div className="flex items-center gap-2 p-3 bg-pink-100">
|
||||||
<span className="text-gray-400">:</span>
|
<div className="bg-white p-2 rounded-full">
|
||||||
<span className="ml-3 text-gray-900">Doesn't Smoke</span>
|
<svg className="w-5 h-5 text-[#A70710]" fill="currentColor" viewBox="0 0 20 20">
|
||||||
</div>
|
<path d="M10.394 2.08a1 1 0 00-.788 0l-7 3a1 1 0 000 1.84L5.25 8.051a.999.999 0 01.356-.257l4-1.714a1 1 0 11.788 1.838L7.667 9.088l1.94.831a1 1 0 00.787 0l7-3a1 1 0 000-1.838l-7-3zM3.31 9.397L5 10.12v4.102a8.969 8.969 0 00-1.05-.174 1 1 0 01-.89-.89 11.115 11.115 0 01.25-3.762zM9.3 16.573A9.026 9.026 0 007 14.935v-3.957l1.818.78a3 3 0 002.364 0l5.508-2.361a11.026 11.026 0 01.25 3.762 1 1 0 01-.89.89 8.968 8.968 0 00-5.35 2.524 1 1 0 01-1.4 0zM6 18a1 1 0 001-1v-2.065a8.935 8.935 0 00-2-.712V17a1 1 0 001 1z" />
|
||||||
<div className="flex">
|
</svg>
|
||||||
<span className="text-gray-600 w-40">Drinking Habits</span>
|
</div>
|
||||||
<span className="text-gray-400">:</span>
|
<h3 className="font-semibold text-lg">Educational Details</h3>
|
||||||
<span className="ml-3 text-gray-900">Doesn't Drink</span>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div className="p-5 space-y-3 text-sm">
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Highest Qualification</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{education.education || safeVal(profile.education, 'education_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Field of Study</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{education.study_field || safeVal(profile.study_field, 'study_field_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">College Name</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{profile.college_name || education.college_name || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Occupation</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{education.occupation || safeVal(profile.occupation, 'occupation_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Organization Name</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{education.company_name || profile.company_name || "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Employee Type</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{education.employee_type || safeVal(profile.employee_type, 'employee_type_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Annual Income</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{education.annual_income || safeVal(profile.annual_income, 'annual_income_name')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-gray-600 w-40">Work Location</span>
|
||||||
|
<span className="text-gray-400">:</span>
|
||||||
|
<span className="ml-3 text-gray-900">{profile.work_location || education.work_location || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,24 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Check, X } from 'lucide-react';
|
import { Check, X } from 'lucide-react';
|
||||||
|
|
||||||
const PartnerPreferences = () => {
|
const PartnerPreferences = ({ data }) => {
|
||||||
|
if (!data) return null;
|
||||||
|
|
||||||
|
const pref = data.preferedDetails;
|
||||||
|
const matchDetails = data.mutual_match.my_preferences_match;
|
||||||
|
const overallMatch = data.mutual_match.overall_match_percentage;
|
||||||
|
|
||||||
const basicPreferences = [
|
const basicPreferences = [
|
||||||
{ label: "Preferred Bride's Age", value: "22-29 yrs", match: true },
|
{ label: "Preferred Groom's Age", value: pref.preferred_age_range || "Any", match: matchDetails.age },
|
||||||
{ label: "Preferred Height", value: "5'0\" - 5'5\"", match: false },
|
{ label: "Preferred Height", value: (pref.preferred_height_from && pref.preferred_height_to) ? `${pref.preferred_height_from} - ${pref.preferred_height_to} ft` : "Any", match: matchDetails.height },
|
||||||
{ label: "Preferred Marital Status", value: "Never Married", match: true },
|
{ label: "Preferred Marital Status", value: pref.preferred_marital_statuses?.join(", ") || "Any", match: matchDetails.marital_status },
|
||||||
{ label: "Preferred Mother Tongue", value: "Tamil", match: true },
|
{ label: "Preferred Mother Tongue", value: pref.preferred_mother_tongues?.join(", ") || "Any", match: matchDetails.mother_tongue },
|
||||||
{ label: "Preferred Physical Status", value: "Normal", match: true },
|
{ label: "Preferred Education", value: pref.preferred_educations?.join(", ") || "Any", match: matchDetails.education },
|
||||||
{ label: "Preferred Eating Habits", value: "Vegetarian", match: false },
|
{ label: "Preferred Employee Type", value: pref.preferred_employee_types?.join(", ") || "Any", match: true }, // Not in matchDetails?
|
||||||
{ label: "Preferred Smoking Habits", value: "Doesn't Matter", match: true },
|
|
||||||
{ label: "Preferred Drinking Habits", value: "Doesn't Matter", match: true },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const religiousPreferences = [
|
const religiousPreferences = [
|
||||||
{ label: "Preferred Religion", value: "Hindu", match: true },
|
{ label: "Preferred Caste", value: pref.preferred_castes?.join(", ") || "Any", match: matchDetails.caste },
|
||||||
{ label: "Preferred Caste", value: "Brahmin - Iyer", match: false },
|
{ label: "Preferred Sub-caste", value: pref.preferred_sub_castes?.join(", ") || "Any", match: matchDetails.sub_caste },
|
||||||
{ label: "Preferred Subcaste", value: "Any", match: false },
|
{ label: "Preferred State", value: pref.preferred_states?.join(", ") || "Any", match: true },
|
||||||
{ label: "Preferred Star", value: "Any", match: true },
|
{ label: "Preferred City", value: pref.preferred_districts?.join(", ") || "Any", match: true },
|
||||||
{ label: "Preferred Dosham", value: "No Dosham", match: true },
|
{ label: "Preferred Occupation", value: pref.preferred_occupations?.join(", ") || "Any", match: matchDetails.occupation },
|
||||||
|
{ label: "Preferred Annual Income", value: pref.preferred_annual_income || "Any", match: matchDetails.annual_income },
|
||||||
];
|
];
|
||||||
|
|
||||||
const PreferenceItem = ({ label, value, match }) => (
|
const PreferenceItem = ({ label, value, match }) => (
|
||||||
@ -46,7 +51,7 @@ const PartnerPreferences = () => {
|
|||||||
<div className="text-center mb-6 ">
|
<div className="text-center mb-6 ">
|
||||||
<h1 className="text-2xl sm:text-3xl font-bold text-gray-800 mb-2 flex items-center justify-center gap-2">
|
<h1 className="text-2xl sm:text-3xl font-bold text-gray-800 mb-2 flex items-center justify-center gap-2">
|
||||||
<span className="text-pink-400">✨</span>
|
<span className="text-pink-400">✨</span>
|
||||||
His Partner Preferences
|
Partner Preferences
|
||||||
<span className="text-pink-400">✨</span>
|
<span className="text-pink-400">✨</span>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
@ -56,65 +61,52 @@ const PartnerPreferences = () => {
|
|||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<img
|
<img
|
||||||
src="https://api.dicebear.com/7.x/avataaars/svg?seed=male1"
|
src={data.my_profile || "https://api.dicebear.com/7.x/avataaars/svg?seed=male1"}
|
||||||
alt="Profile"
|
alt="Your Profile"
|
||||||
className="w-16 h-16 sm:w-20 sm:h-20 rounded-xl border-4 border-pink-100"
|
className="w-16 h-16 sm:w-20 sm:h-20 rounded-xl border-4 border-pink-100 object-cover"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-gray-600 text-sm mb-1">You match</p>
|
<p className="text-gray-600 text-sm mb-1">Overall Match Score</p>
|
||||||
<p className="text-2xl sm:text-3xl font-bold text-red-600">
|
<p className="text-2xl sm:text-3xl font-bold text-red-600">
|
||||||
14<span className="text-[#034E08]">/20</span>
|
{overallMatch}<span className="text-[#034E08]">%</span>
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-500">of his preferences</p>
|
<p className="text-xs text-gray-500">of preferences match</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
src="https://api.dicebear.com/7.x/avataaars/svg?seed=female1"
|
src={data.profile.profile_picture || "https://api.dicebear.com/7.x/avataaars/svg?seed=female1"}
|
||||||
alt="Your Profile"
|
alt="Partner Profile"
|
||||||
className="w-16 h-16 sm:w-20 sm:h-20 rounded-xl border-4 border-purple-100"
|
className="w-16 h-16 sm:w-20 sm:h-20 rounded-xl border-4 border-purple-100 object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid grid-cols-1 gap-2 md:grid-cols-2 mb-8 pt-4'>
|
<div className='grid grid-cols-1 gap-2 md:grid-cols-2 mb-8 pt-4'>
|
||||||
|
{/* Basic Preferences Section */}
|
||||||
{/* Basic Preferences Section */}
|
<div className="bg-white rounded-2xl shadow-lg overflow-hidden">
|
||||||
<div className="bg-white rounded-2xl shadow-lg overflow-hidden">
|
<div className="flex items-center justify-between mb-4 bg-[#f5fbff] pt-4 pb-4 px-6">
|
||||||
<div className="flex items-center justify-between mb-4 bg-[#f5fbff] pt-4 pb-4 px-6">
|
<h2 className="text-lg font-bold text-gray-800">Basic Preferences</h2>
|
||||||
<h2 className="text-lg font-bold text-gray-800">Basic Preferences</h2>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="space-y-1 p-6">
|
||||||
<span className="text-sm text-gray-600">You match</span>
|
{basicPreferences.map((pref, index) => (
|
||||||
<div className="w-6 h-6 rounded-full bg-green-100 flex items-center justify-center">
|
<PreferenceItem key={index} {...pref} />
|
||||||
<Check className="w-4 h-4 text-green-600" />
|
))}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 p-6">
|
|
||||||
{basicPreferences.map((pref, index) => (
|
{/* Other Preferences Section */}
|
||||||
<PreferenceItem key={index} {...pref} />
|
<div className="bg-white rounded-2xl shadow-lg overflow-hidden">
|
||||||
))}
|
<div className="flex items-center justify-between mb-4 bg-[#f5fbff] pt-4 pb-4 px-6">
|
||||||
|
<h2 className="text-lg font-bold text-gray-800">Professional & Location</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1 p-6">
|
||||||
|
{religiousPreferences.map((pref, index) => (
|
||||||
|
<PreferenceItem key={index} {...pref} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Religious Preferences Section */}
|
|
||||||
<div className="bg-white rounded-2xl shadow-lg overflow-hidden">
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between mb-4 bg-[#f5fbff] pt-4 pb-4 px-6">
|
|
||||||
<h2 className="text-lg font-bold text-gray-800">Religious Preferences</h2>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="text-sm text-gray-600">You match</span>
|
|
||||||
<div className="w-6 h-6 rounded-full bg-green-100 flex items-center justify-center">
|
|
||||||
<Check className="w-4 h-4 text-green-600" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-1 p-6">
|
|
||||||
{religiousPreferences.map((pref, index) => (
|
|
||||||
<PreferenceItem key={index} {...pref} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Footer Note */}
|
{/* Footer Note */}
|
||||||
<div className="text-center mt-6 text-sm text-gray-500">
|
<div className="text-center mt-6 text-sm text-gray-500">
|
||||||
<p>Preferences are used to find compatible matches</p>
|
<p>Preferences are used to find compatible matches</p>
|
||||||
|
|||||||
@ -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 { useDispatch, useSelector } from "react-redux";
|
||||||
import { updateEducationalDetails } from "../redux/registrationFormSlice";
|
import { updateEducationalDetails, clearAllStepsFrom } from "../redux/registrationFormSlice";
|
||||||
import {
|
import {
|
||||||
TextField,
|
TextField,
|
||||||
Button,
|
Button,
|
||||||
@ -9,456 +9,412 @@ import {
|
|||||||
InputLabel,
|
InputLabel,
|
||||||
Select,
|
Select,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
|
FormHelperText,
|
||||||
|
InputAdornment,
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useEducationMasters, useEducationList } from "../hooks/useMasters";
|
import { useEducationMasters, useEducationList } from "../hooks/useMasters";
|
||||||
|
import { useCityMasters } from "../hooks/useDependentMasters";
|
||||||
|
import { toast } from "react-hot-toast";
|
||||||
|
|
||||||
const EducationalDetailsForm = ({
|
const EducationalDetailsForm = ({
|
||||||
onSubmitStep,
|
onSubmitStep,
|
||||||
onSkipStep,
|
onSkipStep,
|
||||||
errors,
|
errors: externalErrors,
|
||||||
onFieldChange,
|
isEditMode,
|
||||||
}) => {
|
}) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const data = useSelector((state) => state.registerform.educationalDetails);
|
const data = useSelector((state) => state.registerform.educationalDetails);
|
||||||
const inputRef = useRef(null);
|
const [localErrors, setLocalErrors] = useState({});
|
||||||
const requiredMark = <span style={{ color: "#d32f2f" }}> *</span>;
|
const requiredMark = <span style={{ color: "#d32f2f" }}> *</span>;
|
||||||
|
|
||||||
const { data: educationMasters, isLoading: isEducationMastersLoading } =
|
const { data: educationMasters, isLoading: isEducationMastersLoading } =
|
||||||
useEducationMasters();
|
useEducationMasters();
|
||||||
const educationListQuery = useEducationList(data.fieldOfStudy);
|
const educationListQuery = useEducationList(data.study_field);
|
||||||
|
const districtQuery = useCityMasters(data.work_state);
|
||||||
|
|
||||||
const studyFieldOptions = useMemo(() => {
|
const studyFieldOptions = educationMasters?.studyFields || [];
|
||||||
const raw = educationMasters;
|
const qualificationOptions = educationListQuery.data?.education || educationListQuery.data?.data || [];
|
||||||
if (!raw) return [];
|
const occupationOptions = educationMasters?.occupation || [];
|
||||||
if (Array.isArray(raw)) return raw;
|
const employeeTypeOptions = educationMasters?.employeeType || [];
|
||||||
return raw.studyFields || raw.study_fields || raw.fieldOfStudy || [];
|
const countryOptions = educationMasters?.country || [];
|
||||||
}, [educationMasters]);
|
const stateOptions = educationMasters?.state || [];
|
||||||
|
const districtOptions = districtQuery.data?.districts || districtQuery.data || [];
|
||||||
|
|
||||||
const qualificationOptions = useMemo(() => {
|
const isUnemployed = data.employee_type === 11;
|
||||||
const raw = educationListQuery.data;
|
const isIndia = Number(data.work_country) === 1;
|
||||||
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 handleChange = (field, value) => {
|
const handleChange = (field, value) => {
|
||||||
const updates = { [field]: value };
|
const updates = { [field]: value };
|
||||||
const fieldsToClear = [field];
|
|
||||||
if (field === "fieldOfStudy") {
|
if (field === "study_field") {
|
||||||
updates.qualification = "";
|
updates.education = "";
|
||||||
fieldsToClear.push("qualification");
|
|
||||||
}
|
}
|
||||||
|
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));
|
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 = () => {
|
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();
|
onSubmitStep();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
||||||
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
<form noValidate autoComplete="off" style={{ padding: 16 }}>
|
||||||
<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="grid grid-cols-1 md:grid-cols-2 gap-x-20 gap-y-10 mb-6">
|
{/* 1. Field of Study */}
|
||||||
{/* Field of Study */}
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex flex-col gap-4">
|
<label className="text-gray-900 text-[15px]">Field of Study{requiredMark}</label>
|
||||||
<label className="text-gray-900 text-[15px]">
|
<FormControl fullWidth error={Boolean(localErrors.study_field)} id="study_field">
|
||||||
Field of Study{requiredMark}
|
<InputLabel>Select Field of Study</InputLabel>
|
||||||
</label>
|
<Select
|
||||||
<FormControl
|
value={data.study_field}
|
||||||
fullWidth
|
label="Select Field of Study"
|
||||||
variant="outlined"
|
onChange={(e) => handleChange("study_field", e.target.value)}
|
||||||
error={Boolean(errors.fieldOfStudy)}
|
|
||||||
>
|
>
|
||||||
<InputLabel id="fieldOfStudy-label">
|
{studyFieldOptions.map((opt) => (
|
||||||
Select Field of Study
|
<MenuItem key={opt.id} value={opt.id}>{opt.study_field_name}</MenuItem>
|
||||||
</InputLabel>
|
))}
|
||||||
<Select
|
</Select>
|
||||||
labelId="fieldOfStudy-label"
|
{localErrors.study_field && <FormHelperText>{localErrors.study_field}</FormHelperText>}
|
||||||
label="Select Field of Study"
|
</FormControl>
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Grid
|
{/* 2. Highest Qualification */}
|
||||||
item
|
<div className="flex flex-col gap-2">
|
||||||
xs={12}
|
<label className="text-gray-900 text-[15px]">Highest Qualification{requiredMark}</label>
|
||||||
style={{
|
<FormControl fullWidth error={Boolean(localErrors.education)} id="education" disabled={!data.study_field || educationListQuery.isLoading}>
|
||||||
marginTop: "40px",
|
<InputLabel>Select Qualification</InputLabel>
|
||||||
display: "flex",
|
<Select
|
||||||
gap: 16,
|
value={data.education}
|
||||||
justifyContent: "center",
|
label="Select Qualification"
|
||||||
}}
|
onChange={(e) => handleChange("education", e.target.value)}
|
||||||
>
|
>
|
||||||
{onSkipStep && (
|
{qualificationOptions.map((opt) => (
|
||||||
<Button variant="outlined" onClick={onSkipStep}>
|
<MenuItem key={opt.id} value={opt.id}>{opt.education_name || opt.name}</MenuItem>
|
||||||
Skip
|
))}
|
||||||
</Button>
|
</Select>
|
||||||
)}
|
{localErrors.education && <FormHelperText>{localErrors.education}</FormHelperText>}
|
||||||
<Button variant="contained" color="primary" onClick={handleSubmit}>
|
</FormControl>
|
||||||
{onSkipStep ? "Next" : "Update"}
|
</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>
|
</Button>
|
||||||
</Grid>
|
)}
|
||||||
</form>
|
<Button variant="contained" size="large" onClick={handleSubmit} sx={{ minWidth: 120 }}>
|
||||||
</div>
|
{onSkipStep ? "Next" : "Update"}
|
||||||
</>
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useMemo, useRef } from "react";
|
import React, { useEffect, useMemo, useRef } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { updateFamilyDetails } from "../redux/registrationFormSlice";
|
import { updateFamilyDetails, clearAllStepsFrom } from "../redux/registrationFormSlice";
|
||||||
import {
|
import {
|
||||||
Grid,
|
Grid,
|
||||||
TextField,
|
TextField,
|
||||||
@ -12,46 +12,55 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useFamilyMasters } from "../hooks/useMasters";
|
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 dispatch = useDispatch();
|
||||||
const data = useSelector((state) => state.registerform.familyDetails);
|
const data = useSelector((state) => state.registerform.familyDetails);
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
|
const brotherSectionRef = useRef(null);
|
||||||
|
const sisterSectionRef = useRef(null);
|
||||||
const requiredMark = <span style={{ color: "#d32f2f" }}> *</span>;
|
const requiredMark = <span style={{ color: "#d32f2f" }}> *</span>;
|
||||||
|
|
||||||
const { data: familyMasters, isLoading: isFamilyMastersLoading } =
|
const { data: familyMasters, isLoading: isFamilyMastersLoading } = useFamilyMasters();
|
||||||
useFamilyMasters();
|
|
||||||
|
// District query for India
|
||||||
|
const districtQuery = useCityMasters(data.familyState);
|
||||||
|
|
||||||
const occupationOptions = useMemo(() => {
|
const occupationOptions = useMemo(() => {
|
||||||
const raw = familyMasters;
|
const raw = familyMasters;
|
||||||
if (!raw) return [];
|
if (!raw) return [];
|
||||||
if (Array.isArray(raw)) return raw;
|
return raw.occupation || [];
|
||||||
return raw.occupation || raw.occupations || [];
|
|
||||||
}, [familyMasters]);
|
}, [familyMasters]);
|
||||||
|
|
||||||
const maritalStatusOptions = useMemo(() => {
|
const maritalStatusOptions = useMemo(() => {
|
||||||
const raw = familyMasters;
|
const raw = familyMasters;
|
||||||
if (!raw) return [];
|
if (!raw) return [];
|
||||||
if (Array.isArray(raw)) return raw;
|
return raw.maritalStatus || [];
|
||||||
return raw.maritalStatus || raw.marital_status || [];
|
|
||||||
}, [familyMasters]);
|
}, [familyMasters]);
|
||||||
|
|
||||||
const familyStatusOptions = useMemo(() => {
|
const familyStatusOptions = useMemo(() => {
|
||||||
const raw = familyMasters;
|
const raw = familyMasters;
|
||||||
if (!raw) return [];
|
if (!raw) return [];
|
||||||
if (Array.isArray(raw)) return [];
|
return raw.familyStatus || [];
|
||||||
return raw.familyStatus || raw.family_status || [];
|
|
||||||
}, [familyMasters]);
|
}, [familyMasters]);
|
||||||
|
|
||||||
|
const countryOptions = useMemo(() => familyMasters?.country || [], [familyMasters]);
|
||||||
|
const stateOptions = useMemo(() => familyMasters?.state || [], [familyMasters]);
|
||||||
|
const districtOptions = useMemo(() => districtQuery.data?.districts || districtQuery.data || [], [districtQuery.data]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const createSibling = () => ({
|
const createSibling = () => ({
|
||||||
|
type: "",
|
||||||
name: "",
|
name: "",
|
||||||
occupation: "",
|
occupation: "",
|
||||||
maritalStatus: "",
|
maritalStatus: "",
|
||||||
haveChildrens: "",
|
hasChildren: "",
|
||||||
|
details: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const syncSiblingArray = (arr, count) => {
|
const syncSiblingArray = (arr, count) => {
|
||||||
@ -72,20 +81,48 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
|
|
||||||
if (field === "brotherCount") {
|
if (field === "brotherCount") {
|
||||||
const count = Number(value) || 0;
|
const count = Number(value) || 0;
|
||||||
updates.brotherCount = count;
|
updates.brotherCount = value;
|
||||||
updates.brothers = syncSiblingArray(data.brothers, count);
|
updates.brothers = syncSiblingArray(data.brothers, count);
|
||||||
fieldsToClear.push("brothers");
|
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") {
|
if (field === "sisterCount") {
|
||||||
const count = Number(value) || 0;
|
const count = Number(value) || 0;
|
||||||
updates.sisterCount = count;
|
updates.sisterCount = value;
|
||||||
updates.sisters = syncSiblingArray(data.sisters, count);
|
updates.sisters = syncSiblingArray(data.sisters, count);
|
||||||
fieldsToClear.push("sisters");
|
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));
|
dispatch(updateFamilyDetails(updates));
|
||||||
if (onFieldChange) onFieldChange(fieldsToClear);
|
if (onFieldChange) onFieldChange(fieldsToClear);
|
||||||
|
|
||||||
|
if (!isEditMode) {
|
||||||
|
dispatch(clearAllStepsFrom(4));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSiblingChange = (type, index, field, value) => {
|
const handleSiblingChange = (type, index, field, value) => {
|
||||||
@ -94,14 +131,40 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
list[index] = { ...list[index], [field]: value };
|
list[index] = { ...list[index], [field]: value };
|
||||||
dispatch(updateFamilyDetails({ [type]: list }));
|
dispatch(updateFamilyDetails({ [type]: list }));
|
||||||
if (onFieldChange) onFieldChange(type);
|
if (onFieldChange) onFieldChange(type);
|
||||||
|
|
||||||
|
if (!isEditMode) {
|
||||||
|
dispatch(clearAllStepsFrom(4));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const scrollToError = (errorMap) => {
|
||||||
console.log("Submitting family details:", data);
|
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();
|
onSubmitStep();
|
||||||
};
|
};
|
||||||
|
|
||||||
const countOptions = Array.from({ length: 11 }, (_, i) => i);
|
const countOptions = Array.from({ length: 11 }, (_, i) => i);
|
||||||
|
const isIndia = Number(data.familyCountry) === 1;
|
||||||
|
|
||||||
const renderSiblingCard = (type, index) => {
|
const renderSiblingCard = (type, index) => {
|
||||||
const sibling = (data[type] || [])[index] || createSibling();
|
const sibling = (data[type] || [])[index] || createSibling();
|
||||||
@ -114,95 +177,88 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
padding: 2,
|
padding: 2,
|
||||||
backgroundColor: "#fff",
|
backgroundColor: "#fff",
|
||||||
|
mb: 4
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="text-gray-900 text-[14px] font-semibold mb-3">
|
<div className="text-gray-900 text-[14px] font-semibold mb-3">
|
||||||
{labelPrefix} {index + 1}
|
{labelPrefix} {index + 1}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-4">
|
<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
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label="Name"
|
label="Name"
|
||||||
|
placeholder="Enter Name"
|
||||||
value={sibling.name}
|
value={sibling.name}
|
||||||
onChange={(e) =>
|
onChange={(e) => handleSiblingChange(type, index, "name", e.target.value)}
|
||||||
handleSiblingChange(type, index, "name", e.target.value)
|
|
||||||
}
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
inputProps={{ className: index === 0 ? "first-sibling-name" : "" }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormControl fullWidth variant="outlined">
|
<FormControl fullWidth variant="outlined">
|
||||||
<InputLabel id={`${type}-${index}-occupation-label`}>
|
<InputLabel>Occupation</InputLabel>
|
||||||
Occupation
|
|
||||||
</InputLabel>
|
|
||||||
<Select
|
<Select
|
||||||
labelId={`${type}-${index}-occupation-label`}
|
|
||||||
label="Occupation"
|
label="Occupation"
|
||||||
value={sibling.occupation}
|
value={sibling.occupation}
|
||||||
onChange={(e) =>
|
onChange={(e) => handleSiblingChange(type, index, "occupation", e.target.value)}
|
||||||
handleSiblingChange(type, index, "occupation", e.target.value)
|
|
||||||
}
|
|
||||||
disabled={isFamilyMastersLoading}
|
|
||||||
sx={{
|
|
||||||
"& .MuiSelect-select.Mui-disabled": {
|
|
||||||
cursor: "not-allowed",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
|
<MenuItem value=""><em>Select</em></MenuItem>
|
||||||
{occupationOptions.map((opt) => (
|
{occupationOptions.map((opt) => (
|
||||||
<MenuItem key={opt} value={opt}>
|
<MenuItem key={opt} value={opt}>{opt}</MenuItem>
|
||||||
{opt}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl fullWidth variant="outlined">
|
<FormControl fullWidth variant="outlined">
|
||||||
<InputLabel id={`${type}-${index}-marital-label`}>
|
<InputLabel>Marital Status</InputLabel>
|
||||||
Marital Status
|
|
||||||
</InputLabel>
|
|
||||||
<Select
|
<Select
|
||||||
labelId={`${type}-${index}-marital-label`}
|
|
||||||
label="Marital Status"
|
label="Marital Status"
|
||||||
value={sibling.maritalStatus}
|
value={sibling.maritalStatus}
|
||||||
onChange={(e) =>
|
onChange={(e) => handleSiblingChange(type, index, "maritalStatus", e.target.value)}
|
||||||
handleSiblingChange(type, index, "maritalStatus", e.target.value)
|
|
||||||
}
|
|
||||||
disabled={isFamilyMastersLoading}
|
|
||||||
sx={{
|
|
||||||
"& .MuiSelect-select.Mui-disabled": {
|
|
||||||
cursor: "not-allowed",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
|
<MenuItem value=""><em>Select</em></MenuItem>
|
||||||
{maritalStatusOptions.map((opt) => (
|
{maritalStatusOptions.map((opt) => (
|
||||||
<MenuItem key={opt} value={opt}>
|
<MenuItem key={opt} value={opt}>{opt}</MenuItem>
|
||||||
{opt}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl fullWidth variant="outlined">
|
<FormControl fullWidth variant="outlined">
|
||||||
<InputLabel id={`${type}-${index}-children-label`}>
|
<InputLabel>Have Children</InputLabel>
|
||||||
Have Children
|
|
||||||
</InputLabel>
|
|
||||||
<Select
|
<Select
|
||||||
labelId={`${type}-${index}-children-label`}
|
|
||||||
label="Have Children"
|
label="Have Children"
|
||||||
value={sibling.haveChildrens}
|
value={sibling.hasChildren}
|
||||||
onChange={(e) =>
|
onChange={(e) => handleSiblingChange(type, index, "hasChildren", e.target.value)}
|
||||||
handleSiblingChange(
|
|
||||||
type,
|
|
||||||
index,
|
|
||||||
"haveChildrens",
|
|
||||||
e.target.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<MenuItem value={1}>Yes</MenuItem>
|
<MenuItem value=""><em>Select</em></MenuItem>
|
||||||
<MenuItem value={0}>No</MenuItem>
|
<MenuItem value="Yes">Yes</MenuItem>
|
||||||
|
<MenuItem value="No">No</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</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>
|
</div>
|
||||||
</Box>
|
</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">
|
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
||||||
<form noValidate autoComplete="off" style={{ padding: 16 }}>
|
<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="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]">
|
<label className="text-gray-900 text-[15px]">
|
||||||
Father Name{requiredMark}
|
Father Name{requiredMark}
|
||||||
</label>
|
</label>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
inputRef={inputRef}
|
inputRef={inputRef}
|
||||||
name="fatherName"
|
placeholder="Enter Father Name"
|
||||||
label="Father Name"
|
|
||||||
value={data.fatherName}
|
value={data.fatherName}
|
||||||
onChange={(e) => handleChange("fatherName", e.target.value)}
|
onChange={(e) => handleChange("fatherName", e.target.value)}
|
||||||
error={Boolean(errors.fatherName)}
|
error={Boolean(errors.fatherName)}
|
||||||
helperText={errors.fatherName}
|
helperText={errors.fatherName}
|
||||||
placeholder="Enter Father Name"
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -236,30 +290,24 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
</label>
|
</label>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
name="fatherOccupation"
|
placeholder="Enter Father Occupation"
|
||||||
label="Father Occupation"
|
|
||||||
value={data.fatherOccupation}
|
value={data.fatherOccupation}
|
||||||
onChange={(e) => handleChange("fatherOccupation", e.target.value)}
|
onChange={(e) => handleChange("fatherOccupation", e.target.value)}
|
||||||
error={Boolean(errors.fatherOccupation)}
|
|
||||||
helperText={errors.fatherOccupation}
|
|
||||||
placeholder="Enter Father Occupation"
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4" id="motherName">
|
||||||
<label className="text-gray-900 text-[15px]">
|
<label className="text-gray-900 text-[15px]">
|
||||||
Mother Name{requiredMark}
|
Mother Name{requiredMark}
|
||||||
</label>
|
</label>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
name="motherName"
|
placeholder="Enter Mother Name"
|
||||||
label="Mother Name"
|
|
||||||
value={data.motherName}
|
value={data.motherName}
|
||||||
onChange={(e) => handleChange("motherName", e.target.value)}
|
onChange={(e) => handleChange("motherName", e.target.value)}
|
||||||
error={Boolean(errors.motherName)}
|
error={Boolean(errors.motherName)}
|
||||||
helperText={errors.motherName}
|
helperText={errors.motherName}
|
||||||
placeholder="Enter Mother Name"
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -270,13 +318,9 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
</label>
|
</label>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
name="motherOccupation"
|
placeholder="Enter Mother Occupation"
|
||||||
label="Mother Occupation"
|
|
||||||
value={data.motherOccupation}
|
value={data.motherOccupation}
|
||||||
onChange={(e) => handleChange("motherOccupation", e.target.value)}
|
onChange={(e) => handleChange("motherOccupation", e.target.value)}
|
||||||
error={Boolean(errors.motherOccupation)}
|
|
||||||
helperText={errors.motherOccupation}
|
|
||||||
placeholder="Enter Mother Occupation"
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -286,14 +330,13 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
Brother Count
|
Brother Count
|
||||||
</label>
|
</label>
|
||||||
<FormControl fullWidth variant="outlined">
|
<FormControl fullWidth variant="outlined">
|
||||||
<InputLabel id="brotherCount-label">Select Brother Count</InputLabel>
|
<InputLabel>Select Brother Count</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
labelId="brotherCount-label"
|
|
||||||
label="Select Brother Count"
|
label="Select Brother Count"
|
||||||
name="brotherCount"
|
|
||||||
value={data.brotherCount}
|
value={data.brotherCount}
|
||||||
onChange={(e) => handleChange("brotherCount", e.target.value)}
|
onChange={(e) => handleChange("brotherCount", e.target.value)}
|
||||||
>
|
>
|
||||||
|
<MenuItem value=""><em>Select</em></MenuItem>
|
||||||
{countOptions.map((count) => (
|
{countOptions.map((count) => (
|
||||||
<MenuItem key={count} value={count}>
|
<MenuItem key={count} value={count}>
|
||||||
{count}
|
{count}
|
||||||
@ -303,19 +346,27 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</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">
|
<div className="flex flex-col gap-4">
|
||||||
<label className="text-gray-900 text-[15px]">
|
<label className="text-gray-900 text-[15px]">
|
||||||
Sister Count
|
Sister Count
|
||||||
</label>
|
</label>
|
||||||
<FormControl fullWidth variant="outlined">
|
<FormControl fullWidth variant="outlined">
|
||||||
<InputLabel id="sisterCount-label">Select Sister Count</InputLabel>
|
<InputLabel>Select Sister Count</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
labelId="sisterCount-label"
|
|
||||||
label="Select Sister Count"
|
label="Select Sister Count"
|
||||||
name="sisterCount"
|
|
||||||
value={data.sisterCount}
|
value={data.sisterCount}
|
||||||
onChange={(e) => handleChange("sisterCount", e.target.value)}
|
onChange={(e) => handleChange("sisterCount", e.target.value)}
|
||||||
>
|
>
|
||||||
|
<MenuItem value=""><em>Select</em></MenuItem>
|
||||||
{countOptions.map((count) => (
|
{countOptions.map((count) => (
|
||||||
<MenuItem key={count} value={count}>
|
<MenuItem key={count} value={count}>
|
||||||
{count}
|
{count}
|
||||||
@ -325,105 +376,183 @@ const FamilyDetailsForm = ({ onSubmitStep, onSkipStep, errors, onFieldChange })
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</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]">
|
<label className="text-gray-900 text-[15px]">
|
||||||
Family Status{requiredMark}
|
Family Status{requiredMark}
|
||||||
</label>
|
</label>
|
||||||
<FormControl
|
<FormControl fullWidth variant="outlined" error={Boolean(errors.familyStatus)}>
|
||||||
fullWidth
|
<InputLabel>Select Family Status</InputLabel>
|
||||||
variant="outlined"
|
|
||||||
error={Boolean(errors.familyStatus)}
|
|
||||||
>
|
|
||||||
<InputLabel id="familyStatus-label">Select Family Status</InputLabel>
|
|
||||||
<Select
|
<Select
|
||||||
labelId="familyStatus-label"
|
|
||||||
label="Select Family Status"
|
label="Select Family Status"
|
||||||
name="familyStatus"
|
|
||||||
value={data.familyStatus}
|
value={data.familyStatus}
|
||||||
onChange={(e) => handleChange("familyStatus", e.target.value)}
|
onChange={(e) => handleChange("familyStatus", e.target.value)}
|
||||||
disabled={isFamilyMastersLoading}
|
|
||||||
sx={{
|
|
||||||
"& .MuiSelect-select.Mui-disabled": {
|
|
||||||
cursor: "not-allowed",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{familyStatusOptions.map((item) => (
|
{familyStatusOptions.map((item) => (
|
||||||
<MenuItem key={item.id ?? item} value={item.id ?? item}>
|
<MenuItem key={item.id} value={item.id}>
|
||||||
{item.family_type_name || item.name || item}
|
{item.family_type_name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
{errors.familyStatus && (
|
{errors.familyStatus && (
|
||||||
<p
|
<p className="text-[#d32f2f] text-[0.75rem] mt-1 ml-3">{errors.familyStatus}</p>
|
||||||
style={{
|
|
||||||
color: "#d32f2f",
|
|
||||||
margin: "3px 14px 0 14px",
|
|
||||||
fontSize: "0.75rem",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{errors.familyStatus}
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4" id="nativePlace">
|
||||||
<label className="text-gray-900 text-[15px]">Native Place</label>
|
<label className="text-gray-900 text-[15px]">
|
||||||
|
Native Place{requiredMark}
|
||||||
|
</label>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
name="nativePlace"
|
placeholder="Enter Native Place"
|
||||||
label="Native Place"
|
|
||||||
value={data.nativePlace}
|
value={data.nativePlace}
|
||||||
onChange={(e) => handleChange("nativePlace", e.target.value)}
|
onChange={(e) => handleChange("nativePlace", e.target.value)}
|
||||||
error={Boolean(errors.nativePlace)}
|
error={Boolean(errors.nativePlace)}
|
||||||
helperText={errors.nativePlace}
|
helperText={errors.nativePlace}
|
||||||
placeholder="Enter Native Place"
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
{Number(data.brotherCount) > 0 && (
|
<div className="mt-10 flex gap-4 justify-center">
|
||||||
<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" }}
|
|
||||||
>
|
|
||||||
{onSkipStep && (
|
{onSkipStep && (
|
||||||
<Button variant="outlined" onClick={onSkipStep}>
|
<Button variant="outlined" onClick={onSkipStep} sx={{ minWidth: 120 }}>
|
||||||
Skip
|
Skip
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button variant="contained" color="primary" onClick={handleSubmit}>
|
<Button variant="contained" color="primary" onClick={handleSubmit} sx={{ minWidth: 120 }}>
|
||||||
{onSkipStep ? "Next" : "Update"}
|
{onSkipStep ? "Next" : "Update"}
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } 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, clearAllStepsFrom } from "../redux/registrationFormSlice";
|
||||||
import {
|
import {
|
||||||
Grid,
|
Grid,
|
||||||
FormControl,
|
FormControl,
|
||||||
@ -30,6 +30,7 @@ const LifestyleDetailsForm = ({
|
|||||||
onSkipStep,
|
onSkipStep,
|
||||||
errors,
|
errors,
|
||||||
onFieldChange,
|
onFieldChange,
|
||||||
|
isEditMode,
|
||||||
}) => {
|
}) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const data = useSelector((state) => state.registerform.lifestyleDetails);
|
const data = useSelector((state) => state.registerform.lifestyleDetails);
|
||||||
@ -76,6 +77,10 @@ const LifestyleDetailsForm = ({
|
|||||||
const handleChange = (field, value) => {
|
const handleChange = (field, value) => {
|
||||||
dispatch(updateLifestyleDetails({ [field]: value }));
|
dispatch(updateLifestyleDetails({ [field]: value }));
|
||||||
if (onFieldChange) onFieldChange(field);
|
if (onFieldChange) onFieldChange(field);
|
||||||
|
|
||||||
|
if (!isEditMode) {
|
||||||
|
dispatch(clearAllStepsFrom(5));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMultiChange = (field, value) => {
|
const handleMultiChange = (field, value) => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -397,10 +397,10 @@ const PreviewScreen = ({ onEdit, onSubmit }) => {
|
|||||||
{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;
|
||||||
let displayValue = sVal;
|
let displayValue = sVal;
|
||||||
if (sKey === 'haveChildrens' || sKey === 'have_childrens') {
|
if (sKey === 'haveChildrens' || sKey === 'have_childrens' || sKey === 'hasChildren' || sKey === 'has_children') {
|
||||||
if (sVal === true || sVal === 1 || sVal === '1') {
|
if (sVal === true || sVal === 1 || sVal === '1' || sVal === 'Yes') {
|
||||||
displayValue = 'Yes';
|
displayValue = 'Yes';
|
||||||
} else if (sVal === false || sVal === 0 || sVal === '0') {
|
} else if (sVal === false || sVal === 0 || sVal === '0' || sVal === 'No') {
|
||||||
displayValue = 'No';
|
displayValue = 'No';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
updateFamilyDetails,
|
updateFamilyDetails,
|
||||||
updateLifestyleDetails,
|
updateLifestyleDetails,
|
||||||
updatePartnerPreferences,
|
updatePartnerPreferences,
|
||||||
|
clearAllStepsFrom,
|
||||||
submitForm,
|
submitForm,
|
||||||
} from "../redux/registrationFormSlice";
|
} from "../redux/registrationFormSlice";
|
||||||
import PersonalDetailsForm from "./PersonalDetailsForm";
|
import PersonalDetailsForm from "./PersonalDetailsForm";
|
||||||
@ -31,37 +32,47 @@ import { isAuthenticated } from "../utills/auth";
|
|||||||
import { getPreviewDetails } from "../api/preview.api";
|
import { getPreviewDetails } from "../api/preview.api";
|
||||||
const STEP_FIELD_ORDER = {
|
const STEP_FIELD_ORDER = {
|
||||||
1: [
|
1: [
|
||||||
"name",
|
"profile_for",
|
||||||
"gender",
|
"gender",
|
||||||
"mobileNumber",
|
"name",
|
||||||
"dob",
|
"mobile",
|
||||||
"height",
|
|
||||||
"weight",
|
|
||||||
"maritalStatus",
|
|
||||||
"religion",
|
|
||||||
"profileFor",
|
|
||||||
"caste",
|
|
||||||
"subCaste",
|
|
||||||
"gothram",
|
|
||||||
"raasi",
|
|
||||||
"star",
|
|
||||||
"email",
|
"email",
|
||||||
"password",
|
"password",
|
||||||
"confirmPassword",
|
"confirmPassword",
|
||||||
"state",
|
"marital_status",
|
||||||
"city",
|
"height",
|
||||||
"pincode",
|
"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",
|
"profiles",
|
||||||
],
|
],
|
||||||
2: [
|
2: [
|
||||||
"fieldOfStudy",
|
"study_field",
|
||||||
"qualification",
|
"education",
|
||||||
"collegeName",
|
"education_detail",
|
||||||
|
"college_name",
|
||||||
|
"employee_type",
|
||||||
"occupation",
|
"occupation",
|
||||||
"organization",
|
"occupation_detail",
|
||||||
"employeeType",
|
"company_name",
|
||||||
"income",
|
"income_currency",
|
||||||
"workLocation",
|
"annual_income",
|
||||||
|
"work_country",
|
||||||
|
"work_city",
|
||||||
|
"work_state",
|
||||||
|
"work_district",
|
||||||
|
"address",
|
||||||
],
|
],
|
||||||
3: [
|
3: [
|
||||||
"fatherName",
|
"fatherName",
|
||||||
@ -89,35 +100,29 @@ const STEP_FIELD_ORDER = {
|
|||||||
|
|
||||||
const STEP1_SERVER_FIELD_MAP = {
|
const STEP1_SERVER_FIELD_MAP = {
|
||||||
name: "name",
|
name: "name",
|
||||||
mobile: "mobileNumber",
|
mobile: "mobile",
|
||||||
mobile_number: "mobileNumber",
|
|
||||||
mobileNumber: "mobileNumber",
|
|
||||||
phone: "mobileNumber",
|
|
||||||
email: "email",
|
email: "email",
|
||||||
gender: "gender",
|
gender: "gender",
|
||||||
dob: "dob",
|
|
||||||
height: "height",
|
height: "height",
|
||||||
weight: "weight",
|
weight: "weight",
|
||||||
marital_status: "maritalStatus",
|
marital_status: "marital_status",
|
||||||
maritalStatus: "maritalStatus",
|
|
||||||
religion: "religion",
|
religion: "religion",
|
||||||
profile_for: "profileFor",
|
profile_for: "profile_for",
|
||||||
profileFor: "profileFor",
|
|
||||||
caste: "caste",
|
caste: "caste",
|
||||||
sub_caste: "subCaste",
|
sub_caste: "sub_caste",
|
||||||
subCaste: "subCaste",
|
willing_to_marry: "willing_to_marry",
|
||||||
|
inter_caste_parents: "inter_caste_parents",
|
||||||
|
inter_caste_parents_details: "inter_caste_parents_details",
|
||||||
gothram: "gothram",
|
gothram: "gothram",
|
||||||
raasi: "raasi",
|
do_you_speak_telugu: "do_you_speak_telugu",
|
||||||
star: "star",
|
about_us: "about_us",
|
||||||
state: "state",
|
known_languages: "known_languages",
|
||||||
district: "city",
|
mother_language: "mother_language",
|
||||||
city: "city",
|
complexion: "complexion",
|
||||||
pincode: "pincode",
|
physical_status: "physical_status",
|
||||||
password: "password",
|
password: "password",
|
||||||
confirm_password: "confirmPassword",
|
confirm_password: "confirmPassword",
|
||||||
confirmPassword: "confirmPassword",
|
|
||||||
profiles: "profiles",
|
profiles: "profiles",
|
||||||
profile_images: "profiles",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -171,8 +176,7 @@ const STEP1_SERVER_FIELD_MAP = {
|
|||||||
|
|
||||||
import { Check } from "lucide-react";
|
import { Check } from "lucide-react";
|
||||||
|
|
||||||
const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick }) => {
|
const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick, checkStepValidity }) => {
|
||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{ num: 1, label: "Personal" },
|
{ num: 1, label: "Personal" },
|
||||||
{ num: 2, label: "Educational" },
|
{ num: 2, label: "Educational" },
|
||||||
@ -183,40 +187,57 @@ const Stepper = ({ currentStep, enabledSteps, completedSteps, onStepClick }) =>
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
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) => {
|
{steps.map((step, index) => {
|
||||||
const isEnabled = enabledSteps.includes(step.num);
|
const isSkippable = currentStep > 1 && currentStep < 6 && step.num === currentStep + 1;
|
||||||
const isCompleted = completedSteps.includes(step.num);
|
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 (
|
return (
|
||||||
<React.Fragment key={step.num}>
|
<React.Fragment key={step.num}>
|
||||||
<div
|
<div
|
||||||
className={`flex flex-col items-center ${
|
className={`flex flex-col items-center min-w-[70px] ${
|
||||||
isEnabled ? "cursor-pointer" : "cursor-not-allowed opacity-50"
|
isEnabled ? "cursor-pointer" : "cursor-not-allowed opacity-60"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => isEnabled && onStepClick(step.num)}
|
onClick={() => isEnabled && onStepClick(step.num)}
|
||||||
>
|
>
|
||||||
<div
|
<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
|
isCompleted
|
||||||
? "bg-green-600 text-white"
|
? "bg-green-600 text-white shadow-md"
|
||||||
: currentStep === step.num
|
: isActive
|
||||||
? "bg-red-600 text-white"
|
? "bg-red-600 text-white ring-4 ring-red-100 shadow-md"
|
||||||
: "bg-gray-300 text-gray-600"
|
: 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>
|
</div>
|
||||||
|
<span
|
||||||
<span className="text-xs mt-1">{step.label}</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>
|
</div>
|
||||||
|
|
||||||
{index < steps.length - 1 && (
|
{index < steps.length - 1 && (
|
||||||
<div
|
<div
|
||||||
className={`flex-1 h-0.5 mx-1 ${
|
className={`flex-1 h-[2px] mx-1 mb-6 transition-colors duration-500 ${
|
||||||
completedSteps.includes(step.num)
|
(completedSteps.includes(step.num) || (checkStepValidity && checkStepValidity(step.num)))
|
||||||
? "bg-green-600"
|
? "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");
|
const savedStep = localStorage.getItem("registration_current_step");
|
||||||
return savedStep ? Number(savedStep) : 1;
|
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 [completedSteps, setCompletedSteps] = useState([]);
|
||||||
const [isStep1Update, setIsStep1Update] = useState(false);
|
const [isStep1Update, setIsStep1Update] = useState(false);
|
||||||
const [errors, setErrors] = useState({});
|
const [errors, setErrors] = useState({});
|
||||||
@ -362,24 +390,23 @@ const [completedSteps, setCompletedSteps] = useState([]);
|
|||||||
order[0] ||
|
order[0] ||
|
||||||
Object.keys(errorMap).find((key) => key !== "_form");
|
Object.keys(errorMap).find((key) => key !== "_form");
|
||||||
if (!firstKey) return;
|
if (!firstKey) return;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const byAria = document.querySelector(
|
const element = document.getElementById(firstKey) ||
|
||||||
`[aria-labelledby~="${firstKey}-label"]`
|
document.querySelector(`[name="${firstKey}"]`) ||
|
||||||
);
|
document.querySelector(`[aria-labelledby~="${firstKey}-label"]`);
|
||||||
if (byAria && typeof byAria.focus === "function") {
|
|
||||||
byAria.focus();
|
if (element) {
|
||||||
return;
|
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}"]`);
|
}, 100);
|
||||||
if (byName && typeof byName.focus === "function") {
|
|
||||||
byName.focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const byId = document.getElementById(firstKey);
|
|
||||||
if (byId && typeof byId.focus === "function") {
|
|
||||||
byId.focus();
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearFieldErrors = (fields) => {
|
const clearFieldErrors = (fields) => {
|
||||||
@ -474,18 +501,27 @@ const [completedSteps, setCompletedSteps] = useState([]);
|
|||||||
dispatch(
|
dispatch(
|
||||||
updatePersonalDetails({
|
updatePersonalDetails({
|
||||||
name: pd.name || "",
|
name: pd.name || "",
|
||||||
mobileNumber: pd.mobile || "",
|
mobile: pd.mobile || "",
|
||||||
email: pd.email || "",
|
email: pd.email || "",
|
||||||
gender: pd.gender || "",
|
gender: pd.gender || "",
|
||||||
dob: formattedDob,
|
dob: formattedDob,
|
||||||
height: pd.height || "",
|
height: pd.height_id || "",
|
||||||
weight: pd.weight || "",
|
weight: pd.weight || "",
|
||||||
maritalStatus: pd.marital_status_id || "",
|
marital_status: pd.marital_status_id || "",
|
||||||
religion: pd.religion_id || "",
|
religion: pd.religion_id || "",
|
||||||
profileFor: pd.profile_for_id || "",
|
profile_for: pd.profile_for_id || "",
|
||||||
caste: pd.caste_id || "",
|
caste: pd.caste_id || "",
|
||||||
subCaste: pd.sub_caste_id || "",
|
sub_caste: pd.sub_caste_id || "",
|
||||||
gothram: pd.gothram_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 || "",
|
raasi: pd.raasi_id || "",
|
||||||
star: pd.star_id || "",
|
star: pd.star_id || "",
|
||||||
state: pd.state_id || "",
|
state: pd.state_id || "",
|
||||||
@ -518,14 +554,21 @@ useEffect(() => {
|
|||||||
const ed = educationalData.educational_details;
|
const ed = educationalData.educational_details;
|
||||||
dispatch(
|
dispatch(
|
||||||
updateEducationalDetails({
|
updateEducationalDetails({
|
||||||
fieldOfStudy: ed.study_field_id || "",
|
study_field: ed.study_field_id || "",
|
||||||
qualification: ed.education_id || "",
|
education: ed.education_id || "",
|
||||||
collegeName: ed.college_name || "",
|
education_detail: ed.education_detail || "",
|
||||||
|
college_name: ed.college_name || "",
|
||||||
|
employee_type: ed.employee_type_id || "",
|
||||||
occupation: ed.occupation_id || "",
|
occupation: ed.occupation_id || "",
|
||||||
organization: ed.company_name || "",
|
occupation_detail: ed.occupation_detail || "",
|
||||||
employeeType: ed.employee_type_id || "",
|
company_name: ed.company_name || "",
|
||||||
income: ed.annual_income_id || "",
|
income_currency: ed.income_currency || "INR",
|
||||||
workLocation: ed.work_location || "",
|
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(()=>{
|
useEffect(() => {
|
||||||
if (familyData?.status === "success" && familyData?.family_details) {
|
if (familyData?.status === "success" && familyData?.family_details) {
|
||||||
const fd = familyData.family_details;
|
const fd = familyData.family_details;
|
||||||
|
dispatch(
|
||||||
const mappedBrothers = (fd.brothers || []).map((b) => ({
|
updateFamilyDetails({
|
||||||
name: b.name || "",
|
fatherName: fd.father_name || "",
|
||||||
occupation: b.occupation_name || "",
|
fatherOccupation: fd.father_occupation || "",
|
||||||
maritalStatus: b.marital_status || "",
|
motherName: fd.mother_name || "",
|
||||||
haveChildrens: b.have_childrens === true ? 1 : (b.have_childrens === false ? 0 : b.have_childrens),
|
motherOccupation: fd.mother_occupation || "",
|
||||||
}));
|
familyStatus: fd.family_status_id || "",
|
||||||
|
nativePlace: fd.native_place || "",
|
||||||
const mappedSisters = (fd.sisters || []).map((s) => ({
|
familyCountry: fd.family_country_id || "",
|
||||||
name: s.name || "",
|
familyState: fd.family_state_id || "",
|
||||||
occupation: s.occupation_name || "",
|
familyDistrict: fd.family_district_id || "",
|
||||||
maritalStatus: s.marital_status || "",
|
familyCity: fd.family_city || "",
|
||||||
haveChildrens: s.have_childrens === true ? 1 : (s.have_childrens === false ? 0 : s.have_childrens),
|
address: fd.address || "",
|
||||||
}));
|
expectationDetails: fd.expectation_details || "",
|
||||||
|
willingToGoAbroad: fd.willing_to_go_abroad || "",
|
||||||
dispatch(
|
brotherCount: fd.brother_count || 0,
|
||||||
updateFamilyDetails({
|
sisterCount: fd.sister_count || 0,
|
||||||
fatherName: fd.father_name || "",
|
brothers: (fd.brothers || []).map((b) => ({
|
||||||
fatherOccupation: fd.father_occupation || "",
|
name: b.name || "",
|
||||||
motherName: fd.mother_name || "",
|
occupation: b.occupation_name || "",
|
||||||
motherOccupation: fd.mother_occupation || "",
|
maritalStatus: b.marital_status || "",
|
||||||
familyStatus: fd.family_status_id || "",
|
type: b.type || "",
|
||||||
nativePlace: fd.native_place || "",
|
hasChildren: b.has_children || "",
|
||||||
brotherCount: fd.brother_count || 0,
|
details: b.additional_details || ""
|
||||||
sisterCount: fd.sister_count || 0,
|
})),
|
||||||
brothers: mappedBrothers,
|
sisters: (fd.sisters || []).map((s) => ({
|
||||||
sisters: mappedSisters,
|
name: s.name || "",
|
||||||
})
|
occupation: s.occupation_name || "",
|
||||||
);
|
maritalStatus: s.marital_status || "",
|
||||||
}
|
type: s.type || "",
|
||||||
|
hasChildren: s.has_children || "",
|
||||||
},[familyData,dispatch])
|
details: s.additional_details || ""
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [familyData, dispatch]);
|
||||||
|
|
||||||
// Fetch Lifestyle Details
|
// Fetch Lifestyle Details
|
||||||
const { data: lifestyleData } = useQuery({
|
const { data: lifestyleData } = useQuery({
|
||||||
@ -668,23 +716,24 @@ useEffect(()=>{
|
|||||||
if (step === 1) {
|
if (step === 1) {
|
||||||
const required = [
|
const required = [
|
||||||
"name",
|
"name",
|
||||||
"mobileNumber",
|
"mobile",
|
||||||
"gender",
|
"gender",
|
||||||
"dob",
|
|
||||||
"height",
|
"height",
|
||||||
"maritalStatus",
|
"marital_status",
|
||||||
"profileFor",
|
"profile_for",
|
||||||
"caste",
|
"caste",
|
||||||
"email",
|
"email",
|
||||||
"state",
|
"mother_language",
|
||||||
"city",
|
"complexion",
|
||||||
"pincode",
|
"physical_status",
|
||||||
|
"inter_caste_parents",
|
||||||
|
"do_you_speak_telugu",
|
||||||
];
|
];
|
||||||
|
|
||||||
required.forEach((field) => {
|
required.forEach((field) => {
|
||||||
if (!personalDetails[field]) {
|
if (!personalDetails[field] && personalDetails[field] !== 0) {
|
||||||
const label = field
|
const label = field
|
||||||
.replace(/([A-Z])/g, " $1")
|
.replace(/_/g, " ")
|
||||||
.replace(/^./, (str) => str.toUpperCase());
|
.replace(/^./, (str) => str.toUpperCase());
|
||||||
newErrors[field] = `${label} is required`;
|
newErrors[field] = `${label} is required`;
|
||||||
}
|
}
|
||||||
@ -702,16 +751,10 @@ useEffect(()=>{
|
|||||||
newErrors.email = "Invalid email format";
|
newErrors.email = "Invalid email format";
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
personalDetails.mobileNumber &&
|
personalDetails.mobile &&
|
||||||
personalDetails.mobileNumber.length !== 10
|
personalDetails.mobile.length !== 10
|
||||||
) {
|
) {
|
||||||
newErrors.mobileNumber = "Mobile number must be 10 digits";
|
newErrors.mobile = "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";
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
personalDetails.password &&
|
personalDetails.password &&
|
||||||
@ -721,16 +764,24 @@ useEffect(()=>{
|
|||||||
newErrors.confirmPassword = "Passwords do not match";
|
newErrors.confirmPassword = "Passwords do not match";
|
||||||
}
|
}
|
||||||
} else if (step === 2) {
|
} else if (step === 2) {
|
||||||
const required = [
|
const isUnemployed = educationalDetails.employee_type === 11;
|
||||||
"qualification",
|
const isIndia = educationalDetails.work_country === 1;
|
||||||
"fieldOfStudy",
|
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) => {
|
required.forEach((field) => {
|
||||||
if (!educationalDetails[field]) {
|
if (!educationalDetails[field]) {
|
||||||
const label = field
|
const label = field
|
||||||
.replace(/([A-Z])/g, " $1")
|
.replace(/_/g, " ")
|
||||||
.replace(/^./, (str) => str.toUpperCase());
|
.replace(/^./, (str) => str.toUpperCase());
|
||||||
newErrors[field] = `${label} is required`;
|
newErrors[field] = `${label} is required`;
|
||||||
}
|
}
|
||||||
@ -740,6 +791,7 @@ useEffect(()=>{
|
|||||||
"fatherName",
|
"fatherName",
|
||||||
"motherName",
|
"motherName",
|
||||||
"familyStatus",
|
"familyStatus",
|
||||||
|
"nativePlace",
|
||||||
];
|
];
|
||||||
required.forEach((field) => {
|
required.forEach((field) => {
|
||||||
if (!familyDetails[field]) {
|
if (!familyDetails[field]) {
|
||||||
@ -836,24 +888,33 @@ useEffect(()=>{
|
|||||||
const buildRegisterStep1Payload = async () => {
|
const buildRegisterStep1Payload = async () => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("name", personalDetails.name);
|
formData.append("name", personalDetails.name);
|
||||||
formData.append("mobile", personalDetails.mobileNumber);
|
formData.append("mobile", personalDetails.mobile);
|
||||||
formData.append("email", personalDetails.email);
|
formData.append("email", personalDetails.email);
|
||||||
formData.append("pincode", personalDetails.pincode);
|
|
||||||
formData.append("gender", personalDetails.gender);
|
formData.append("gender", personalDetails.gender);
|
||||||
formData.append("dob", personalDetails.dob);
|
|
||||||
formData.append("height", personalDetails.height || "");
|
formData.append("height", personalDetails.height || "");
|
||||||
formData.append("weight", personalDetails.weight || "");
|
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("religion", personalDetails.religion);
|
||||||
formData.append("profile_for", personalDetails.profileFor || "");
|
formData.append("profile_for", personalDetails.profile_for || "");
|
||||||
formData.append("caste", personalDetails.caste);
|
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("gothram", personalDetails.gothram || "");
|
||||||
formData.append("raasi", personalDetails.raasi || "");
|
formData.append("do_you_speak_telugu", personalDetails.do_you_speak_telugu);
|
||||||
formData.append("star", personalDetails.star || "");
|
formData.append("about_us", personalDetails.about_us || "");
|
||||||
formData.append("state", personalDetails.state);
|
formData.append("mother_language", personalDetails.mother_language || "");
|
||||||
formData.append("district", personalDetails.city);
|
formData.append("complexion", personalDetails.complexion || "");
|
||||||
formData.append("password", personalDetails.password || "");
|
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") || "");
|
formData.append("web_fcm_token", localStorage.getItem("fcm_token") || "");
|
||||||
|
|
||||||
if (personalDetails.profiles && Array.isArray(personalDetails.profiles)) {
|
if (personalDetails.profiles && Array.isArray(personalDetails.profiles)) {
|
||||||
@ -895,14 +956,23 @@ useEffect(()=>{
|
|||||||
|
|
||||||
const buildRegisterStep2Payload = () => {
|
const buildRegisterStep2Payload = () => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("college_name", educationalDetails.collegeName || "");
|
formData.append("study_field", educationalDetails.study_field || "");
|
||||||
formData.append("study_field", educationalDetails.fieldOfStudy || "");
|
formData.append("education", educationalDetails.education || "");
|
||||||
formData.append("education", educationalDetails.qualification || "");
|
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("occupation", educationalDetails.occupation || "");
|
||||||
formData.append("company_name", educationalDetails.organization || "");
|
formData.append("occupation_detail", educationalDetails.occupation_detail || "");
|
||||||
formData.append("employee_type", educationalDetails.employeeType || "");
|
formData.append("company_name", educationalDetails.company_name || "");
|
||||||
formData.append("annual_income", educationalDetails.income || "");
|
formData.append("income_currency", educationalDetails.income_currency || "INR");
|
||||||
formData.append("work_location", educationalDetails.workLocation || "");
|
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;
|
return formData;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -916,19 +986,30 @@ useEffect(()=>{
|
|||||||
formData.append("native_place", familyDetails.nativePlace || "");
|
formData.append("native_place", familyDetails.nativePlace || "");
|
||||||
formData.append("brother_count", familyDetails.brotherCount || 0);
|
formData.append("brother_count", familyDetails.brotherCount || 0);
|
||||||
formData.append("sister_count", familyDetails.sisterCount || 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) => {
|
(familyDetails.brothers || []).forEach((brother, index) => {
|
||||||
formData.append(`brothers[${index}][name]`, brother?.name || "");
|
formData.append(`brothers[${index}][name]`, brother?.name || "");
|
||||||
formData.append(`brothers[${index}][occupation]`, brother?.occupation || "");
|
formData.append(`brothers[${index}][occupation]`, brother?.occupation || "");
|
||||||
formData.append(`brothers[${index}][marital_status]`, brother?.maritalStatus || "");
|
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) => {
|
(familyDetails.sisters || []).forEach((sister, index) => {
|
||||||
formData.append(`sisters[${index}][name]`, sister?.name || "");
|
formData.append(`sisters[${index}][name]`, sister?.name || "");
|
||||||
formData.append(`sisters[${index}][occupation]`, sister?.occupation || "");
|
formData.append(`sisters[${index}][occupation]`, sister?.occupation || "");
|
||||||
formData.append(`sisters[${index}][marital_status]`, sister?.maritalStatus || "");
|
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;
|
return formData;
|
||||||
@ -1053,6 +1134,12 @@ useEffect(()=>{
|
|||||||
|
|
||||||
const token = extractAccessToken(res.data || res);
|
const token = extractAccessToken(res.data || res);
|
||||||
if (token) setAccessToken(token);
|
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;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
@ -1141,29 +1228,43 @@ useEffect(()=>{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSkip = () => {
|
const handleSkip = () => {
|
||||||
setErrors({});
|
setErrors({});
|
||||||
|
|
||||||
|
// Remove from completed if skipping (matching Flutter logic)
|
||||||
|
setCompletedSteps((prev) => prev.filter(s => s !== currentStep));
|
||||||
|
|
||||||
setCurrentStep((prev) => {
|
setCurrentStep((prev) => {
|
||||||
const nextStep = Math.min(prev + 1, 6);
|
const nextStep = Math.min(prev + 1, 6);
|
||||||
|
|
||||||
setEnabledSteps((steps) =>
|
setEnabledSteps((steps) =>
|
||||||
steps.includes(nextStep) ? steps : [...steps, nextStep]
|
steps.includes(nextStep) ? steps : [...steps, nextStep]
|
||||||
);
|
);
|
||||||
|
|
||||||
return nextStep;
|
return nextStep;
|
||||||
});
|
});
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStepClick = (step) => {
|
const handleStepClick = (step) => {
|
||||||
if (!enabledSteps.includes(step)) return;
|
// 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);
|
if (!enabledSteps.includes(step)) return;
|
||||||
setErrors({});
|
|
||||||
window.scrollTo(0, 0);
|
// 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(() => {
|
useEffect(() => {
|
||||||
if (currentStep === 6) {
|
if (currentStep === 6) {
|
||||||
@ -1203,7 +1304,7 @@ useEffect(() => {
|
|||||||
onSubmitStep={handleStepSubmit}
|
onSubmitStep={handleStepSubmit}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onFieldChange={clearFieldErrors}
|
onFieldChange={clearFieldErrors}
|
||||||
isStep1Update={isStep1Update}
|
isEditMode={isStep1Update || shouldHideStepper}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
@ -1213,6 +1314,7 @@ useEffect(() => {
|
|||||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onFieldChange={clearFieldErrors}
|
onFieldChange={clearFieldErrors}
|
||||||
|
isEditMode={shouldHideStepper}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 3:
|
case 3:
|
||||||
@ -1222,6 +1324,7 @@ useEffect(() => {
|
|||||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onFieldChange={clearFieldErrors}
|
onFieldChange={clearFieldErrors}
|
||||||
|
isEditMode={shouldHideStepper}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 4:
|
case 4:
|
||||||
@ -1231,6 +1334,7 @@ useEffect(() => {
|
|||||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onFieldChange={clearFieldErrors}
|
onFieldChange={clearFieldErrors}
|
||||||
|
isEditMode={shouldHideStepper}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 5:
|
case 5:
|
||||||
@ -1240,6 +1344,7 @@ useEffect(() => {
|
|||||||
onSkipStep={shouldHideStepper ? null : handleSkip}
|
onSkipStep={shouldHideStepper ? null : handleSkip}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onFieldChange={clearFieldErrors}
|
onFieldChange={clearFieldErrors}
|
||||||
|
isEditMode={shouldHideStepper}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 6:
|
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 getTitle = () => {
|
||||||
const titles = {
|
const titles = {
|
||||||
1: "Personal Details",
|
1: "Personal Details",
|
||||||
@ -1272,6 +1417,7 @@ useEffect(() => {
|
|||||||
onStepClick={handleStepClick}
|
onStepClick={handleStepClick}
|
||||||
enabledSteps={enabledSteps}
|
enabledSteps={enabledSteps}
|
||||||
completedSteps={completedSteps}
|
completedSteps={completedSteps}
|
||||||
|
checkStepValidity={checkStepValidity}
|
||||||
/> )}
|
/> )}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
168
src/hooks/useWebSocket.js
Normal file
168
src/hooks/useWebSocket.js
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
const WS_URL = "wss://www.thirukalyanam.amrithaa.net/backend/reverb/app/xk30gjh2ggmel5szmm5w?protocol=7&client=js&version=1.0";
|
||||||
|
|
||||||
|
// SINGLETON state to share across all components
|
||||||
|
let globalSocket = null;
|
||||||
|
let globalMessages = [];
|
||||||
|
let globalIsConnected = false;
|
||||||
|
let globalActiveChannels = new Set();
|
||||||
|
let subscribers = new Set();
|
||||||
|
let reconnectTimer = null;
|
||||||
|
let heartbeatTimer = null;
|
||||||
|
|
||||||
|
const notifySubscribers = () => {
|
||||||
|
subscribers.forEach(callback => callback({
|
||||||
|
messages: [...globalMessages],
|
||||||
|
isConnected: globalIsConnected
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const connect = () => {
|
||||||
|
if (globalSocket?.readyState === WebSocket.OPEN) return;
|
||||||
|
if (globalSocket?.readyState === WebSocket.CONNECTING) return;
|
||||||
|
|
||||||
|
console.log("[WS] Connecting to:", WS_URL);
|
||||||
|
const socket = new WebSocket(WS_URL);
|
||||||
|
globalSocket = socket;
|
||||||
|
|
||||||
|
socket.onopen = () => {
|
||||||
|
console.log("[WS] Open - Waiting for handshake...");
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log("[WS] RAW:", data);
|
||||||
|
|
||||||
|
// 1. Handshake
|
||||||
|
if (data.event === "pusher:connection_established") {
|
||||||
|
console.log("[WS] Handshake Complete | Socket ID:", data.data ? JSON.parse(data.data).socket_id : "N/A");
|
||||||
|
globalIsConnected = true;
|
||||||
|
|
||||||
|
// Auto-subscribe to all pending channels
|
||||||
|
if (globalActiveChannels.size > 0) {
|
||||||
|
console.log(`[WS] Re-subscribing to ${globalActiveChannels.size} channels...`);
|
||||||
|
globalActiveChannels.forEach(channel => {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
event: "pusher:subscribe",
|
||||||
|
data: { channel }
|
||||||
|
}));
|
||||||
|
console.log(`[WS] Subscribing to: ${channel}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
notifySubscribers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Heartbeat
|
||||||
|
if (data.event === "pusher:ping") {
|
||||||
|
socket.send(JSON.stringify({ event: "pusher:pong", data: {} }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data.event === "pusher:pong") return;
|
||||||
|
|
||||||
|
// 3. Subscription Succeeded
|
||||||
|
if (data.event === "pusher_internal:subscription_succeeded") {
|
||||||
|
console.log(`[WS] ✅ Subscribed to ${data.channel}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Subscription Error
|
||||||
|
if (data.event === "pusher:subscription_error") {
|
||||||
|
console.error(`[WS] ❌ Subscription failed for ${data.channel}`, data.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Regular Events
|
||||||
|
console.log(`[WS] 📩 Event: ${data.event} | Channel: ${data.channel}`);
|
||||||
|
globalMessages = [...globalMessages, data];
|
||||||
|
notifySubscribers();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("[WS] Parse Error:", err, event.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onclose = (event) => {
|
||||||
|
console.log(`[WS] Disconnected (Code: ${event.code}) - Reconnecting in 5s...`);
|
||||||
|
globalIsConnected = false;
|
||||||
|
notifySubscribers();
|
||||||
|
|
||||||
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
||||||
|
reconnectTimer = setTimeout(connect, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onerror = (err) => {
|
||||||
|
console.error("[WS] Error:", err);
|
||||||
|
socket.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Heartbeat
|
||||||
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
||||||
|
heartbeatTimer = setInterval(() => {
|
||||||
|
if (socket.readyState === WebSocket.OPEN) {
|
||||||
|
socket.send(JSON.stringify({ event: "pusher:ping", data: {} }));
|
||||||
|
}
|
||||||
|
}, 20000);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useWebSocket = (channels = []) => {
|
||||||
|
const [state, setState] = useState({
|
||||||
|
messages: globalMessages,
|
||||||
|
isConnected: globalIsConnected
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Add this component's listener
|
||||||
|
const callback = (newState) => setState(newState);
|
||||||
|
subscribers.add(callback);
|
||||||
|
|
||||||
|
// Initialize connection if needed
|
||||||
|
if (!globalSocket) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
subscribers.delete(callback);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Handle Dynamic Subscriptions
|
||||||
|
useEffect(() => {
|
||||||
|
if (!channels || channels.length === 0) return;
|
||||||
|
|
||||||
|
channels.forEach(channel => {
|
||||||
|
if (channel && !globalActiveChannels.has(channel)) {
|
||||||
|
globalActiveChannels.add(channel);
|
||||||
|
|
||||||
|
if (globalIsConnected && globalSocket?.readyState === WebSocket.OPEN) {
|
||||||
|
globalSocket.send(JSON.stringify({
|
||||||
|
event: "pusher:subscribe",
|
||||||
|
data: { channel }
|
||||||
|
}));
|
||||||
|
console.log(`[WS] Dynamic Subscribe: ${channel}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Optional: Cleanup old channels if they are no longer in the provided array
|
||||||
|
// But for a chat app, we often want to keep listening to notification channels.
|
||||||
|
// So we'll leave them for now unless we implement a more complex cleanup.
|
||||||
|
}, [channels]);
|
||||||
|
|
||||||
|
const unsubscribe = (channel) => {
|
||||||
|
if (channel && globalActiveChannels.has(channel)) {
|
||||||
|
globalActiveChannels.delete(channel);
|
||||||
|
if (globalIsConnected && globalSocket?.readyState === WebSocket.OPEN) {
|
||||||
|
globalSocket.send(JSON.stringify({
|
||||||
|
event: "pusher:unsubscribe",
|
||||||
|
data: { channel }
|
||||||
|
}));
|
||||||
|
console.log(`[WS] Unsubscribed from: ${channel}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...state, unsubscribe };
|
||||||
|
};
|
||||||
@ -1,42 +1,57 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Tabs, Tab, Box, Chip } from '@mui/material';
|
import { Tabs, Tab, Box, CircularProgress } from '@mui/material';
|
||||||
import { CheckCircle, Phone, ExpandMore } from '@mui/icons-material';
|
import { CheckCircle, Phone } from '@mui/icons-material';
|
||||||
import { ChevronDown } from 'lucide-react';
|
import { ChevronDown } from 'lucide-react';
|
||||||
|
import { getBlockedProfiles, getReportedProfiles, unblockProfile } from '../services/profileActionApi';
|
||||||
|
import { toast } from 'react-hot-toast';
|
||||||
|
|
||||||
const BlockedProfile = ({ profile }) => (
|
const BlockedProfile = ({ profile, onUnblock }) => (
|
||||||
<div className="bg-white border border-1 border-red-100 rounded-lg shadow-sm p-6 mb-4">
|
<div className="bg-white border border-1 border-red-100 rounded-lg shadow-sm p-6 mb-4">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
<div className="relative flex-shrink-0">
|
<div className="relative flex-shrink-0">
|
||||||
<img
|
<img
|
||||||
src={profile.image}
|
src={profile.photo || 'https://via.placeholder.com/150'}
|
||||||
alt={profile.name}
|
alt={profile.name}
|
||||||
className="w-32 h-32 rounded-2xl object-cover border-2 border-[#A70710]"
|
className="w-32 h-32 rounded-2xl object-cover border-2 border-[#A70710]"
|
||||||
/>
|
/>
|
||||||
<button className="w-8 h-8 flex justify-center items-center absolute bottom-0 right-0 bg-[#A70710] text-white rounded-full shadow-lg">
|
{/* <button className="w-8 h-8 flex justify-center items-center absolute bottom-0 right-0 bg-[#A70710] text-white rounded-full shadow-lg">
|
||||||
<Phone className="w-4 h-4" />
|
<Phone className="w-4 h-4" />
|
||||||
</button>
|
</button> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
{/* <div className="flex items-center gap-2 mb-1">
|
||||||
<CheckCircle className="text-green-500 w-5 h-5" />
|
<CheckCircle className="text-green-500 w-5 h-5" />
|
||||||
<span className="text-green-500 font-medium">Verified</span>
|
<span className="text-green-500 font-medium">Verified</span>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-1">{profile.name}</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-1">{profile.name}</h2>
|
||||||
<p className="text-gray-500 text-sm mb-3">{profile.id} | Profile Created by Parent</p>
|
<p className="text-gray-500 text-sm mb-3">{profile.member_id} | Profile Created by Parent</p>
|
||||||
|
|
||||||
<div className="space-y-1 text-gray-700">
|
<div className="space-y-1 text-gray-700">
|
||||||
<p className="font-medium">{profile.age} yrs, {profile.height}, {profile.language},</p>
|
<p className="font-medium">{profile.age ? `${profile.age} yrs` : ''}{profile.age && profile.height ? ', ' : ''}{profile.height || ''}</p>
|
||||||
<p className="font-medium">{profile.location},</p>
|
|
||||||
<p className="font-medium">{profile.education}, {profile.occupation}, ₹ {profile.income}, {profile.state}, India</p>
|
<p className="font-medium">
|
||||||
|
{[profile.district_name, profile.state_name].filter(Boolean).join(', ')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="font-medium">
|
||||||
|
{[
|
||||||
|
profile.education,
|
||||||
|
profile.occupation,
|
||||||
|
profile.annual_income_name ? `₹ ${profile.annual_income_name}` : null
|
||||||
|
].filter(Boolean).join(', ')}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 flex items-center justify-between border-t border-[#A70710] pt-4">
|
<div className="mt-6 flex items-center justify-between border-t border-[#A70710] pt-4">
|
||||||
<p className="text-gray-600">You have blocked this profile</p>
|
<p className="text-gray-600">You have blocked this profile</p>
|
||||||
<button className="bg-[#A70710] hover:bg-red-600 text-white px-8 py-2 rounded-full font-medium transition-colors">
|
<button
|
||||||
|
onClick={() => onUnblock(profile.id)}
|
||||||
|
className="bg-[#A70710] hover:bg-red-600 text-white px-8 py-2 rounded-full font-medium transition-colors"
|
||||||
|
>
|
||||||
UnBlock
|
UnBlock
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -49,7 +64,7 @@ const ReportedProfile = ({ profile, onViewReason }) => {
|
|||||||
<div className="flex flex-col sm:flex-row items-start gap-4">
|
<div className="flex flex-col sm:flex-row items-start gap-4">
|
||||||
<div className='overflow-hidden w-[100%] h-[100%] max-w-50 max-h-45 rounded-lg flex-shrink-0'>
|
<div className='overflow-hidden w-[100%] h-[100%] max-w-50 max-h-45 rounded-lg flex-shrink-0'>
|
||||||
<img
|
<img
|
||||||
src={profile.image}
|
src={profile.photo || 'https://via.placeholder.com/150'}
|
||||||
alt={profile.name}
|
alt={profile.name}
|
||||||
className="w-full h-full object-cover "
|
className="w-full h-full object-cover "
|
||||||
/>
|
/>
|
||||||
@ -57,25 +72,39 @@ const ReportedProfile = ({ profile, onViewReason }) => {
|
|||||||
<div className="flex-1 w-full">
|
<div className="flex-1 w-full">
|
||||||
<h3 className="text-lg font-bold text-gray-900 mb-1">{profile.name}</h3>
|
<h3 className="text-lg font-bold text-gray-900 mb-1">{profile.name}</h3>
|
||||||
<p className="text-sm text-gray-500 mb-2">
|
<p className="text-sm text-gray-500 mb-2">
|
||||||
ID : {profile.id} <span className="text-xs ml-1">Last seen {profile.lastSeen}</span>
|
ID : {profile.member_id} {profile.last_seen_at && <span className="text-xs ml-1">{profile.last_seen_at}</span>}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="space-y-1.5 text-sm">
|
<div className="space-y-1.5 text-sm">
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<span className="text-gray-400">•</span>
|
<span className="text-gray-400">•</span>
|
||||||
<span className="text-gray-600">Profile created by Parent</span>
|
<span className="text-gray-600">Profile created by Parent</span>
|
||||||
<span className="text-gray-400">•</span>
|
{profile.age && (
|
||||||
<span className="text-gray-600">{profile.age} yrs</span>
|
<>
|
||||||
</div>
|
<span className="text-gray-400">•</span>
|
||||||
<div className="flex items-center gap-2">
|
<span className="text-gray-600">{profile.age} yrs</span>
|
||||||
<span className="text-gray-400">•</span>
|
</>
|
||||||
<span className="text-gray-600">{profile.caste}</span>
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{profile.caste_name && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-gray-400">•</span>
|
||||||
|
<span className="text-gray-600">{profile.caste_name}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<span className="text-gray-400">•</span>
|
{profile.occupation && (
|
||||||
<span className="text-gray-600">{profile.occupation}</span>
|
<>
|
||||||
<span className="text-gray-400">•</span>
|
<span className="text-gray-400">•</span>
|
||||||
<span className="text-gray-600">{profile.location}</span>
|
<span className="text-gray-600">{profile.occupation}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{profile.district_name && (
|
||||||
|
<>
|
||||||
|
<span className="text-gray-400">•</span>
|
||||||
|
<span className="text-gray-600">{profile.district_name}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -100,20 +129,20 @@ const ReportReasonModal = ({ profile, onClose }) => {
|
|||||||
<div className="bg-white rounded-lg shadow-2xl max-w-md w-full p-6 animate-slideUp">
|
<div className="bg-white rounded-lg shadow-2xl max-w-md w-full p-6 animate-slideUp">
|
||||||
<div className="flex items-start gap-4 mb-4">
|
<div className="flex items-start gap-4 mb-4">
|
||||||
<img
|
<img
|
||||||
src={profile.image}
|
src={profile.photo || 'https://via.placeholder.com/150'}
|
||||||
alt={profile.name}
|
alt={profile.name}
|
||||||
className="w-16 h-20 rounded-lg object-cover flex-shrink-0"
|
className="w-16 h-20 rounded-lg object-cover flex-shrink-0"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-bold text-gray-900">{profile.name}</h3>
|
<h3 className="text-lg font-bold text-gray-900">{profile.name}</h3>
|
||||||
<p className="text-sm text-gray-500">ID : {profile.id}</p>
|
<p className="text-sm text-gray-500">ID : {profile.member_id}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t pt-4">
|
<div className="border-t pt-4">
|
||||||
<h4 className="font-bold text-gray-900 mb-3">Reason For Report</h4>
|
<h4 className="font-bold text-gray-900 mb-3">Reason For Report</h4>
|
||||||
<p className="text-sm text-gray-600 leading-relaxed bg-gray-50 p-3 rounded-lg mb-4">
|
<p className="text-sm text-gray-600 leading-relaxed bg-gray-50 p-3 rounded-lg mb-4">
|
||||||
{profile.reportReason}
|
{profile.reason}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full flex justify-center'>
|
<div className='w-full flex justify-center'>
|
||||||
@ -134,117 +163,63 @@ const ReportReasonModal = ({ profile, onClose }) => {
|
|||||||
|
|
||||||
function BlockedProfileListPage() {
|
function BlockedProfileListPage() {
|
||||||
const [activeTab, setActiveTab] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
const [selectedReport, setSelectedReport] = useState(null);
|
const [selectedReport, setSelectedReport] = useState(null);
|
||||||
const blockedProfiles = [
|
const [blockedProfiles, setBlockedProfiles] = useState([]);
|
||||||
{
|
const [reportedProfiles, setReportedProfiles] = useState([]);
|
||||||
id: 'M6075010',
|
const [loading, setLoading] = useState(true);
|
||||||
name: 'Aravindh Vinayak M',
|
|
||||||
age: 37,
|
|
||||||
height: "5'6\"",
|
|
||||||
language: 'Tamil',
|
|
||||||
location: 'Karuneegar',
|
|
||||||
education: 'BE',
|
|
||||||
occupation: 'Clerk',
|
|
||||||
income: '9 - 10 Lakhs',
|
|
||||||
state: 'Tamil Nadu',
|
|
||||||
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=300&h=300&fit=crop'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'M6075010',
|
|
||||||
name: 'Aravindh Vinayak M',
|
|
||||||
age: 37,
|
|
||||||
height: "5'6\"",
|
|
||||||
language: 'Tamil',
|
|
||||||
location: 'Karuneegar',
|
|
||||||
education: 'BE',
|
|
||||||
occupation: 'Clerk',
|
|
||||||
income: '9 - 10 Lakhs',
|
|
||||||
state: 'Tamil Nadu',
|
|
||||||
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=300&h=300&fit=crop'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'M6075010',
|
|
||||||
name: 'Aravindh Vinayak M',
|
|
||||||
age: 37,
|
|
||||||
height: "5'6\"",
|
|
||||||
language: 'Tamil',
|
|
||||||
location: 'Karuneegar',
|
|
||||||
education: 'BE',
|
|
||||||
occupation: 'Clerk',
|
|
||||||
income: '9 - 10 Lakhs',
|
|
||||||
state: 'Tamil Nadu',
|
|
||||||
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=300&h=300&fit=crop'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'M6075010',
|
|
||||||
name: 'Aravindh Vinayak M',
|
|
||||||
age: 37,
|
|
||||||
height: "5'6\"",
|
|
||||||
language: 'Tamil',
|
|
||||||
location: 'Karuneegar',
|
|
||||||
education: 'BE',
|
|
||||||
occupation: 'Clerk',
|
|
||||||
income: '9 - 10 Lakhs',
|
|
||||||
state: 'Tamil Nadu',
|
|
||||||
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=300&h=300&fit=crop'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const reportedProfiles = [
|
useEffect(() => {
|
||||||
{
|
fetchData();
|
||||||
id: 'TK52586A',
|
}, []);
|
||||||
name: 'Pavilash . P',
|
|
||||||
age: 23,
|
const fetchData = async () => {
|
||||||
lastSeen: 'Nov 25',
|
setLoading(true);
|
||||||
caste: 'Agamudayar / Arcot / Thuluva vellala',
|
try {
|
||||||
occupation: 'Engineer-non – IT',
|
const [blockedRes, reportedRes] = await Promise.all([
|
||||||
location: 'Chennai',
|
getBlockedProfiles(),
|
||||||
image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=300&h=400&fit=crop',
|
getReportedProfiles()
|
||||||
showReason: true,
|
]);
|
||||||
reportReason: 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.'
|
|
||||||
},
|
if (blockedRes.status === "success") {
|
||||||
{
|
setBlockedProfiles(blockedRes.data);
|
||||||
id: 'TK52586A',
|
}
|
||||||
name: 'Pavilash . P',
|
if (reportedRes.status === "success") {
|
||||||
age: 23,
|
setReportedProfiles(reportedRes.data);
|
||||||
lastSeen: 'Nov 25',
|
}
|
||||||
caste: 'Agamudayar / Arcot / Thuluva vellala',
|
} catch (error) {
|
||||||
occupation: 'Engineer-non – IT',
|
console.error("Error fetching data:", error);
|
||||||
location: 'Chennai',
|
toast.error("Failed to load profiles");
|
||||||
image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=300&h=400&fit=crop',
|
} finally {
|
||||||
showReason: true,
|
setLoading(false);
|
||||||
reportReason: 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'TK52586A',
|
|
||||||
name: 'Pavilash . P',
|
|
||||||
age: 23,
|
|
||||||
lastSeen: 'Nov 25',
|
|
||||||
caste: 'Agamudayar / Arcot / Thuluva vellala',
|
|
||||||
occupation: 'Engineer-non – IT',
|
|
||||||
location: 'Chennai',
|
|
||||||
image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=300&h=400&fit=crop',
|
|
||||||
showReason: true,
|
|
||||||
reportReason: 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'TK52586A',
|
|
||||||
name: 'Pavilash . P',
|
|
||||||
age: 23,
|
|
||||||
lastSeen: 'Nov 25',
|
|
||||||
caste: 'Agamudayar / Arcot / Thuluva vellala',
|
|
||||||
occupation: 'Engineer-non – IT',
|
|
||||||
location: 'Chennai',
|
|
||||||
image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=300&h=400&fit=crop',
|
|
||||||
showReason: true,
|
|
||||||
reportReason: 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.'
|
|
||||||
}
|
}
|
||||||
];
|
};
|
||||||
|
|
||||||
|
const handleUnblock = async (profileId) => {
|
||||||
|
try {
|
||||||
|
const res = await unblockProfile(profileId);
|
||||||
|
if (res.status === "success") {
|
||||||
|
toast.success(res.message || "Profile unblocked successfully");
|
||||||
|
setBlockedProfiles(prev => prev.filter(p => p.id !== profileId));
|
||||||
|
} else {
|
||||||
|
toast.error(res.message || "Failed to unblock profile");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("Something went wrong");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleTabChange = (event, newValue) => {
|
const handleTabChange = (event, newValue) => {
|
||||||
setActiveTab(newValue);
|
setActiveTab(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '60vh' }}>
|
||||||
|
<CircularProgress color="error" />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className=" py-4 md:py-8">
|
<div className=" py-4 md:py-8">
|
||||||
<div className="max-w-[1400px] mx-auto">
|
<div className="max-w-[1400px] mx-auto">
|
||||||
@ -259,14 +234,14 @@ function BlockedProfileListPage() {
|
|||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
minWidth: 120,
|
minWidth: 150,
|
||||||
},
|
},
|
||||||
'& .Mui-selected': {
|
'& .Mui-selected': {
|
||||||
color: '#fff !important',
|
color: '#fff !important',
|
||||||
background:"#A70710"
|
background:"#A70710"
|
||||||
},
|
},
|
||||||
'& .MuiTabs-indicator': {
|
'& .MuiTabs-indicator': {
|
||||||
backgroundColor: '#A70710',
|
backgroundColor: 'transparent',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -277,28 +252,32 @@ function BlockedProfileListPage() {
|
|||||||
|
|
||||||
<div className="transition-all duration-300">
|
<div className="transition-all duration-300">
|
||||||
{activeTab === 0 && (
|
{activeTab === 0 && (
|
||||||
<div className='w-[100%] max-w-[1400px] mx-auto grid grid-cols-1 md:grid-cols-2 gap-2'>
|
<div className='w-[100%] max-w-[1400px] mx-auto grid grid-cols-1 md:grid-cols-2 gap-4 px-4'>
|
||||||
{blockedProfiles.map((profile, index) => (
|
{blockedProfiles.length > 0 ? (
|
||||||
<BlockedProfile key={index} profile={profile} />
|
blockedProfiles.map((profile, index) => (
|
||||||
))}
|
<BlockedProfile key={profile.id || index} profile={profile} onUnblock={handleUnblock} />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="col-span-full text-center py-10 text-gray-500">No blocked profiles found.</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{activeTab === 1 && (
|
{activeTab === 1 && (
|
||||||
<div className='w-[100%] max-w-[1400px] mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 gap-2'>
|
<div className='w-[100%] max-w-[1400px] mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 gap-4 px-4'>
|
||||||
{reportedProfiles.map((profile, index) => (
|
{reportedProfiles.length > 0 ? (
|
||||||
<ReportedProfile
|
reportedProfiles.map((profile, index) => (
|
||||||
key={index}
|
<ReportedProfile
|
||||||
profile={profile}
|
key={profile.id || index}
|
||||||
onViewReason={setSelectedReport}
|
profile={profile}
|
||||||
/>
|
onViewReason={setSelectedReport}
|
||||||
))}
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="col-span-full text-center py-10 text-gray-500">No reported profiles found.</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/* Report Reason Modal */}
|
{/* Report Reason Modal */}
|
||||||
<ReportReasonModal
|
<ReportReasonModal
|
||||||
@ -307,7 +286,7 @@ function BlockedProfileListPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style jsx>{`
|
<style>{`
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,58 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import MatrimonyProfile from "../components/profiledetail/MatrimonyProfile"
|
import MatrimonyProfile from "../components/profiledetail/MatrimonyProfile"
|
||||||
import PartnerPreferences from "../components/profiledetail/PartnerPreferences"
|
import PartnerPreferences from "../components/profiledetail/PartnerPreferences"
|
||||||
import MatchingList from "../components/profiledashboard/MatchingList";
|
import MatchingList from "../components/profiledashboard/MatchingList";
|
||||||
|
import { getProfileDetail } from "../services/profileActionApi";
|
||||||
|
import { CircularProgress, Box } from "@mui/material";
|
||||||
|
|
||||||
const ProfileDetailPage = () => {
|
const ProfileDetailPage = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const [data, setData] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchDetail = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const res = await getProfileDetail(id);
|
||||||
|
setData(res);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch profile details:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (id) {
|
||||||
|
fetchDetail();
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh' }}>
|
||||||
|
<CircularProgress color="error" />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<div className="text-center py-20 text-gray-500 text-xl">
|
||||||
|
Profile details not found.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-[100%] max-w-[1400px] mx-auto my-10">
|
<div className="w-[100%] max-w-[1400px] mx-auto my-10">
|
||||||
<MatrimonyProfile/>
|
<MatrimonyProfile data={data} />
|
||||||
<PartnerPreferences/>
|
<PartnerPreferences data={data} />
|
||||||
<MatchingList/>
|
<MatchingList matches={data.all_matches} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ProfileDetailPage
|
export default ProfileDetailPage;
|
||||||
@ -74,6 +74,13 @@ const LoginPage = () => {
|
|||||||
localStorage.setItem("access_token", token);
|
localStorage.setItem("access_token", token);
|
||||||
setAccessToken(token);
|
setAccessToken(token);
|
||||||
|
|
||||||
|
// Store profile_id and user_id for WebSocket channels
|
||||||
|
const profileId = data?.profile_id || data?.data?.profile_id;
|
||||||
|
const userId = data?.user_id || data?.data?.user_id;
|
||||||
|
|
||||||
|
if (profileId) localStorage.setItem("profile_id", profileId);
|
||||||
|
if (userId) localStorage.setItem("user_id", userId);
|
||||||
|
|
||||||
toast.success("Login Successful!");
|
toast.success("Login Successful!");
|
||||||
navigate("/dashboard-home");
|
navigate("/dashboard-home");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -5,49 +5,72 @@ const registrationformSlice = createSlice({
|
|||||||
initialState: {
|
initialState: {
|
||||||
personalDetails: {
|
personalDetails: {
|
||||||
name: "",
|
name: "",
|
||||||
mobileNumber: "",
|
mobile: "",
|
||||||
|
email: "",
|
||||||
gender: "",
|
gender: "",
|
||||||
dob: "",
|
|
||||||
height: "",
|
height: "",
|
||||||
weight: "",
|
weight: "",
|
||||||
maritalStatus: "",
|
marital_status: "",
|
||||||
religion: "",
|
religion: 1, // Default Hindu
|
||||||
profileFor: "",
|
profile_for: "",
|
||||||
caste: "",
|
caste: 1, // Default Naidu
|
||||||
subCaste: "",
|
sub_caste: "",
|
||||||
|
willing_to_marry: "",
|
||||||
|
inter_caste_parents: "",
|
||||||
|
inter_caste_parents_details: "",
|
||||||
gothram: "",
|
gothram: "",
|
||||||
raasi: "",
|
do_you_speak_telugu: "",
|
||||||
star: "",
|
about_us: "",
|
||||||
bloodGroup: "",
|
known_languages: [],
|
||||||
email: "",
|
mother_language: "",
|
||||||
|
complexion: "",
|
||||||
|
physical_status: "",
|
||||||
password: "",
|
password: "",
|
||||||
confirmPassword: "",
|
confirmPassword: "",
|
||||||
|
dob: "",
|
||||||
|
raasi: "",
|
||||||
|
star: "",
|
||||||
state: "",
|
state: "",
|
||||||
city: "",
|
city: "",
|
||||||
pincode: "",
|
pincode: "",
|
||||||
profiles: [],
|
profiles: [],
|
||||||
|
verifiedMobileNumber: "",
|
||||||
},
|
},
|
||||||
educationalDetails: {
|
educationalDetails: {
|
||||||
collegeName: "",
|
study_field: "",
|
||||||
employeeType: "",
|
education: "",
|
||||||
qualification: "",
|
education_detail: "",
|
||||||
fieldOfStudy: "",
|
college_name: "",
|
||||||
|
employee_type: "",
|
||||||
occupation: "",
|
occupation: "",
|
||||||
organization: "",
|
occupation_detail: "",
|
||||||
income: "",
|
company_name: "",
|
||||||
workLocation: "",
|
income_currency: "INR",
|
||||||
|
annual_income: "",
|
||||||
|
work_country: 1,
|
||||||
|
work_city: "",
|
||||||
|
work_state: "",
|
||||||
|
work_district: "",
|
||||||
|
address: "",
|
||||||
},
|
},
|
||||||
familyDetails: {
|
familyDetails: {
|
||||||
fatherName: "",
|
fatherName: "",
|
||||||
fatherOccupation: "",
|
fatherOccupation: "",
|
||||||
motherName: "",
|
motherName: "",
|
||||||
motherOccupation: "",
|
motherOccupation: "",
|
||||||
brotherCount: 0,
|
brotherCount: "",
|
||||||
sisterCount: 0,
|
sisterCount: "",
|
||||||
brothers: [],
|
brothers: [],
|
||||||
sisters: [],
|
sisters: [],
|
||||||
familyStatus: "",
|
familyStatus: "",
|
||||||
nativePlace: "",
|
nativePlace: "",
|
||||||
|
familyCountry: "",
|
||||||
|
familyState: "",
|
||||||
|
familyDistrict: "",
|
||||||
|
familyCity: "",
|
||||||
|
address: "",
|
||||||
|
expectationDetails: "",
|
||||||
|
willingToGoAbroad: "",
|
||||||
},
|
},
|
||||||
lifestyleDetails: {
|
lifestyleDetails: {
|
||||||
diets: [],
|
diets: [],
|
||||||
@ -114,14 +137,38 @@ const registrationformSlice = createSlice({
|
|||||||
state.partnerPreferences = { ...state.partnerPreferences, ...action.payload };
|
state.partnerPreferences = { ...state.partnerPreferences, ...action.payload };
|
||||||
},
|
},
|
||||||
|
|
||||||
submitForm: (state) => {
|
clearAllStepsFrom: (state, action) => {
|
||||||
console.log("Form Submitted:", {
|
const step = action.payload;
|
||||||
personalDetails: state.personalDetails,
|
if (step <= 2) {
|
||||||
educationalDetails: state.educationalDetails,
|
state.educationalDetails = {
|
||||||
familyDetails: state.familyDetails,
|
study_field: "", education: "", education_detail: "", college_name: "",
|
||||||
lifestyleDetails: state.lifestyleDetails,
|
employee_type: "", occupation: "", occupation_detail: "", company_name: "",
|
||||||
partnerPreferences: state.partnerPreferences,
|
income_currency: "INR", annual_income: "", work_country: "", work_state: "",
|
||||||
});
|
work_district: "", work_city: "", address: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (step <= 3) {
|
||||||
|
state.familyDetails = {
|
||||||
|
fatherName: "", fatherOccupation: "", motherName: "", motherOccupation: "",
|
||||||
|
brotherCount: "", sisterCount: "", brothers: [], sisters: [],
|
||||||
|
familyStatus: "", nativePlace: "", familyCountry: "", familyState: "",
|
||||||
|
familyDistrict: "", familyCity: "", address: "", expectationDetails: "",
|
||||||
|
willingToGoAbroad: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (step <= 4) {
|
||||||
|
state.lifestyleDetails = {
|
||||||
|
diets: "", hobbies: [], dob: "", tob: "", placeOfBirth: "",
|
||||||
|
graha: { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [] },
|
||||||
|
amsam: { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [] },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (step <= 5) {
|
||||||
|
state.partnerPreferences = {
|
||||||
|
ageRange: "", castes: [], subCastes: [], occupations: [], educations: [],
|
||||||
|
hobbies: [], annualIncome: "", states: [], districts: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -279,6 +326,7 @@ export const {
|
|||||||
updateFamilyDetails,
|
updateFamilyDetails,
|
||||||
updateLifestyleDetails,
|
updateLifestyleDetails,
|
||||||
updatePartnerPreferences,
|
updatePartnerPreferences,
|
||||||
|
clearAllStepsFrom,
|
||||||
submitForm,
|
submitForm,
|
||||||
preloadDummyProfile,
|
preloadDummyProfile,
|
||||||
} = registrationformSlice.actions;
|
} = registrationformSlice.actions;
|
||||||
|
|||||||
34
src/services/chatApi.js
Normal file
34
src/services/chatApi.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import axiosInstance from "../api/axiosInstance";
|
||||||
|
import { API_ENDPOINTS } from "../api/apiEndpoints";
|
||||||
|
|
||||||
|
export const getChatList = async (searchValue = "") => {
|
||||||
|
try {
|
||||||
|
// Add timestamp to prevent caching
|
||||||
|
const response = await axiosInstance.get(`${API_ENDPOINTS.CHAT_LIST}?search_value=${searchValue}&_t=${Date.now()}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching chat list:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getChatMessages = async (chatId, page = 1) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get(`${API_ENDPOINTS.CHAT_MESSAGES(chatId)}?page=${page}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching chat messages:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sendMessage = async (chatId, message) => {
|
||||||
|
try {
|
||||||
|
// Correct endpoint based on user request: chat/message/send?chat_id={id}&message={text}
|
||||||
|
const response = await axiosInstance.post(`chat/message/send?chat_id=${chatId}&message=${encodeURIComponent(message)}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending message:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
65
src/services/profileActionApi.js
Normal file
65
src/services/profileActionApi.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import axiosInstance from "../api/axiosInstance";
|
||||||
|
import { API_ENDPOINTS } from "../api/apiEndpoints";
|
||||||
|
|
||||||
|
export const getBlockedProfiles = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get(API_ENDPOINTS.BLOCK_PROFILE_LIST);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching blocked profiles:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getReportedProfiles = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get(API_ENDPOINTS.REPORT_PROFILE_LIST);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching reported profiles:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const unblockProfile = async (profileId) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.post(`unblock_profile?profile_id=${profileId}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error unblocking profile:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProfileDetail = async (profile_id) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get(`${API_ENDPOINTS.PROFILE_DETAIL}?profile_id=${profile_id}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching profile detail:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInterestList = async (tab, type) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get(`${API_ENDPOINTS.INTEREST_LIST}?tab=${tab}&type=${type}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching interest list:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateInterestStatus = async (profile_id, status) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.post(API_ENDPOINTS.UPDATE_INTEREST_STATUS, {
|
||||||
|
profile_id,
|
||||||
|
status
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating interest status:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -10,7 +10,9 @@ export const shortlistProfile = async (profileId) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const sendInterest = async (profileId) => {
|
export const sendInterest = async (profileId) => {
|
||||||
const response = await axiosInstance.post(`interest?profile_id=${profileId}`);
|
const response = await axiosInstance.post(`interest_send`, {
|
||||||
|
profile_id: profileId // ✅ sent in request body
|
||||||
|
});
|
||||||
if (response.data?.status === "error") {
|
if (response.data?.status === "error") {
|
||||||
throw new Error(response.data.message || "Failed to send interest");
|
throw new Error(response.data.message || "Failed to send interest");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user