From 899316d5f865b5747a7f99ea1ac4b4ffbc2381d4 Mon Sep 17 00:00:00 2001 From: Ida Rogalska Date: Tue, 11 Aug 2026 19:13:37 +0200 Subject: [PATCH] client: add resolveLegMode helper for endpoint-aware leg modes --- client/src/components/Planner/legMode.test.ts | 30 +++++++++++++++++++ client/src/components/Planner/legMode.ts | 22 ++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 client/src/components/Planner/legMode.test.ts create mode 100644 client/src/components/Planner/legMode.ts diff --git a/client/src/components/Planner/legMode.test.ts b/client/src/components/Planner/legMode.test.ts new file mode 100644 index 000000000..ddeb31db4 --- /dev/null +++ b/client/src/components/Planner/legMode.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect } from 'vitest'; +import { resolveLegMode } from './legMode'; + +const P = (o?: Partial<{ leg_transport_mode: string | null; incoming_leg_transport_mode: string | null }>) => + ({ isPlace: true, ...o }); +const B = () => ({ isPlace: false }); + +describe('resolveLegMode', () => { + it('origin place with outgoing mode wins', () => { + expect(resolveLegMode(P({ leg_transport_mode: 'cycling' }), P(), 'walking')).toBe('cycling'); + }); + it('origin place, no override -> day default', () => { + expect(resolveLegMode(P(), P(), 'driving')).toBe('driving'); + }); + it('non-place origin -> destination incoming override', () => { + expect(resolveLegMode(B(), P({ incoming_leg_transport_mode: 'transit' }), 'walking')).toBe('transit'); + }); + it('non-place origin, no incoming override -> day default', () => { + expect(resolveLegMode(B(), P(), 'walking')).toBe('walking'); + }); + it('no place endpoint at all -> day default', () => { + expect(resolveLegMode(B(), B(), 'walking')).toBe('walking'); + }); + it('incoming is inert when origin is a place', () => { + expect(resolveLegMode(P(), P({ incoming_leg_transport_mode: 'transit' }), 'walking')).toBe('walking'); + }); + it('undefined dest falls back to day default for a non-place origin', () => { + expect(resolveLegMode(B(), undefined, 'walking')).toBe('walking'); + }); +}); diff --git a/client/src/components/Planner/legMode.ts b/client/src/components/Planner/legMode.ts new file mode 100644 index 000000000..15c813d12 --- /dev/null +++ b/client/src/components/Planner/legMode.ts @@ -0,0 +1,22 @@ +export type LegPoint = { + isPlace: boolean; + leg_transport_mode?: string | null; + incoming_leg_transport_mode?: string | null; +}; + +/** + * Travel mode of the leg from `origin` to `dest`. The mode is owned by the leg's + * place endpoint: the origin's outgoing override wins when the origin is a place; + * otherwise the destination's incoming override applies (only meaningful when the + * origin is not a place - a booking arrival or the morning hotel); otherwise the + * day default. The incoming value is inert whenever the origin is a place. + */ +export function resolveLegMode( + origin: LegPoint, + dest: LegPoint | undefined, + dayDefault: string, +): string { + if (origin.isPlace) return origin.leg_transport_mode ?? dayDefault; + if (dest?.isPlace) return dest.incoming_leg_transport_mode ?? dayDefault; + return dayDefault; +}