import { useState, useEffect } from "preact/hooks"; import type { Trip, TripSummary, MapSummary, StandaloneMap } from "../lib/types"; import { loadTrip, loadTrips, loadMap, loadMaps } from "../lib/trip-store"; import { TripView } from "./TripView"; import { TripIndex } from "./TripIndex"; import { MapIndex } from "./MapIndex"; import { MapView } from "./MapView"; import "../styles/palacetravel.css"; type Section = "trips" | "maps"; function parseUrl(): { section: Section; tripId: string | null; mapId: string | null } { const rel = window.location.pathname.replace(/^\/travel\/?/, "").replace(/\/$/, ""); const parts = rel ? rel.split("/") : []; if (parts[0] === "maps") { return { section: "maps", tripId: null, mapId: parts[1] || null }; } else if (parts[0]) { return { section: "trips", tripId: parts[0], mapId: null }; } return { section: "trips", tripId: null, mapId: null }; } export function MapApp() { const [section, setSection] = useState
("trips"); // --- Trips state --- const [trips, setTrips] = useState(null); const [activeTripId, setActiveTripId] = useState(null); const [trip, setTrip] = useState(null); // --- Maps state --- const [maps, setMaps] = useState(null); const [selectedMapId, setSelectedMapId] = useState(null); const [standaloneMap, setStandaloneMap] = useState(null); const [error, setError] = useState(null); // Parse path on mount and handle browser back/forward useEffect(() => { const apply = () => { const { section, tripId, mapId } = parseUrl(); setSection(section); if (section === "maps") { setActiveTripId(null); setSelectedMapId(mapId); if (!mapId) loadMaps().then(setMaps).catch(e => setError(e.message)); } else { setSelectedMapId(null); setActiveTripId(tripId); if (!tripId) loadTrips().then(setTrips).catch(e => setError(e.message)); } }; apply(); window.addEventListener("popstate", apply); return () => window.removeEventListener("popstate", apply); }, []); // Load trip data when activeTripId changes useEffect(() => { if (!activeTripId) return; setTrip(null); setError(null); loadTrip(activeTripId).then(setTrip).catch(e => setError(e.message)); }, [activeTripId]); // Load standalone map when selectedMapId changes useEffect(() => { if (!selectedMapId) return; setStandaloneMap(null); setError(null); loadMap(selectedMapId).then(setStandaloneMap).catch(e => setError(e.message)); }, [selectedMapId]); const openTrip = (id: string) => { setActiveTripId(id); history.pushState(null, "", `/travel/${id}/`); }; const goBackToTrips = () => { setActiveTripId(null); setTrip(null); setError(null); history.pushState(null, "", "/travel/"); loadTrips().then(setTrips).catch(e => setError(e.message)); }; const openMap = (id: string) => { setSelectedMapId(id); history.pushState(null, "", `/travel/maps/${id}/`); }; const goBackToMaps = () => { setSelectedMapId(null); setStandaloneMap(null); setError(null); history.pushState(null, "", "/travel/maps/"); loadMaps().then(setMaps).catch(e => setError(e.message)); }; const switchSection = (s: Section) => { setSection(s); setError(null); if (s === "trips") { setActiveTripId(null); setTrip(null); history.pushState(null, "", "/travel/"); if (!trips) loadTrips().then(setTrips).catch(e => setError(e.message)); } else { setSelectedMapId(null); setStandaloneMap(null); history.pushState(null, "", "/travel/maps/"); if (!maps) loadMaps().then(setMaps).catch(e => setError(e.message)); } }; // Render trip detail view (no section switcher shown) if (activeTripId) { if (!trip) return
Loading trip...
; return ; } // Render standalone map view (no section switcher shown) if (selectedMapId) { if (!standaloneMap) return
Loading map...
; return ; } if (error) return
{error}
; return (
{/* Section switcher */}
{/* Trips section */} {section === "trips" && ( trips === null ?
Loading trips...
: )} {/* Maps section */} {section === "maps" && ( maps === null ?
Loading maps...
: )}
); }