import { useState, useMemo, useCallback } from 'react'; import { Drawer } from 'vaul'; import { MapPin, PoundSterling } from 'lucide-react'; import { SwipeableCardRow } from './SwipeableCardRow'; import { ListView } from './ListView'; import type { GeoJSONFeatureCollection, PropertyProperties, PropertyFeature } from '@/types'; interface MobileBottomSheetProps { listingData: GeoJSONFeatureCollection | null; onPropertyClick?: (property: PropertyProperties, coordinates: [number, number]) => void; highlightedPropertyUrl?: string | null; onActiveListingChange?: (feature: PropertyFeature | null) => void; poiMetricSelection?: { poiId: number; travelMode: string } | null; } function formatCurrency(value: number): string { if (value >= 1000) return `£${(value / 1000).toFixed(1)}k`; return `£${Math.round(value)}`; } export function MobileBottomSheet({ listingData, onPropertyClick, highlightedPropertyUrl, onActiveListingChange, poiMetricSelection, }: MobileBottomSheetProps) { const [snap, setSnap] = useState("148px"); const [activeCardIndex, setActiveCardIndex] = useState(0); const features = listingData?.features ?? []; const stats = useMemo(() => { if (features.length === 0) return { count: 0, avgPrice: 0 }; const validPrices = features .map((f) => f.properties.total_price) .filter((p): p is number => typeof p === 'number' && p > 0); const avgPrice = validPrices.length > 0 ? validPrices.reduce((a, b) => a + b, 0) / validPrices.length : 0; return { count: features.length, avgPrice }; }, [features]); const avgPricePerSqm = useMemo(() => { const validPrices = features .map((f) => f.properties.qmprice) .filter((p): p is number => typeof p === 'number' && p > 0); return validPrices.length > 0 ? validPrices.reduce((a, b) => a + b, 0) / validPrices.length : 0; }, [features]); const handleActiveIndexChange = useCallback((index: number) => { setActiveCardIndex(index); if (features[index]) { onActiveListingChange?.(features[index]); } }, [features, onActiveListingChange]); const handleCardClick = useCallback((feature: PropertyFeature) => { window.open(feature.properties.url, '_blank', 'noopener,noreferrer'); onPropertyClick?.(feature.properties, feature.geometry.coordinates); }, [onPropertyClick]); const isExpanded = snap === 0.85; return ( Property Listings {/* Drag handle */}
{/* Compact stats (always visible) */}
{stats.count.toLocaleString()} listings
{stats.avgPrice > 0 && (
Avg: {formatCurrency(stats.avgPrice)}
)}
{/* Swipeable cards (visible at peek snap) */} {!isExpanded && features.length > 0 && ( )} {/* Full list view (visible at expanded snap) */} {isExpanded && listingData && features.length > 0 && (
)} ); }