import { useState } from "preact/hooks"; import type { Trip, Place } from "../../lib/types"; import type { UserLocation } from "../../lib/use-location"; import { haversineKm } from "../../lib/geo"; import { PlaceCard } from "../shared/PlaceCard"; import { getCategory } from "../../lib/categories"; export function OnRoadTab({ trip, location }: { trip: Trip; location: UserLocation | null }) { const [expandedIdx, setExpandedIdx] = useState(null); const legOrder = (place: Place): number => { const leg = (place.details?.leg as string || "").toLowerCase(); if (leg.includes("departure")) return 0; if (leg.includes("outbound")) return 1; if (leg.includes("return")) return 2; return 3; }; const sortByRoute = (places: Place[]): Place[] => [...places].sort((a, b) => { const la = legOrder(a); const lb = legOrder(b); if (la !== lb) return la - lb; const ma = (a.details?.mileFromStart as number) ?? 9999; const mb = (b.details?.mileFromStart as number) ?? 9999; return ma - mb; }); const sortByDistance = (places: Place[]): Place[] => { if (!location) return places; return [...places].sort((a, b) => { const da = haversineKm({ lat: location.lat, lng: location.lng }, { lat: a.lat, lng: a.lng }); const db = haversineKm({ lat: location.lat, lng: location.lng }, { lat: b.lat, lng: b.lng }); return da - db; }); }; const fuelStops = sortByRoute(trip.places.filter(p => p.category === "fuel")); const restStops = sortByDistance(trip.places.filter(p => p.category === "rest-stop")); const cellCoverage = trip.safety.cellCoverage || []; const nextFuelIdx = (() => { if (!location || fuelStops.length === 0) return 0; for (let i = 0; i < fuelStops.length - 1; i++) { const distHere = haversineKm( { lat: location.lat, lng: location.lng }, { lat: fuelStops[i].lat, lng: fuelStops[i].lng } ); const distNext = haversineKm( { lat: location.lat, lng: location.lng }, { lat: fuelStops[i + 1].lat, lng: fuelStops[i + 1].lng } ); if (distHere <= distNext) return i; } return fuelStops.length - 1; })(); const allStops = [...fuelStops, ...restStops]; return (
{fuelStops.length > 0 && (
{fuelStops.map((place, i) => ( setExpandedIdx(expandedIdx === i ? null : i)} location={location} passed={nextFuelIdx >= 0 && i < nextFuelIdx} next={nextFuelIdx >= 0 && i === nextFuelIdx} /> ))}
)} {restStops.length > 0 && (
{restStops.map((place, i) => { const idx = fuelStops.length + i; return ( setExpandedIdx(expandedIdx === idx ? null : idx)} location={location} /> ); })}
)} {cellCoverage.length > 0 && (
{cellCoverage.map((seg, i) => (
{seg.segment} {seg.status === "full" ? "FULL" : seg.status === "spotty" ? "SPOTTY" : "NO SERVICE"}
))}
)}
{trip.days.map((day, di) => ( day.drives.length > 0 && (
{day.label}
{day.drives.map((drive, i) => (
{drive.from} {drive.to}
{drive.distance && {drive.distance}} {drive.duration && {drive.duration}}
{drive.costs && drive.costs.length > 0 && (
{drive.costs.map((c, ci) => (
{c.item} {c.amount}
))}
)}
))}
) ))}
{allStops.length === 0 && cellCoverage.length === 0 && (
No road info available yet.
)}
); }