diff options
Diffstat (limited to 'src/frontend/app/components')
| -rw-r--r-- | src/frontend/app/components/PlannerOverlay.tsx | 120 | ||||
| -rw-r--r-- | src/frontend/app/components/layout/NavBar.module.css | 1 | ||||
| -rw-r--r-- | src/frontend/app/components/layout/NavBar.tsx | 19 |
3 files changed, 107 insertions, 33 deletions
diff --git a/src/frontend/app/components/PlannerOverlay.tsx b/src/frontend/app/components/PlannerOverlay.tsx index 622884e..8046ab2 100644 --- a/src/frontend/app/components/PlannerOverlay.tsx +++ b/src/frontend/app/components/PlannerOverlay.tsx @@ -1,4 +1,10 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; import { useTranslation } from "react-i18next"; import { reverseGeocode, @@ -20,6 +26,7 @@ interface PlannerOverlayProps { inline?: boolean; clearPickerOnOpen?: boolean; showLastDestinationWhenCollapsed?: boolean; + cardBackground?: string; } export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ @@ -29,6 +36,7 @@ export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ inline, clearPickerOnOpen = false, showLastDestinationWhenCollapsed = true, + cardBackground, }) => { const { t } = useTranslation(); const { origin, setOrigin, destination, setDestination, loading, error } = @@ -108,6 +116,14 @@ export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ clearPickerOnOpen ? "" : field === "origin" ? originQuery : destQuery ); setPickerOpen(true); + + // When opening destination picker, auto-fill origin from current location if not set + if (field === "destination" && !origin) { + console.log( + "[PlannerOverlay] Destination picker opened with no origin, requesting geolocation" + ); + setOriginFromCurrentLocation(false); + } }; const applyPickedResult = (result: PlannerSearchResult) => { @@ -121,34 +137,75 @@ export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ setPickerOpen(false); }; - const setOriginFromCurrentLocation = () => { - if (!navigator.geolocation) return; - setLocationLoading(true); - navigator.geolocation.getCurrentPosition( - async (pos) => { - try { - const rev = await reverseGeocode( + const setOriginFromCurrentLocation = useCallback( + (closePicker: boolean = true) => { + console.log( + "[PlannerOverlay] setOriginFromCurrentLocation called, closePicker:", + closePicker + ); + if (!navigator.geolocation) { + console.warn("[PlannerOverlay] Geolocation not available"); + return; + } + setLocationLoading(true); + navigator.geolocation.getCurrentPosition( + async (pos) => { + console.log( + "[PlannerOverlay] Geolocation success:", pos.coords.latitude, pos.coords.longitude ); - const picked: PlannerSearchResult = { - name: rev?.name || "Ubicación actual", - label: rev?.label || "GPS", - lat: pos.coords.latitude, - lon: pos.coords.longitude, - layer: "current-location", - }; - setOrigin(picked); - setOriginQuery(picked.name || ""); - setPickerOpen(false); - } finally { + try { + // Set immediately using raw coordinates; refine later if reverse geocode works. + const initial: PlannerSearchResult = { + name: t("planner.current_location"), + label: "GPS", + lat: pos.coords.latitude, + lon: pos.coords.longitude, + layer: "current-location", + }; + console.log("[PlannerOverlay] Setting initial origin:", initial); + setOrigin(initial); + setOriginQuery(initial.name || ""); + + try { + const rev = await reverseGeocode( + pos.coords.latitude, + pos.coords.longitude + ); + console.log("[PlannerOverlay] Reverse geocode result:", rev); + if (rev) { + const refined: PlannerSearchResult = { + ...initial, + name: rev.name || initial.name, + label: rev.label || initial.label, + layer: "current-location", + }; + console.log( + "[PlannerOverlay] Setting refined origin:", + refined + ); + setOrigin(refined); + setOriginQuery(refined.name || ""); + } + } catch (err) { + console.error("[PlannerOverlay] Reverse geocode failed:", err); + } + + if (closePicker) setPickerOpen(false); + } finally { + setLocationLoading(false); + } + }, + (err) => { + console.error("[PlannerOverlay] Geolocation error:", err); setLocationLoading(false); - } - }, - () => setLocationLoading(false), - { enableHighAccuracy: true, timeout: 10000 } - ); - }; + }, + { enableHighAccuracy: true, timeout: 10000 } + ); + }, + [setOrigin, t] + ); useEffect(() => { if (!pickerOpen) return; @@ -199,8 +256,8 @@ export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ : "pointer-events-none absolute left-0 right-0 top-0 z-20 flex justify-center"; const cardClass = inline - ? "pointer-events-auto w-full overflow-hidden rounded-xl bg-white dark:bg-slate-900 px-2 flex flex-col gap-3" - : "pointer-events-auto w-[min(640px,calc(100%-16px))] px-2 py-1 flex flex-col gap-3 m-4 overflow-hidden rounded-xl border border-slate-200/80 dark:border-slate-700/70 bg-white/95 dark:bg-slate-900/90 shadow-2xl backdrop-blur"; + ? `pointer-events-auto w-full overflow-hidden rounded-xl px-2 flex flex-col gap-3 ${cardBackground || "bg-white dark:bg-slate-900"}` + : `pointer-events-auto w-[min(640px,calc(100%-16px))] px-2 py-1 flex flex-col gap-3 m-4 overflow-hidden rounded-xl border border-slate-200/80 dark:border-slate-700/70 shadow-2xl backdrop-blur ${cardBackground || "bg-white/95 dark:bg-slate-900/90"}`; return ( <div className={wrapperClass}> @@ -346,7 +403,12 @@ export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ time = targetDate; } - onSearch(origin, destination, time, timeMode === "arrive"); + await onSearch( + origin, + destination, + time, + timeMode === "arrive" + ); // After search, if origin was current location, switch to reverse-geocoded address if ( @@ -492,7 +554,7 @@ export const PlannerOverlay: React.FC<PlannerOverlayProps> = ({ <li className="border-t border-slate-100 dark:border-slate-700 px-4 py-2 text-xs font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 bg-slate-50 dark:bg-slate-800/70"> {remoteLoading ? t("planner.searching_ellipsis") - : t("planner.results")} + : t("planner.results", "Results")} </li> )} {remoteResults.map((r, i) => ( diff --git a/src/frontend/app/components/layout/NavBar.module.css b/src/frontend/app/components/layout/NavBar.module.css index ddace40..19d0a93 100644 --- a/src/frontend/app/components/layout/NavBar.module.css +++ b/src/frontend/app/components/layout/NavBar.module.css @@ -5,7 +5,6 @@ padding: 0.5rem 0; background-color: var(--background-color); - border-top: 1px solid var(--border-color); max-width: 48rem; margin-inline: auto; diff --git a/src/frontend/app/components/layout/NavBar.tsx b/src/frontend/app/components/layout/NavBar.tsx index 69b3a63..9c42987 100644 --- a/src/frontend/app/components/layout/NavBar.tsx +++ b/src/frontend/app/components/layout/NavBar.tsx @@ -1,7 +1,8 @@ import { Home, Map, Navigation2, Route } from "lucide-react"; import type { LngLatLike } from "maplibre-gl"; import { useTranslation } from "react-i18next"; -import { Link, useLocation } from "react-router"; +import { Link, useLocation, useNavigate } from "react-router"; +import { usePlanner } from "~/hooks/usePlanner"; import { useApp } from "../../AppContext"; import styles from "./NavBar.module.css"; @@ -28,6 +29,8 @@ export default function NavBar({ orientation = "horizontal" }: NavBarProps) { const { t } = useTranslation(); const { mapState, updateMapState, mapPositionMode } = useApp(); const location = useLocation(); + const navigate = useNavigate(); + const { deselectItinerary } = usePlanner(); const navItems = [ { @@ -94,8 +97,18 @@ export default function NavBar({ orientation = "horizontal" }: NavBarProps) { <Link key={item.name} to={item.path} - className={`${styles.link} ${isActive ? styles.active : ""}`} - onClick={item.callback ? item.callback : undefined} + className={`${styles.link} ${isActive ? styles.active : ""}${item.path === "/planner" ? " planner-nav-link" : ""}`} + onClick={(e) => { + if ( + item.path === "/planner" && + location.pathname === "/planner" + ) { + deselectItinerary(); + window.location.reload(); + } else if (item.callback) { + item.callback(); + } + }} title={item.name} aria-label={item.name} > |
