From 68f97c40dcea584060eb90a3b7f3922d5234f6bb Mon Sep 17 00:00:00 2001 From: Meenadeveloper Date: Sat, 14 Mar 2026 17:07:39 +0530 Subject: [PATCH] matrimony --- src/api/preview.api.js | 6 + src/assets/images/kiridam.png | Bin 0 -> 569 bytes src/components/common/ProfileHeader.jsx | 10 +- src/components/matches/MatchesProfilesTab.jsx | 3 +- .../profiledashboard/MatchingList.jsx | 394 +++++++---------- .../profiledashboard/MatrimonyArticles.jsx | 89 +--- .../profiledashboard/MembershipCard.jsx | 70 ++- .../profiledashboard/NewJoinedProfile.jsx | 399 +++++++---------- .../profiledashboard/ProfileCompletion.jsx | 4 +- .../profiledashboard/VideoSwiperGallery.jsx | 175 ++------ src/components/ui/ProfileCardDemo.jsx | 401 ++++++++++++------ src/pages/UserDashboardHome.jsx | 9 +- src/services/shortlistapi.js | 26 ++ 13 files changed, 700 insertions(+), 886 deletions(-) create mode 100644 src/assets/images/kiridam.png create mode 100644 src/services/shortlistapi.js diff --git a/src/api/preview.api.js b/src/api/preview.api.js index 64c71b9..9c5e2ba 100644 --- a/src/api/preview.api.js +++ b/src/api/preview.api.js @@ -5,3 +5,9 @@ export const getPreviewDetails = async () => { const res = await axiosInstance.get(API_ENDPOINTS.PREVIEW_DETAILS); return res.data; }; + + +export const getHeaderDetails = async () => { + const res = await axiosInstance.get(API_ENDPOINTS.HEADER_API); + return res.data; +} \ No newline at end of file diff --git a/src/assets/images/kiridam.png b/src/assets/images/kiridam.png new file mode 100644 index 0000000000000000000000000000000000000000..0cfad9f964340588c41901cd4ae03029a2d9d454 GIT binary patch literal 569 zcmV-90>=G`P)DyTJ7w7-oE{eKn`RR4lL9m zu}w=`InjflA#o?p;F~pKg5Zh@M`(|Wr=vxL4I&IOMDh|<3brsi0?MywG7%reChHCJ zBftPV!b51qx}GvAyT@uU)*RrdokwJ23FmBBq{fB5lNGw#g`!IN@DqC&0$=^4obwX6 z(nHZAHTz@N-Zij(pll{7m1A{vU@<0Lwv{@)iA0f9xlH7YiS8?^n0H*IQKHa>3v9ZI zK$CDDtJIL#67qtkG*}TQ{{*U#3wU>)2cbIhLk$M}g6WA8xrj;h5%tXD`4)L#q5$a+ z$Rv*^^it()HpjkuS-(V|iMllEMnK(*iI)~~Ve!! { + const { data: headerData } = useQuery({ + queryKey: ["headerDetails"], + queryFn: getHeaderDetails, + enabled: !!auth, + }); + const apiProfileImage = headerData?.myDetails?.profile; + const handleMenuClick = (item) => { if (item.action === "delete") { setDeleteModalOpen(true); @@ -381,7 +389,7 @@ const ProfileHeader = () => { - + diff --git a/src/components/matches/MatchesProfilesTab.jsx b/src/components/matches/MatchesProfilesTab.jsx index 7b42494..90d8065 100644 --- a/src/components/matches/MatchesProfilesTab.jsx +++ b/src/components/matches/MatchesProfilesTab.jsx @@ -34,6 +34,7 @@ export default function MatchesInterface() { const filterType = filters.filter_type; const selectedTab = filterType || "all_matches"; const isPaidMember = filters.isPaidMember; + const { ref, inView } = useInView({ threshold: 0, rootMargin: "300px" @@ -167,7 +168,7 @@ useEffect(() => {
diff --git a/src/components/profiledashboard/MatchingList.jsx b/src/components/profiledashboard/MatchingList.jsx index dc296d0..9f1514a 100644 --- a/src/components/profiledashboard/MatchingList.jsx +++ b/src/components/profiledashboard/MatchingList.jsx @@ -1,4 +1,4 @@ -import { useRef, useState } from "react"; +import { useRef, useState, useEffect } from "react"; import { motion } from "framer-motion"; import { Swiper, SwiperSlide } from "swiper/react"; import { @@ -10,141 +10,84 @@ import { import { Crown, Bookmark, - User, - Briefcase, - MapPin, X, - Send, ChevronLeft, ChevronRight, + Heart, + Eye, } from "lucide-react"; -import CakeIcon from "@mui/icons-material/Cake"; -import HeightIcon from "@mui/icons-material/Height"; -import GroupsIcon from "@mui/icons-material/Groups"; -import TempleHinduIcon from "@mui/icons-material/TempleHindu"; -import SchoolIcon from "@mui/icons-material/School"; -import LocationOnIcon from "@mui/icons-material/LocationOn"; -import AccessibilityNewIcon from "@mui/icons-material/AccessibilityNew"; -import AccountBalanceWalletIcon from "@mui/icons-material/AccountBalanceWallet"; -import profilebg from "../../assets/images/profilebg.jpg"; -import Image from "../../assets/images/astrology-horoscope-svgrepo-com.svg"; -import Image1 from "../../assets/images/scorpio-svgrepo-com.svg"; // Import Swiper styles import "swiper/css"; import "swiper/css/navigation"; import "swiper/css/pagination"; import "swiper/css/effect-coverflow"; import { useNavigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { updateFilter } from "../../redux/filterSlice"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import toast from "react-hot-toast"; +import { shortlistProfile, sendInterest, declineProfile } from "../../services/shortlistapi"; -const MatchingList = () => { - const swiperRef = useRef(null); - const navigate = useNavigate(); - - // Sample profile data - const profiles = [ - { - id: 1, - name: "Selva Kumar . R", - userId: "TK52586A", - lastSeen: "14 Nov 25", - age: 23, - height: "5'2\"", - salary: "5-10 LPA", - location: "chennai", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: - "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=500&fit=crop", - isPremium: true, - }, - { - id: 2, - name: "Priya Sharma", - userId: "TK52587B", - lastSeen: "15 Nov 25", - age: 25, - height: "5'4\"", - salary: "8-12 LPA", - location: "hyderabad", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: - "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=500&fit=crop", - isPremium: true, - }, - { - id: 3, - name: "Rahul Venkat", - userId: "TK52588C", - lastSeen: "16 Nov 25", - age: 28, - height: "5'10\"", - salary: "6-11 LPA", - location: "Mumbai", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: - "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&h=500&fit=crop", - isPremium: false, - }, - { - id: 4, - name: "Aishwarya Reddy", - userId: "TK52589D", - lastSeen: "17 Nov 25", - age: 26, - height: "5'5\"", - salary: "7-11 LPA", - location: "Bangalore", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: - "https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=400&h=500&fit=crop", - isPremium: true, - }, - { - id: 5, - name: "Karthik Mohan", - userId: "TK52590E", - lastSeen: "18 Nov 25", - age: 27, - height: "5'8\"", - salary: "9-14 LPA", - location: "kerala", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: - "https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=400&h=500&fit=crop", - isPremium: false, - }, - { - id: 6, - name: "Divya Lakshmi", - userId: "TK52591F", - lastSeen: "19 Nov 25", - age: 24, - height: "5'3\"", - salary: "5-10 LPA", - location: "madya pradesh", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: - "https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=400&h=500&fit=crop", - isPremium: true, - }, - ]; - - // Profile Card Component - - const ProfileCard = ({ profile }) => { - const [isLiked, setIsLiked] = useState(false); +const ProfileCard = ({ profile }) => { const navigate = useNavigate(); + const queryClient = useQueryClient(); + const [isShortlisted, setIsShortlisted] = useState(profile?.is_shortlisted === 1); + + useEffect(() => { + setIsShortlisted(profile?.is_shortlisted === 1); + }, [profile?.is_shortlisted]); + + const shortlistMutation = useMutation({ + mutationFn: shortlistProfile, + onMutate: () => { + setIsShortlisted((prev) => !prev); + }, + onSuccess: (data) => { + toast.success(data.message || "Profile shortlisted successfully."); + // Invalidating queries will refetch data and update all profile cards simultaneously + queryClient.invalidateQueries(); + }, + onError: (error) => { + setIsShortlisted(profile?.is_shortlisted === 1); + toast.error(error.message || "Failed to update shortlist status."); + } + }); + + const interestMutation = useMutation({ + mutationFn: sendInterest, + onSuccess: (data) => { + toast.success(data.message || "Interest sent successfully."); + queryClient.invalidateQueries(); + }, + onError: (error) => { + toast.error(error.message || "Failed to send interest."); + } + }); + + const declineMutation = useMutation({ + mutationFn: declineProfile, + onSuccess: (data) => { + toast.success(data.message || "Profile declined."); + queryClient.invalidateQueries(); + }, + onError: (error) => { + toast.error(error.message || "Failed to decline profile."); + } + }); + + const id = profile.id; + const image = profile.photo || profile.image; + const name = profile.name || "Unknown"; + const idNumber = profile.member_id || profile.userId || "N/A"; + const lastSeen = profile.last_seen_at || profile.lastSeen || "Recently"; + const age = profile.age ? `${profile.age} yrs` : null; + const height = profile.height || null; + const salary = profile.annual_income_name || profile.salary || null; + const location = profile.district_name || profile.location || null; + const caste = profile.caste_name || profile.caste || null; + const zodiac1 = profile.raasi_name || profile.zodiac1 || null; + const zodiac2 = profile.star_name || profile.zodiac2 || null; + const isPremium = profile.is_paid_member !== undefined ? profile.is_paid_member === 1 : profile.isPremium; return ( { whileInView={{ opacity: 1, scale: 1 }} viewport={{ once: true }} transition={{ duration: 0.5 }} - onClick={() => navigate(`/profile-details/${profile.id}`)} - className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-2 border-gray-200" + onClick={() => navigate(`/profile-details/${id}`)} + className="w-full rounded-[28px] overflow-hidden bg-white shadow-md cursor-pointer" > - {/* Profile Image Section */} + {/* IMAGE SECTION */}
- {/* Premium Badge */} - {profile.isPremium && ( - - - + profile { + e.target.src = "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png"; + }} + /> + + {isPremium && ( +
+ +
)} - {/* Shortlist Button */} - { e.stopPropagation(); - // shortlist logic + if (!shortlistMutation.isPending) { + shortlistMutation.mutate(id); + } }} > - - Shortlist - - -
- {profile.name} -
- {/* */} - - {/* White Gradient Overlay at bottom of image */} -
- - {/* Profile Info Overlay - positioned at bottom */} -
-

- {profile.name} -

-

- Matrimony ID: {profile.userId} -

+ + {shortlistMutation.isPending ? "..." : "Shortlist"}
- {/* Stats and Follow Section */} -
-
-
- - - Age : {profile.age} - -
+ {/* CONTENT */} +
+

+ {name} +

-
- - - Height: {profile.height} - -
- - +
+

ID: {idNumber}

+

+ {lastSeen} +

-
-
- - - {profile.salary} - -
-
- - - {profile.location} - -
+
+ {[ + age, + height, + salary, + location, + caste, + zodiac1, + zodiac2, + ] + .filter(Boolean) + .map((v, i) => ( + + {v} + + ))}
-
-
- - - {profile.caste} - -
-
- - - {profile.zodiac1} - -
-
-
-
- - - {profile.zodiac2} - -
+
+ + +
); }; +const MatchingList = ({ matches }) => { + const swiperRef = useRef(null); + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const displayProfiles = matches || []; + if (displayProfiles.length === 0) return null; + return ( <>
{ }} className="pb-16" > - {profiles.map((profile) => ( - + {displayProfiles.map((profile, index) => ( + ))} @@ -383,7 +296,10 @@ const MatchingList = () => { whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} className="px-6 py-3 bg-[#034E08] text-white rounded-full font-semibold text-lg shadow-lg hover:shadow-xl transition-shadow" - onClick={() => navigate("/matches")} + onClick={() => { + dispatch(updateFilter({ filter_type: "all_matches" })); + navigate("/matches", { state: { activeTab: "allmatches", filter_type: "all_matches" } }); + }} > View All Matches diff --git a/src/components/profiledashboard/MatrimonyArticles.jsx b/src/components/profiledashboard/MatrimonyArticles.jsx index 074cd73..bdf7ce2 100644 --- a/src/components/profiledashboard/MatrimonyArticles.jsx +++ b/src/components/profiledashboard/MatrimonyArticles.jsx @@ -5,48 +5,13 @@ import "swiper/css/navigation"; import { motion } from 'framer-motion'; import { Crown, Bookmark, User, Briefcase, MapPin, X, Send, ChevronLeft, ChevronRight } from 'lucide-react'; import { useRef } from "react"; -import LazyImage from "../common/LazyImage"; -import weddingImg1 from "../../assets/images/wedding6.jpeg"; -import weddingImg2 from "../../assets/images/wedding8.jpg"; -import weddingImg3 from "../../assets/images/wedding7.jpg"; - - -const articleData = [ - { - title: "Marriage is not just finding the right partner, it's creating a lifetime of moments together Find someone who understands your heart and walks with you in every season.", - img: weddingImg1, - - }, - { - title: "Top 10 Qualities for a Happy Marriage, A perfect match begins with trust, respect, and shared dreams", - img: weddingImg2 - }, - - { - title: "Expert Tips for a Strong Relationship, A perfect match begins with trust, respect, and shared dreams", - img: weddingImg3 - }, - { - title: "How to Build Trust in Marriage, A perfect match begins with trust, respect, and shared dreams", - img: weddingImg1 - }, - { - title: "Communication Secrets for Couples, A perfect match begins with trust, respect, and shared dreams,A perfect match begins with trust, respect, and shared dreams.A perfect match begins with trust, respect, and shared dreams.A perfect match begins with trust, respect, and shared dreams,Real relationships are built on honesty, compassion, and understanding.,Real relationships are built on honesty, compassion, and understanding.", - img: weddingImg1 - } -]; - -const twoLineStyle = { - display: '-webkit-box', - WebkitBoxOrient: 'vertical', - WebkitLineClamp: 2, - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'normal' -}; -const MatrimonyArticles = () => { +const MatrimonyArticles = ({ articles }) => { const swiperRef = useRef(null); + const displayArticles = articles || []; + + if (displayArticles.length === 0) return null; + return ( <>
@@ -70,51 +35,19 @@ const MatrimonyArticles = () => { loop={true} className="mySwiper" > - {articleData.map((item, index) => ( - + {displayArticles.map((item) => ( +
-
+
{item.title}
- {/* */} - - {/* White Gradient Overlay at bottom of image */} - - - {/* Profile Info Overlay - positioned at bottom */} -
- -
- -
-
-

{item.title}

-
-
diff --git a/src/components/profiledashboard/MembershipCard.jsx b/src/components/profiledashboard/MembershipCard.jsx index cb85686..6fc97bb 100644 --- a/src/components/profiledashboard/MembershipCard.jsx +++ b/src/components/profiledashboard/MembershipCard.jsx @@ -1,7 +1,19 @@ import { Phone, MessageCircle, ThumbsUp, Eye } from 'lucide-react'; import promogirl from "../../assets/images/mobile.png" -const MembershipCard = ()=>{ +import { useNavigate } from 'react-router-dom'; + +const MembershipCard = ({ becomePaidMember })=>{ + const navigate = useNavigate(); + + const offerPercentage = becomePaidMember?.offer_percentage + ? parseInt(becomePaidMember.offer_percentage) + : 58; + + const points = becomePaidMember?.points || []; + + const icons = [Phone, MessageCircle, Eye, ThumbsUp]; + return ( <> @@ -19,50 +31,31 @@ return ( {/* Subheading with offer */}

- Get up to 58% OFF on paid membership! + Get up to {offerPercentage}% OFF on paid membership!

{/* Features List */}
-
-
- -
-

- Call/WhatsApp matches -

-
- -
-
- -
-

- Unlimited messages -

-
- -
-
- -
-

- Higher chances of response -

-
- -
-
- -
-

- View and match horoscopes -

-
+ {points.map((point, index) => { + const Icon = icons[index % icons.length]; + return ( +
+
+ +
+

+ {point} +

+
+ ); + })}
{/* CTA Button */} -
@@ -86,4 +79,3 @@ return ( ); }; export default MembershipCard - diff --git a/src/components/profiledashboard/NewJoinedProfile.jsx b/src/components/profiledashboard/NewJoinedProfile.jsx index 0ee680c..125ce8d 100644 --- a/src/components/profiledashboard/NewJoinedProfile.jsx +++ b/src/components/profiledashboard/NewJoinedProfile.jsx @@ -1,116 +1,96 @@ -import { useRef, useState } from 'react'; +import { useRef, useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { Swiper, SwiperSlide } from 'swiper/react'; import { Navigation, Pagination, Autoplay, EffectCoverflow } from 'swiper/modules'; -import { Crown, Bookmark, User, Briefcase, MapPin, X, Send, ChevronLeft, ChevronRight } from 'lucide-react'; -import CakeIcon from "@mui/icons-material/Cake"; -import HeightIcon from "@mui/icons-material/Height"; -import GroupsIcon from "@mui/icons-material/Groups"; -import TempleHinduIcon from "@mui/icons-material/TempleHindu"; -import SchoolIcon from "@mui/icons-material/School"; -import LocationOnIcon from "@mui/icons-material/LocationOn"; -import AccessibilityNewIcon from "@mui/icons-material/AccessibilityNew"; -import profilebg from "../../assets/images/profilebg.jpg"; +import { + Crown, + Bookmark, + X, + ChevronLeft, + ChevronRight, + Heart, + Eye, +} from 'lucide-react'; // Import Swiper styles import 'swiper/css'; import 'swiper/css/navigation'; import 'swiper/css/pagination'; import 'swiper/css/effect-coverflow'; import { useNavigate } from 'react-router-dom'; - -const NewJoinedProfile = () => { - - - const swiperRef = useRef(null); - const navigate = useNavigate(); - - // Sample profile data - const profiles = [ - { - id: 1, - name: 'Selva Kumar . R', - userId: 'TK52586A', - lastSeen: '14 Nov 25', - age: 23, - height: '5\'2"', - religion: 'Hindu / Agamudayar / Thuluva Vellal', - education: 'BCA, Data Analyst', - location: 'Vellore, Tamil Nadu', - image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=500&fit=crop', - isPremium: true - }, - { - id: 2, - name: 'Priya Sharma', - userId: 'TK52587B', - lastSeen: '15 Nov 25', - age: 25, - height: '5\'4"', - religion: 'Hindu / Brahmin / Iyer', - education: 'MBA, Marketing Manager', - location: 'Chennai, Tamil Nadu', - image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=500&fit=crop', - isPremium: true - }, - { - id: 3, - name: 'Rahul Venkat', - userId: 'TK52588C', - lastSeen: '16 Nov 25', - age: 28, - height: '5\'10"', - religion: 'Hindu / Mudaliar / Arcot', - education: 'B.Tech, Software Engineer', - location: 'Bangalore, Karnataka', - image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&h=500&fit=crop', - isPremium: false - }, - { - id: 4, - name: 'Aishwarya Reddy', - userId: 'TK52589D', - lastSeen: '17 Nov 25', - age: 26, - height: '5\'5"', - religion: 'Hindu / Reddy / Telangana', - education: 'CA, Chartered Accountant', - location: 'Hyderabad, Telangana', - image: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=400&h=500&fit=crop', - isPremium: true - }, - { - id: 5, - name: 'Karthik Mohan', - userId: 'TK52590E', - lastSeen: '18 Nov 25', - age: 27, - height: '5\'8"', - religion: 'Hindu / Nadar / Tamil', - education: 'M.Tech, Civil Engineer', - location: 'Madurai, Tamil Nadu', - image: 'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=400&h=500&fit=crop', - isPremium: false - }, - { - id: 6, - name: 'Divya Lakshmi', - userId: 'TK52591F', - lastSeen: '19 Nov 25', - age: 24, - height: '5\'3"', - religion: 'Hindu / Pillai / Tamil', - education: 'B.Com, HR Executive', - location: 'Coimbatore, Tamil Nadu', - image: 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=400&h=500&fit=crop', - isPremium: true - } - ]; - - // Profile Card Component - +import { useDispatch } from 'react-redux'; +import { updateFilter } from "../../redux/filterSlice"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import toast from "react-hot-toast"; +import { shortlistProfile, sendInterest, declineProfile } from "../../services/shortlistapi"; const ProfileCard = ({ profile }) => { - const [isLiked, setIsLiked] = useState(false); + const navigate = useNavigate(); + const queryClient = useQueryClient(); + const [isShortlisted, setIsShortlisted] = useState(profile?.is_shortlisted === 1); + + useEffect(() => { + setIsShortlisted(profile?.is_shortlisted === 1); + }, [profile?.is_shortlisted]); + + const shortlistMutation = useMutation({ + mutationFn: shortlistProfile, + onMutate: () => { + setIsShortlisted((prev) => !prev); + }, + onSuccess: (data) => { + toast.success(data.message || "Profile shortlisted successfully."); + // Invalidating queries will refetch data and update all profile cards simultaneously + queryClient.invalidateQueries(); + }, + onError: (error) => { + setIsShortlisted(profile?.is_shortlisted === 1); + toast.error(error.message || "Failed to update shortlist status."); + } + }); + + const interestMutation = useMutation({ + mutationFn: sendInterest, + onSuccess: (data) => { + toast.success(data.message || "Interest sent successfully."); + queryClient.invalidateQueries(); + }, + onError: (error) => { + toast.error(error.message || "Failed to send interest."); + } + }); + + const declineMutation = useMutation({ + mutationFn: declineProfile, + onSuccess: (data) => { + toast.success(data.message || "Profile declined."); + queryClient.invalidateQueries(); + }, + onError: (error) => { + toast.error(error.message || "Failed to decline profile."); + } + }); + + const id = profile.id; + const image = profile.photo || profile.image; + const name = profile.name || "Unknown"; + const idNumber = profile.member_id || profile.userId || "N/A"; + const lastSeen = profile.last_seen_at || profile.lastSeen || "Recently"; + const age = profile.age ? `${profile.age} yrs` : null; + const height = profile.height || null; + const salary = profile.annual_income_name || profile.salary || null; + const location = profile.district_name || profile.location || null; + const caste = profile.caste_name || profile.caste || null; + const zodiac1 = profile.raasi_name || profile.zodiac1 || null; + const zodiac2 = profile.star_name || profile.zodiac2 || null; + 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 ( { whileInView={{ opacity: 1, scale: 1 }} viewport={{ once: true }} transition={{ duration: 0.5 }} - onClick={() => navigate(`/profile-details/${profile.id}`)} - className="w-full max-w-sm rounded-[10px] shadow-xl overflow-hidden border-1 border-green-200" + onClick={() => navigate(`/profile-details/${id}`)} + className="w-full rounded-[28px] overflow-hidden bg-white shadow-md cursor-pointer" > + {/* IMAGE SECTION */}
- {profile.isPremium && ( - - - + profile { + e.target.src = "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png"; + }} + /> + + {isPremium && ( +
+ +
)} - { e.stopPropagation(); + if (!shortlistMutation.isPending) { + shortlistMutation.mutate(id); + } }} > - - Shortlist - - -
- {profile.name} -
- -
- -
-

- {profile.name} -

-

- Matrimony ID: {profile.userId} -

+ + {shortlistMutation.isPending ? "..." : "Shortlist"}
-
-
-
- - - Age : {profile.age} - -
+ {/* CONTENT */} +
+

+ {name} +

-
- - - Height: {profile.height} - -
+
+

ID: {idNumber}

+

+ {lastSeen} +

-
-
- - - {profile.religion} - -
+
+ {[ + age, + height, + salary, + location, + caste, + zodiac1, + zodiac2, + ] + .filter(Boolean) + .map((v, i) => ( + + {v} + + ))}
-
-
- - - {profile.education} - -
-
- -
-
- - - {profile.location} - -
-
- -
- -
@@ -301,10 +210,10 @@ const ProfileCard = ({ profile }) => { animate={{ opacity: 1, y: 0 }} className="text-center mb-12" > -

+

New Joined

-

Find your perfect match today

+

Find your perfect match today

{/* Swiper Container */} @@ -319,10 +228,6 @@ const ProfileCard = ({ profile }) => { disableOnInteraction: false, pauseOnMouseEnter: true }} - pagination={{ - clickable: true, - dynamicBullets: true - }} loop={true} speed={800} breakpoints={{ @@ -341,8 +246,8 @@ const ProfileCard = ({ profile }) => { }} className="pb-16" > - {profiles.map((profile) => ( - + {displayProfiles.map((profile, index) => ( + ))} @@ -383,8 +288,12 @@ const ProfileCard = ({ profile }) => { whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} className="px-6 py-3 bg-[#034E08] text-white rounded-full font-semibold text-lg shadow-lg hover:shadow-xl transition-shadow" + onClick={() => { + dispatch(updateFilter({ filter_type: "newly_joined" })); + navigate("/matches", { state: { activeTab: "newly_joined", filter_type: "newly_joined" } }); + }} > - View All + View All Matches
diff --git a/src/components/profiledashboard/ProfileCompletion.jsx b/src/components/profiledashboard/ProfileCompletion.jsx index 93ec9be..e5d309a 100644 --- a/src/components/profiledashboard/ProfileCompletion.jsx +++ b/src/components/profiledashboard/ProfileCompletion.jsx @@ -9,7 +9,7 @@ import { useNavigate } from "react-router-dom"; import AstroChatUI from "./AstroChatUI"; import MembershipCard from "./MembershipCard"; -const ProfileCompletion = ({ percentage = 0, missingDetails }) => { +const ProfileCompletion = ({ percentage = 0, missingDetails,becomePaidMember }) => { const navigate = useNavigate(); const cards = [ @@ -167,7 +167,7 @@ const ProfileCompletion = ({ percentage = 0, missingDetails }) => { ))} - +
diff --git a/src/components/profiledashboard/VideoSwiperGallery.jsx b/src/components/profiledashboard/VideoSwiperGallery.jsx index 6326aa2..642b4cc 100644 --- a/src/components/profiledashboard/VideoSwiperGallery.jsx +++ b/src/components/profiledashboard/VideoSwiperGallery.jsx @@ -2,113 +2,31 @@ import React, { useState, useRef } from 'react'; import { motion } from 'framer-motion'; import { Swiper, SwiperSlide } from 'swiper/react'; import { Navigation, Pagination, Autoplay } from 'swiper/modules'; -import { Play, X, Heart, Share2, Eye, ChevronLeft, ChevronRight } from 'lucide-react'; -import weddingImg1 from "../../assets/images/wedding6.jpeg"; -import weddingImg2 from "../../assets/images/wedding8.jpg"; -import weddingImg3 from "../../assets/images/wedding6.jpeg"; +import { Play, X, ChevronLeft, ChevronRight } from 'lucide-react'; // Import Swiper styles import 'swiper/css'; import 'swiper/css/navigation'; import 'swiper/css/pagination'; -const VideoSwiperGallery = () => { +const VideoSwiperGallery = ({ videos }) => { const [selectedVideo, setSelectedVideo] = useState(null); const swiperRef = useRef(null); - // Video data with online sources - const videos = [ - { - id: 1, - title: 'Priya & Rahul - Wedding Story', - thumbnail: weddingImg1, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', - views: '2.4K', - likes: '142', - duration: '3:45' - }, - { - id: 2, - title: 'Aisha - Profile Introduction', - thumbnail: weddingImg2, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4', - views: '1.8K', - likes: '98', - duration: '2:30' - }, - { - id: 3, - title: 'Rohan - Life Journey', - thumbnail: weddingImg3, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4', - views: '3.2K', - likes: '256', - duration: '4:15' - }, - { - id: 4, - title: 'Divya - Family Values', - thumbnail: weddingImg1, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4', - views: '1.5K', - likes: '87', - duration: '3:00' - }, - { - id: 5, - title: 'Karthik & Meera - First Meet', - thumbnail: weddingImg2, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4', - views: '4.1K', - likes: '312', - duration: '5:20' - }, - { - id: 6, - title: 'Sneha - Hobbies & Interests', - thumbnail: weddingImg3, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4', - views: '2.7K', - likes: '178', - duration: '2:45' - }, - { - id: 7, - title: 'Arjun - Career & Dreams', - thumbnail: weddingImg1, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4', - views: '1.9K', - likes: '134', - duration: '3:30' - }, - { - id: 8, - title: 'Lakshmi - Traditional Values', - thumbnail: weddingImg2, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4', - views: '3.5K', - likes: '267', - duration: '4:00' - }, - { - id: 9, - title: 'Vikram - Adventure Life', - thumbnail: weddingImg3, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', - views: '5.2K', - likes: '423', - duration: '4:30' - }, - { - id: 10, - title: 'Anjali - Creative Journey', - thumbnail: weddingImg1, - videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4', - views: '3.8K', - likes: '289', - duration: '3:15' + const displayVideos = videos || []; + + if (displayVideos.length === 0) return null; + + const getEmbedUrl = (url) => { + if (!url) return ''; + let embedUrl = url; + if (url.includes('youtu.be/')) { + embedUrl = url.replace('youtu.be/', 'www.youtube.com/embed/'); + } else if (url.includes('youtube.com/watch?v=')) { + embedUrl = url.replace('youtube.com/watch?v=', 'youtube.com/embed/'); } - ]; + return embedUrl.split('?')[0] + '?autoplay=1'; + }; const VideoCard = ({ video }) => { const [isHovered, setIsHovered] = useState(false); @@ -129,12 +47,12 @@ const VideoSwiperGallery = () => {
{video.title} {/* Overlay */} -
+
{/* Play Button */} {
- - {/* Duration Badge */} -
- {video.duration} -
- - {/* Stats at bottom */} -
-

- {video.title} -

-
-
- - {video.views} -
-
- - {video.likes} -
-
-
@@ -202,36 +98,13 @@ const VideoSwiperGallery = () => { {/* Video Player */} -
-
@@ -290,7 +163,7 @@ const VideoSwiperGallery = () => { }} className="pb-16" > - {videos.map((video) => ( + {displayVideos.map((video) => ( diff --git a/src/components/ui/ProfileCardDemo.jsx b/src/components/ui/ProfileCardDemo.jsx index 433de34..14d64ad 100644 --- a/src/components/ui/ProfileCardDemo.jsx +++ b/src/components/ui/ProfileCardDemo.jsx @@ -1,73 +1,222 @@ -import React from "react"; -import { Heart, X, Crown, Bookmark, Eye } from "lucide-react"; -// Import your images -import Profile1 from "../../assets/images/bride1.jpg"; -import Profile2 from "../../assets/images/bride2.jpg"; -import Profile3 from "../../assets/images/bride3.jpg"; -import Profile4 from "../../assets/images/bride4.jpg"; +import React, { useState, useEffect } from "react"; +import { Heart, X, Crown, Bookmark, Eye, Clock, ChevronLeft, ChevronRight } from "lucide-react"; +import { Swiper, SwiperSlide } from "swiper/react"; +import { Navigation, Pagination } from "swiper/modules"; +import "swiper/css"; +import "swiper/css/navigation"; +import "swiper/css/pagination"; import { motion } from "framer-motion"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import toast from "react-hot-toast"; +import { shortlistProfile, sendInterest, declineProfile } from "../../services/shortlistapi"; +import { useNavigate } from "react-router-dom"; +const ProfileCardItem = ({ profile }) => { + const navigate = useNavigate(); + const queryClient = useQueryClient(); + const [isShortlisted, setIsShortlisted] = useState(profile?.is_shortlisted === 1); -export default function ProfileCard() { - // Sample data for multiple cards with image paths - const profiles = [ - { - id: 1, - name: "Jerome Bell", - idNumber: "KI2847596", - lastSeen: "4 Nov 2025", - salary: "5-10", - age: "22 yrs", - height: "5'2\"", - location: "Chennai", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: Profile1, + useEffect(() => { + setIsShortlisted(profile?.is_shortlisted === 1); + }, [profile?.is_shortlisted]); + + const shortlistMutation = useMutation({ + mutationFn: shortlistProfile, + onMutate: () => { + setIsShortlisted((prev) => !prev); }, - { - id: 2, - name: "Neha Singh", - idNumber: "KI2847597", - lastSeen: "5 Nov 2025", - salary: "8-12", - age: "26 yrs", - height: "5'6\"", - location: "hyderabad", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: Profile2, + onSuccess: (data) => { + toast.success(data.message || "Profile shortlisted successfully."); + queryClient.invalidateQueries(); }, - { - id: 3, - name: "Priya Sharma", - idNumber: "KI2847598", - lastSeen: "3 Nov 2025", - salary: "6-11", - age: "24 yrs", - height: "5'4\"", - location: "Mumbai", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: Profile3, + onError: (error) => { + setIsShortlisted(profile?.is_shortlisted === 1); + toast.error(error.message || "Failed to update shortlist status."); + } + }); + + const interestMutation = useMutation({ + mutationFn: sendInterest, + onSuccess: (data) => { + toast.success(data.message || "Interest sent successfully."); + queryClient.invalidateQueries(); }, - { - id: 4, - name: "Kavya Iyer", - idNumber: "KI2847599", - lastSeen: "2 Nov 2025", - salary: "7-10", - age: "23 yrs", - height: "5'3\"", - location: "Bangalore", - caste: "Brahmin", - zodiac1: "Aries", - zodiac2: "Scorpio", - image: Profile4, + onError: (error) => { + toast.error(error.message || "Failed to send interest."); + } + }); + + const declineMutation = useMutation({ + mutationFn: declineProfile, + onSuccess: (data) => { + toast.success(data.message || "Profile declined."); + queryClient.invalidateQueries(); }, - ]; + onError: (error) => { + toast.error(error.message || "Failed to decline profile."); + } + }); + + const id = profile.id; + const image = profile.photo || profile.image; + const name = profile.name || "Unknown"; + const idNumber = profile.member_id || profile.idNumber || "N/A"; + const lastSeen = profile.last_seen_at || profile.lastSeen || "Recently"; + const age = profile.age ? `${profile.age} yrs` : null; + const height = profile.height || null; + const salary = profile.annual_income_name || (profile.salary ? `${profile.salary} LPA` : null); + const location = profile.district_name || profile.location || null; + const caste = profile.caste_name || profile.caste || null; + const zodiac1 = profile.raasi_name || profile.zodiac1 || null; + const zodiac2 = profile.star_name || profile.zodiac2 || null; + const isPremium = profile.is_paid_member !== undefined ? profile.is_paid_member === 1 : true; + + return ( +
navigate(`/profile-details/${id}`)} + > + {/* IMAGE SECTION */} +
+ profile { + e.target.src = "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png"; + }} + /> + + {isPremium && ( +
+ +
+ )} + +
{ + e.stopPropagation(); + if (!shortlistMutation.isPending) shortlistMutation.mutate(id); + }} + > + + {shortlistMutation.isPending ? "..." : "Shortlist"} +
+
+ + {/* CONTENT */} +
+

+ {name} +

+ +
+

ID: {idNumber}

+

+ {lastSeen} +

+
+ +
+ {[ + age, + height, + salary, + location, + caste, + zodiac1, + zodiac2, + ] + .filter(Boolean) + .map((v, i) => ( + + {v} + + ))} +
+ +
+ + + +
+
+
+ ); +}; + +export default function ProfileCard({ profiles }) { + const displayProfiles = profiles || []; + + const [showTimer, setShowTimer] = useState(false); + const [timeLeft, setTimeLeft] = useState(24 * 60 * 60); // 24 hours in seconds + + useEffect(() => { + const storedEndTime = localStorage.getItem("profileTimerEnd"); + if (storedEndTime) { + const endTime = parseInt(storedEndTime, 10); + const now = Date.now(); + if (endTime > now) { + setShowTimer(true); + setTimeLeft(Math.floor((endTime - now) / 1000)); + } else { + localStorage.removeItem("profileTimerEnd"); + } + } + }, []); + + useEffect(() => { + let timer; + if (showTimer && timeLeft > 0) { + timer = setInterval(() => { + setTimeLeft((prev) => { + if (prev <= 1) { + setShowTimer(false); + localStorage.removeItem("profileTimerEnd"); + return 0; + } + return prev - 1; + }); + }, 1000); + } + return () => clearInterval(timer); + }, [showTimer, timeLeft]); + + const handleShowTimer = () => { + const endTime = Date.now() + 24 * 60 * 60 * 1000; // 24 hours from now + localStorage.setItem("profileTimerEnd", endTime.toString()); + setTimeLeft(24 * 60 * 60); + setShowTimer(true); + }; + + const formatTime = (seconds) => { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = seconds % 60; + return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`; + }; return (
@@ -90,73 +239,73 @@ export default function ProfileCard() { {/* CARDS GRID */}
-
- {profiles.map((profile) => ( -
+ {!showTimer ? ( + <> + {/* Custom Navigation Arrows */} + + + + { + if (displayProfiles.length > 0) { + setTimeout(handleShowTimer, 2500); // Wait 2.5s on the last slide before hiding + } + }} + className="pb-12" > - {/* IMAGE SECTION */} -
- profile - -
- -
- -
- Shortlist -
-
- - {/* CONTENT */} -
-

- {profile.name} -

- -
-

ID: {profile.idNumber}

-

- {profile.lastSeen} -

-
- -
- {[ - profile.age, - profile.height, - profile.salary + " LPA", - profile.location, - profile.caste, - profile.zodiac1, - profile.zodiac2, - ].map((v, i) => ( - - {v} - - ))} -
- -
- - -
+ + + + ) : ( + + +

Next Recommendations In

+
+ {formatTime(timeLeft)}
-
- ))} +

+ We are curating the best matches for you. Please check back when the timer ends! +

+ + )}
diff --git a/src/pages/UserDashboardHome.jsx b/src/pages/UserDashboardHome.jsx index 736e8ea..7792923 100644 --- a/src/pages/UserDashboardHome.jsx +++ b/src/pages/UserDashboardHome.jsx @@ -12,7 +12,7 @@ import weddingpromo3 from "../assets/images/weddingpromo3.jpg"; import weddingpromo4 from "../assets/images/weddingpromo4.jpg"; import { useDashboardQuery } from "../hooks/useDashboardQuery"; - +const NewJoinedProfile = lazy(() => import("../components/profiledashboard/NewJoinedProfile")); const ProfileCompletion = lazy(() => import("../components/profiledashboard/ProfileCompletion")); const MatrimonyArticles = lazy(() => import("../components/profiledashboard/MatrimonyArticles")); const MatchingList = lazy(() => import("../components/profiledashboard/MatchingList")); @@ -225,6 +225,7 @@ const UserDashboardHome = () => { {/* */} @@ -235,9 +236,9 @@ const UserDashboardHome = () => { }> - {/* */} - - {/* */} + }> + + {/* */} }> diff --git a/src/services/shortlistapi.js b/src/services/shortlistapi.js new file mode 100644 index 0000000..a97c931 --- /dev/null +++ b/src/services/shortlistapi.js @@ -0,0 +1,26 @@ +import axiosInstance from "../api/axiosInstance"; +import { API_ENDPOINTS } from "../api/apiEndpoints"; + +export const shortlistProfile = async (profileId) => { + const response = await axiosInstance.post(`${API_ENDPOINTS.SHORTLIST_API}?profile_id=${profileId}`); + if (response.data?.status === "error") { + throw new Error(response.data.message || "Failed to shortlist"); + } + return response.data; +}; + +export const sendInterest = async (profileId) => { + const response = await axiosInstance.post(`interest?profile_id=${profileId}`); + if (response.data?.status === "error") { + throw new Error(response.data.message || "Failed to send interest"); + } + return response.data; +}; + +export const declineProfile = async (profileId) => { + const response = await axiosInstance.post(`decline?profile_id=${profileId}`); + if (response.data?.status === "error") { + throw new Error(response.data.message || "Failed to decline profile"); + } + return response.data; +}; \ No newline at end of file