import { useState, useCallback } from 'react'; import { Slider } from '../ui/Slider'; import { IconButton } from '../ui/IconButton'; import { PillToggle } from '../ui/PillToggle'; import { DestinationDropdown } from '../ui/DestinationDropdown'; import InfoPopup from '../ui/InfoPopup'; import { CloseIcon } from '../ui/icons/CloseIcon'; import { EyeIcon } from '../ui/icons/EyeIcon'; import { InfoIcon } from '../ui/icons/InfoIcon'; import { CarIcon } from '../ui/icons/CarIcon'; import { BicycleIcon } from '../ui/icons/BicycleIcon'; import { WalkingIcon } from '../ui/icons/WalkingIcon'; import { TransitIcon } from '../ui/icons/TransitIcon'; import { formatFilterValue } from '../../lib/format'; import { useTravelDestinations } from '../../hooks/useTravelDestinations'; import { MODE_LABELS, type TransportMode } from '../../hooks/useTravelTime'; import type { ComponentType } from 'react'; const MODE_ICONS: Record> = { car: CarIcon, bicycle: BicycleIcon, walking: WalkingIcon, transit: TransitIcon, }; interface TravelTimeCardProps { mode: TransportMode; slug: string; label: string; timeRange: [number, number] | null; useBest: boolean; isPinned: boolean; onTogglePin: () => void; onSetDestination: (slug: string, label: string) => void; onTimeRangeChange: (range: [number, number]) => void; onToggleBest: () => void; onRemove: () => void; } export function TravelTimeCard({ mode, slug, label, timeRange, useBest, isPinned, onTogglePin, onSetDestination, onTimeRangeChange, onToggleBest, onRemove, }: TravelTimeCardProps) { const { destinations, loading: destinationsLoading } = useTravelDestinations(mode); const [showInfo, setShowInfo] = useState(false); const [showBestInfo, setShowBestInfo] = useState(false); const handleDestinationSelect = useCallback( (selectedSlug: string, selectedLabel: string) => { onSetDestination(selectedSlug, selectedLabel); }, [onSetDestination] ); const sliderMin = 0; const sliderMax = 120; const displayRange = timeRange ?? [sliderMin, sliderMax]; const ModeIcon = MODE_ICONS[mode]; return (
{/* Header */}
Travel Time ({MODE_LABELS[mode]})
setShowInfo(true)} title="Feature info"> {slug && ( )} onRemove()} title="Remove travel time">
{/* Destination */} onSetDestination('', '')} placeholder="Select destination..." /> {/* Best-case toggle — transit only, shown when destination is set */} {slug && mode === 'transit' && (
setShowBestInfo(true)} title="What is best case?">
)} {showInfo && ( setShowInfo(false)}>

Shows how long it takes to reach the selected destination from each area {mode === 'transit' ? ' by public transport (bus, rail, tube). Times are computed across a typical weekday morning window.' : mode === 'car' ? ' by car, based on typical road speeds and the road network.' : mode === 'bicycle' ? ' by bicycle, using cycle-friendly routes.' : ' on foot, using pedestrian paths and pavements.'}{' '} Use the slider to filter areas within your preferred commute time.

)} {showBestInfo && ( setShowBestInfo(false)}>

Uses the 5th percentile travel time - the fastest realistic journey if you time your departure to catch optimal connections. The default uses the{' '} median, representing a typical journey regardless of when you leave.

)} {/* Time range slider — only show when we have data */} {slug && (
Max time onTimeRangeChange([min, max])} />
{formatFilterValue(displayRange[0])} min {formatFilterValue(displayRange[1])} min
)}
); }