import { useRef, useState } from 'react'; import { useDrag } from '@use-gesture/react'; import { useSpring, animated } from '@react-spring/web'; import { Heart, X } from 'lucide-react'; import { PropertyCard } from './PropertyCard'; import type { PropertyProperties, POI, DecisionType } from '@/types'; interface SwipeablePropertyCardProps { property: PropertyProperties; variant?: 'compact' | 'full'; isHighlighted?: boolean; avgPricePerSqm?: number; allPOIs?: POI[]; onClick?: () => void; onSwipeRight?: () => void; onSwipeLeft?: () => void; decision?: DecisionType | null; } const SWIPE_THRESHOLD = 80; export function SwipeablePropertyCard({ property, variant = 'compact', isHighlighted = false, avgPricePerSqm, allPOIs, onClick, onSwipeRight, onSwipeLeft, decision, }: SwipeablePropertyCardProps) { const containerRef = useRef(null); const [gone, setGone] = useState(false); const [{ x, opacity }, api] = useSpring(() => ({ x: 0, opacity: 1, config: { tension: 200, friction: 20 }, })); const bind = useDrag( ({ active, movement: [mx], direction: [dx] }) => { if (gone) return; // If dragging vertically more than horizontally, cancel (let scroll work) if (active && Math.abs(mx) < 15) return; if (!active) { // Released if (Math.abs(mx) > SWIPE_THRESHOLD) { // Swipe confirmed setGone(true); const dir = dx > 0 ? 1 : -1; api.start({ x: dir * 400, opacity: 0, onRest: () => { if (dir > 0) onSwipeRight?.(); else onSwipeLeft?.(); }, }); } else { // Spring back api.start({ x: 0, opacity: 1 }); } } else { api.start({ x: mx, opacity: 1 - Math.abs(mx) / 400, immediate: true }); } }, { axis: 'x', filterTaps: true, from: () => [x.get(), 0], }, ); if (gone) return null; const likedBadge = decision === 'liked'; return (
{/* Background indicators */}
{/* Card */}
{likedBadge && (
)}
); }