import { useState, useCallback, useEffect } from 'react'; import { X, Heart, ArrowUp, Undo2, ArrowLeft } from 'lucide-react'; import { Button } from './ui/button'; import { SwipeCard } from './SwipeCard'; import type { PropertyFeature, DecisionType } from '@/types'; interface SwipeReviewModeProps { features: PropertyFeature[]; onDecide: (listingId: number, decision: DecisionType, listingType?: 'RENT' | 'BUY') => void; onClear: (listingId: number, listingType?: 'RENT' | 'BUY') => void; onClose: () => void; onSelectListing?: (listingId: number) => void; getDecision: (listingId: number, listingType?: string) => DecisionType | undefined; } interface HistoryEntry { index: number; listingId: number; listingType: string; action: 'liked' | 'disliked' | 'skipped'; } function getListingId(feature: PropertyFeature): number { const parts = feature.properties.url.split('/'); return parseInt(parts[parts.length - 1], 10); } function getListingType(feature: PropertyFeature): 'RENT' | 'BUY' { return feature.properties.listing_type === 'BUY' ? 'BUY' : 'RENT'; } export function SwipeReviewMode({ features, onDecide, onClear, onClose, onSelectListing, getDecision, }: SwipeReviewModeProps) { // Filter to only undecided features const undecided = features.filter((f) => { const id = getListingId(f); const type = getListingType(f); return getDecision(id, type) === undefined; }); const [currentIndex, setCurrentIndex] = useState(0); const [history, setHistory] = useState([]); const handleSwipe = useCallback( (direction: 'left' | 'right' | 'up') => { const feature = undecided[currentIndex]; if (!feature) return; const listingId = getListingId(feature); const listingType = getListingType(feature); let action: HistoryEntry['action']; if (direction === 'right') { action = 'liked'; onDecide(listingId, 'liked', listingType); } else if (direction === 'left') { action = 'disliked'; onDecide(listingId, 'disliked', listingType); } else { action = 'skipped'; } setHistory((prev) => [...prev, { index: currentIndex, listingId, listingType, action }]); setCurrentIndex((prev) => prev + 1); }, [currentIndex, undecided, onDecide], ); const handleUndo = useCallback(() => { const lastEntry = history[history.length - 1]; if (!lastEntry) return; if (lastEntry.action !== 'skipped') { onClear(lastEntry.listingId, lastEntry.listingType as 'RENT' | 'BUY'); } setHistory((prev) => prev.slice(0, -1)); setCurrentIndex((prev) => prev - 1); }, [history, onClear]); // Keyboard shortcuts useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === 'ArrowRight') handleSwipe('right'); else if (e.key === 'ArrowLeft') handleSwipe('left'); else if (e.key === 'ArrowUp') handleSwipe('up'); else if ((e.ctrlKey || e.metaKey) && e.key === 'z') handleUndo(); else if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', handler); return () => window.removeEventListener('keydown', handler); }, [handleSwipe, handleUndo, onClose]); const isFinished = currentIndex >= undecided.length; return (
{/* Header */}
{Math.min(currentIndex + 1, undecided.length)} / {undecided.length}
{/* Card stack */}
{isFinished ? (

All done!

You've reviewed all {undecided.length} properties.

) : (
{undecided.slice(currentIndex, currentIndex + 3).map((feature, i) => ( onSelectListing?.(getListingId(feature))} isTop={i === 0} stackIndex={i} /> ))}
)}
{/* Action buttons */} {!isFinished && (
)}
); }