(null)
@@ -105,6 +106,7 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
setTitle(res.title || '')
setNotes(res.notes || '')
setEditingTitle(false)
+ setNotesTab(res.notes ? 'preview' : 'write')
}, [res.id])
useEffect(() => { if (editingTitle) titleInputRef.current?.focus() }, [editingTitle])
diff --git a/client/src/components/Planner/TransitSearchPanel.tsx b/client/src/components/Planner/TransitSearchPanel.tsx
index fe6acad7b..ae219e987 100644
--- a/client/src/components/Planner/TransitSearchPanel.tsx
+++ b/client/src/components/Planner/TransitSearchPanel.tsx
@@ -26,6 +26,7 @@ interface TransitLeg {
mode: string; from: TransitLegStop; to: TransitLegStop; duration: number; distance: number | null
headsign: string | null; line: string | null; lineColor: string | null; lineTextColor: string | null
agency: string | null; intermediateStops: number
+ geometry?: string | null; geometryPrecision?: number
}
export interface TransitItinerary {
startTime: string; endTime: string; duration: number; transfers: number; walkSeconds: number; legs: TransitLeg[]
@@ -370,7 +371,18 @@ export default function TransitSearchPanel({ day, days, places, accommodations =
const allModes = activeModes.size === MODE_GROUPS.length
const modes = allModes ? undefined : MODE_GROUPS.filter(m => activeModes.has(m.key)).map(m => m.modes).join(',')
const d = await transitApi.plan({ from: `${from.lat},${from.lng}`, to: `${to.lat},${to.lng}`, time: timeIso, arriveBy, modes })
- setItineraries(d.itineraries || [])
+ // MOTIS names the request coordinates START/END — swap in the places the
+ // user actually picked so walks read "Walk to Zoologischer Garten".
+ const cleanStop = (n: string) => (n === 'START' ? from.name : n === 'END' ? to.name : n)
+ const cleaned = (d.itineraries || []).map((it: TransitItinerary) => ({
+ ...it,
+ legs: it.legs.map(l => ({
+ ...l,
+ from: { ...l.from, name: cleanStop(l.from.name) },
+ to: { ...l.to, name: cleanStop(l.to.name) },
+ })),
+ }))
+ setItineraries(cleaned)
} catch {
toast.error(t('transit.searchError'))
setItineraries([])
@@ -444,6 +456,8 @@ export default function TransitSearchPanel({ day, days, places, accommodations =
stops: l.intermediateStops,
from: { name: l.from.name, time: l.from.time ? timeHHmmInTz(l.from.time, tzAt(l.from.lat, l.from.lng)) : null, track: l.from.track },
to: { name: l.to.name, time: l.to.time ? timeHHmmInTz(l.to.time, tzAt(l.to.lat, l.to.lng)) : null, track: l.to.track },
+ geometry: l.geometry || null,
+ geometry_precision: l.geometryPrecision ?? 6,
})),
},
},
diff --git a/client/src/components/Planner/transitDisplay.tsx b/client/src/components/Planner/transitDisplay.tsx
index 9a9cdb48e..2fb8a4093 100644
--- a/client/src/components/Planner/transitDisplay.tsx
+++ b/client/src/components/Planner/transitDisplay.tsx
@@ -32,7 +32,7 @@ export function TransitWalkDivider({ leg, t, size = 'md' }: {
size?: 'sm' | 'md'
}) {
const mins = leg.duration ? Math.round(leg.duration / 60) : null
- const ruleStyle: React.CSSProperties = { flex: 1, borderTop: '1px dashed var(--border-primary)', opacity: 0.6, minWidth: 12 }
+ const ruleStyle: React.CSSProperties = { flex: 1, borderTop: '1.5px dashed var(--text-faint)', opacity: 0.75, minWidth: 12 }
return (
diff --git a/server/src/services/transitService.ts b/server/src/services/transitService.ts
index 8bf13fa2b..1dfe7b527 100644
--- a/server/src/services/transitService.ts
+++ b/server/src/services/transitService.ts
@@ -129,6 +129,9 @@ export interface TransitLeg {
lineTextColor: string | null;
agency: string | null;
intermediateStops: number;
+ /** Encoded polyline of the leg's real path (Google encoding) + its precision. */
+ geometry: string | null;
+ geometryPrecision: number;
}
export interface TransitItinerary {
@@ -216,6 +219,7 @@ export async function plan(q: PlanQuery): Promise<{ itineraries: TransitItinerar
routeShortName?: string; displayName?: string; routeColor?: string; routeTextColor?: string;
agencyName?: string; from?: MotisPlaceRaw; to?: MotisPlaceRaw;
intermediateStops?: unknown[];
+ legGeometry?: { points?: string; precision?: number };
}>;
}>;
};
@@ -234,6 +238,8 @@ export async function plan(q: PlanQuery): Promise<{ itineraries: TransitItinerar
lineTextColor: safeColor(leg.routeTextColor),
agency: leg.agencyName || null,
intermediateStops: Array.isArray(leg.intermediateStops) ? leg.intermediateStops.length : 0,
+ geometry: leg.legGeometry?.points || null,
+ geometryPrecision: leg.legGeometry?.precision ?? 6,
}));
const walkSeconds = legs.filter((l) => l.mode === 'WALK').reduce((a, l) => a + l.duration, 0);
return [{