thirukalyanamweb/src/components/common/MatrimonySwipeCards.jsx
2025-11-28 18:10:54 +05:30

370 lines
13 KiB
JavaScript

import { useState, useEffect,useRef, useMemo } from 'react';
import { Heart, X, RotateCcw, MapPin, Briefcase, GraduationCap } from 'lucide-react';
import LazyImage from './LazyImage';
import nomoreimg from "../../assets/images/nomoreimg.png";
import { useNavigate } from "react-router-dom";
import bride1 from "../../assets/images/bride1.jpg";
import bride2 from "../../assets/images/bride2.jpg";
import bride3 from "../../assets/images/bride3.jpg";
import bride4 from "../../assets/images/bride4.jpg";
import Tooltip from '@mui/material/Tooltip';
const TinderCard = ({ children, onSwipe, onCardLeftScreen, preventSwipe, className }) => {
const [pos, setPos] = useState({ x: 0, y: 0 });
const [dragging, setDragging] = useState(false);
const [startPos, setStartPos] = useState({ x: 0, y: 0 });
const [gone, setGone] = useState(false);
useEffect(() => {
// Reset state on mount
setPos({ x: 0, y: 0 });
setDragging(false);
setGone(false);
}, []);
const handleStart = (clientX, clientY) => {
if (gone) return;
setDragging(true);
setStartPos({ x: clientX - pos.x, y: clientY - pos.y });
};
const handleMove = (clientX, clientY) => {
if (!dragging || gone) return;
setPos({ x: clientX - startPos.x, y: clientY - startPos.y });
};
const handleEnd = () => {
if (gone) return;
setDragging(false);
if (Math.abs(pos.x) > 120) {
const dir = pos.x > 0 ? 'right' : 'left';
if (onSwipe) onSwipe(dir);
setGone(true);
setTimeout(() => onCardLeftScreen && onCardLeftScreen(dir), 300);
} else {
setPos({ x: 0, y: 0 });
}
};
if (gone) return null;
const rotation = pos.x / 20;
const opacity = Math.min(Math.abs(pos.x) / 100, 1);
return (
<div
className={className}
style={{
transform: `translate(${pos.x}px, ${pos.y}px) rotate(${rotation}deg)`,
transition: dragging ? 'none' : 'transform 0.3s ease-out',
touchAction: 'none'
}}
onMouseDown={(e) => handleStart(e.clientX, e.clientY)}
onMouseMove={(e) => handleMove(e.clientX, e.clientY)}
onMouseUp={handleEnd}
onMouseLeave={() => dragging && handleEnd()}
onTouchStart={(e) => handleStart(e.touches[0].clientX, e.touches[0].clientY)}
onTouchMove={(e) => handleMove(e.touches[0].clientX, e.touches[0].clientY)}
onTouchEnd={handleEnd}
>
{pos.x > 50 && (
<div className="absolute top-8 left-8 z-10 border-4 border-green-500 text-green-500 px-4 py-2 rounded-lg text-2xl font-bold rotate-[-20deg]" style={{ opacity }}>
LIKE
</div>
)}
{pos.x < -50 && (
<div className="absolute top-8 right-8 z-10 border-4 border-red-500 text-red-500 px-4 py-2 rounded-lg text-2xl font-bold rotate-[20deg]" style={{ opacity }}>
NOPE
</div>
)}
{children}
</div>
);
};
const profiles = [
{
id: 1,
name: 'Priya Sharma',
age: 26,
location: 'Mumbai, India',
profession: 'Software Engineer',
education: 'B.Tech from IIT Bombay',
about: 'Love traveling, reading, and cooking. Looking for someone who values family.',
image: bride1
},
{
id: 2,
name: 'Ananya Patel',
age: 24,
location: 'Bangalore, India',
profession: 'Doctor',
education: 'MBBS from AIIMS',
about: 'Passionate about healthcare and music. Seeking a caring life partner.',
image: bride2
},
{
id: 3,
name: 'Neha Gupta',
age: 27,
location: 'Delhi, India',
profession: 'CA',
education: 'CA from ICAI',
about: 'Enjoy yoga and meditation. Looking for someone with similar values.',
image: bride3
},
{
id: 4,
name: 'Kavya Reddy',
age: 25,
location: 'Hyderabad, India',
profession: 'Marketing Manager',
education: 'MBA from ISB',
about: 'Creative soul who loves art and dance. Seeking a supportive partner.',
image: bride4
}
];
export default function MatrimonySwipeCards() {
const [swipedCards, setSwipedCards] = useState(new Set());
const [lastDirection, setLastDirection] = useState('');
const [likedProfiles, setLikedProfiles] = useState([]);
const [dislikedProfiles, setDislikedProfiles] = useState([]);
const [key, setKey] = useState(0);
const navigate = useNavigate();
const activeProfiles = profiles.filter(p => !swipedCards.has(p.id));
const canSwipe = activeProfiles.length > 0;
// **CHECK TOKEN FOR BLUR CONTROL**
const hasValidToken = useMemo(() => {
return !!localStorage.getItem("token");
}, []);
// **FIX: Ensure consistent order - Priya Sharma first**
const displayProfiles = useMemo(() => {
return activeProfiles.sort((a, b) => b.id - a.id ); // Sort by ID ascending (1,2,3,4)
}, [activeProfiles]);
const swiped = (direction, profile) => {
setLastDirection(direction);
setSwipedCards(prev => new Set([...prev, profile.id]));
if (direction === 'right') {
setLikedProfiles(prev => [...prev, profile]);
} else {
setDislikedProfiles(prev => [...prev, profile]);
}
};
// const swipe = (dir) => {
// if (canSwipe) {
// const topProfile = activeProfiles[activeProfiles.length - 1];
// swiped(dir, topProfile);
// }
// };
const swipe = (dir) => {
const token = localStorage.getItem("token");
if (!token) {
navigate("/login");
return;
}
navigate("/match");
if (canSwipe) {
// const topProfile = activeProfiles[activeProfiles.length - 1];
const topProfile = displayProfiles[0]; // Priya Sharma first
swiped(dir, topProfile);
}
};
const reset = () => {
setSwipedCards(new Set());
setLikedProfiles([]);
setDislikedProfiles([]);
setLastDirection('');
setKey(prev => prev + 1);
};
return (
<div className=" w-[100%] max-w-[fit-screen] p-2 md:px-6 overflow-hidden">
<div className="max-w-md mx-auto">
<h1 className="text-2xl font-bold text-center text-gray-800 mb-2">
Find Your Match
</h1>
<p className="text-center text-gray-600 mb-4 text-sm">
Swipe right to like, left to pass
</p>
{/* Card Container with overflow hidden */}
<div className="relative h-[480px] w-full overflow-hidden rounded-2xl">
<div className="absolute inset-0 flex items-center justify-center">
{!canSwipe ? (
<div className="text-center p-8 bg-white rounded-2xl shadow-lg">
<p className="text-xl text-gray-600 mb-4">No more profiles!</p>
<LazyImage
src={nomoreimg}
className="w-full h-[190px] object-cover "
/>
<button
onClick={reset}
className="cursor-pointer flex items-center gap-2 mx-auto px-6 py-3 bg-[#034E08] text-white rounded-full hover:bg-[#A70710] transition"
>
<RotateCcw size={20} />
Start Over
</button>
</div>
) : (
displayProfiles
.slice(0, 4) // Limit to 3 cards for stack effect
.map((profile, index) => {
const isTopCard = index === 3; // ALWAYS FIXED TOP CARD
// **NO BLUR IF TOKEN EXISTS**
const shouldBlur = !hasValidToken && !isTopCard;
return (
<TinderCard
key={`${key}-${profile.id}`}
onSwipe={(dir) => swiped(dir, profile)}
onCardLeftScreen={() => {}}
preventSwipe={['up', 'down']}
className="absolute w-full max-w-sm cursor-grab active:cursor-grabbing"
>
<div onClick={(e) => e.stopPropagation()} className="bg-white rounded-2xl shadow-xl overflow-hidden select-none">
<div className="relative">
<div classname=" relative bg-gray-200 overflow-hidden w-full max-w-sm h-[300px]" style={{height:"300px"}}>
<img
src={profile.image}
alt={profile.name}
className={`w-full h-full object-cover
${shouldBlur ? "blur-[4px] brightness-75 p-2" : ""}
`}
draggable={false}
/>
{/* LOCK ICON FOR NON TOP CARDS */}
{shouldBlur && (
<div className="absolute inset-0 flex items-center justify-center">
<svg width="60" height="60" fill="white">
<path d="M12 22v-6a10 10 0 1120 0v6h2a2 2 0 012 2v18a2 2 0 01-2 2H10a2 2 0 01-2-2V24a2 2 0 012-2h2zm4 0h16v-6a8 8 0 10-16 0v6z"/>
</svg>
</div>
)}
</div>
{/* White Gradient Overlay at bottom of image */}
<div
className="z-1 absolute bottom-0 left-0 right-0 h-15 pointer-events-none"
style={{
background:
"linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.75) 50%, rgb(255, 255, 255) 100%)",
}}
></div>
<div className="z-2 absolute bottom-1 left-0 right-0 pb-0 p-4">
<h2 className=" text-[22px] font-bold text-black">
{profile.name}, {profile.age}
</h2>
</div>
</div>
<div className="p-4 space-y-3">
<div className="flex items-center gap-2 text-gray-600">
<MapPin size={16} className="text-pink-500 flex-shrink-0" />
<span className="text-sm">{profile.location}</span>
</div>
<div className="flex items-center gap-2 text-gray-600">
<Briefcase size={16} className="text-purple-500 flex-shrink-0" />
<span className="text-sm">{profile.profession}</span>
</div>
<div className="flex items-center gap-2 text-gray-600">
<GraduationCap size={16} className="text-indigo-500 flex-shrink-0" />
<span className="text-sm">{profile.education}</span>
</div>
<p className="text-gray-700 text-sm mt-2 line-clamp-2">
{profile.about}
</p>
</div>
</div>
</TinderCard>
)
})
)}
</div>
</div>
{/* Action Buttons */}
{canSwipe && (
<div className="flex justify-center gap-6 mt-4">
{/* Decline Button with MUI Tooltip */}
<Tooltip title="Decline" placement="top" arrow>
<button
onClick={() => swipe('left')}
className="w-12 h-12 bg-white rounded-full shadow-lg flex items-center justify-center hover:bg-red-50 transition border-2 border-red-200 hover:border-red-400 active:scale-95"
>
<X size={26} className="text-red-500" />
</button>
</Tooltip>
{/* Reset Button with MUI Tooltip */}
<Tooltip title="Reset" placement="top" arrow>
<button
onClick={reset}
className="w-12 h-12 bg-white rounded-full shadow-lg flex items-center justify-center hover:bg-yellow-50 transition border-2 border-yellow-200 hover:border-yellow-400 active:scale-95 self-center"
>
<RotateCcw size={20} className="text-yellow-500" />
</button>
</Tooltip>
{/* Interest Button with MUI Tooltip */}
<Tooltip title="Show Interest" placement="top" arrow>
<button
onClick={() => swipe('right')}
className="w-12 h-12 bg-white rounded-full shadow-lg flex items-center justify-center hover:bg-green-50 transition border-2 border-green-200 hover:border-green-400 active:scale-95"
>
<Heart size={26} className="text-green-500" />
</button>
</Tooltip>
</div>
)}
{/* Stats */}
{/* <div className="mt-6 flex gap-4 text-sm">
<div className="flex-1 bg-green-100 rounded-lg p-3 text-center">
<p className="font-semibold text-green-700">👍 Liked: {likedProfiles.length}</p>
</div>
<div className="flex-1 bg-red-100 rounded-lg p-3 text-center">
<p className="font-semibold text-red-700">👎 Passed: {dislikedProfiles.length}</p>
</div>
</div> */}
{/* Liked Profiles Preview */}
{/* {likedProfiles.length > 0 && (
<div className="mt-4 bg-white rounded-xl p-4 shadow-md">
<h3 className="font-semibold text-gray-700 mb-3">💚 Your Likes</h3>
<div className="flex gap-2 flex-wrap">
{likedProfiles.map(p => (
<div key={p.id} className="flex items-center gap-2 bg-green-50 px-3 py-1.5 rounded-full">
<img src={p.image} alt={p.name} className="w-6 h-6 rounded-full object-cover" />
<span className="text-sm text-green-700">{p.name.split(' ')[0]}</span>
</div>
))}
</div>
</div>
)} */}
</div>
</div>
);
}