-
-
- {[
- { value: true, label: t('settings.on') || 'On' },
- { value: false, label: t('settings.off') || 'Off' },
- ].map(opt => (
-
- ))}
-
-
-
{/* Booking route labels */}
diff --git a/client/src/hooks/useRouteCalculation.ts b/client/src/hooks/useRouteCalculation.ts
index 13c15058..142b8168 100644
--- a/client/src/hooks/useRouteCalculation.ts
+++ b/client/src/hooks/useRouteCalculation.ts
@@ -1,5 +1,4 @@
import { useState, useCallback, useRef, useEffect, useMemo } from 'react'
-import { useSettingsStore } from '../store/settingsStore'
import { useTripStore } from '../store/tripStore'
import { calculateRouteWithLegs } from '../components/Map/RouteCalculator'
import type { TripStoreState } from '../store/tripStore'
@@ -9,14 +8,13 @@ const TRANSPORT_TYPES = ['flight', 'train', 'bus', 'car', 'cruise']
/**
* Manages route calculation state for a selected day. Extracts geo-coded waypoints from
- * day assignments, draws a straight-line route, and optionally fetches per-segment
- * driving/walking durations via OSRM. Aborts in-flight requests when the day changes.
+ * day assignments, draws a straight-line route immediately, then upgrades it to real OSRM
+ * road geometry with per-segment durations. Aborts in-flight requests when the day changes.
*/
export function useRouteCalculation(tripStore: TripStoreState, selectedDayId: number | null, enabled: boolean = true, profile: 'driving' | 'walking' | 'cycling' = 'driving') {
const [route, setRoute] = useState<[number, number][][] | null>(null)
const [routeInfo, setRouteInfo] = useState
(null)
const [routeSegments, setRouteSegments] = useState([])
- const routeCalcEnabled = useSettingsStore((s) => s.settings.route_calculation) !== false
const routeAbortRef = useRef(null)
const reservationsForSignature = useTripStore((s) => s.reservations)
@@ -88,9 +86,8 @@ export function useRouteCalculation(tripStore: TripStoreState, selectedDayId: nu
if (runs.length === 0) { setRoute(null); setRouteSegments([]); return }
// Draw straight lines immediately for snappiness, then upgrade to the real
- // OSRM road geometry. If route calc is disabled, keep the straight lines.
+ // OSRM road geometry.
setRoute(straightLines())
- if (!routeCalcEnabled) { setRouteSegments([]); return }
const controller = new AbortController()
routeAbortRef.current = controller
@@ -113,7 +110,7 @@ export function useRouteCalculation(tripStore: TripStoreState, selectedDayId: nu
// Aborted (day changed) — newer call owns the state. Anything else: keep straight lines.
if (!(err instanceof Error) || err.name !== 'AbortError') setRouteSegments([])
}
- }, [routeCalcEnabled, enabled, profile])
+ }, [enabled, profile])
// Stable signature for transport reservations on the selected day — changes when a transport
// is added, removed, or repositioned, ensuring route recalc fires even on transport-only reorders.
diff --git a/client/src/i18n/translations/ar.ts b/client/src/i18n/translations/ar.ts
index c9a54cec..5e81722e 100644
--- a/client/src/i18n/translations/ar.ts
+++ b/client/src/i18n/translations/ar.ts
@@ -200,7 +200,6 @@ const ar: Record = {
'settings.language': 'اللغة',
'settings.temperature': 'وحدة الحرارة',
'settings.timeFormat': 'تنسيق الوقت',
- 'settings.routeCalculation': 'حساب المسار',
'settings.blurBookingCodes': 'إخفاء رموز الحجز',
'settings.notifications': 'الإشعارات',
'settings.notifyTripInvite': 'دعوات الرحلات',
diff --git a/client/src/i18n/translations/br.ts b/client/src/i18n/translations/br.ts
index 7fa534c1..637285d5 100644
--- a/client/src/i18n/translations/br.ts
+++ b/client/src/i18n/translations/br.ts
@@ -195,7 +195,6 @@ const br: Record = {
'settings.language': 'Idioma',
'settings.temperature': 'Unidade de temperatura',
'settings.timeFormat': 'Formato de hora',
- 'settings.routeCalculation': 'Cálculo de rota',
'settings.blurBookingCodes': 'Ocultar códigos de reserva',
'settings.notifications': 'Notificações',
'settings.notifyTripInvite': 'Convites de viagem',
diff --git a/client/src/i18n/translations/cs.ts b/client/src/i18n/translations/cs.ts
index 92ea45b9..fbc035d6 100644
--- a/client/src/i18n/translations/cs.ts
+++ b/client/src/i18n/translations/cs.ts
@@ -196,7 +196,6 @@ const cs: Record = {
'settings.language': 'Jazyk',
'settings.temperature': 'Jednotky teploty',
'settings.timeFormat': 'Formát času',
- 'settings.routeCalculation': 'Výpočet trasy',
'settings.blurBookingCodes': 'Skrýt rezervační kódy',
'settings.notifications': 'Oznámení',
'settings.notifyTripInvite': 'Pozvánky na cesty',
diff --git a/client/src/i18n/translations/de.ts b/client/src/i18n/translations/de.ts
index a1399ed4..5fd4823a 100644
--- a/client/src/i18n/translations/de.ts
+++ b/client/src/i18n/translations/de.ts
@@ -198,7 +198,6 @@ const de: Record = {
'settings.language': 'Sprache',
'settings.temperature': 'Temperatureinheit',
'settings.timeFormat': 'Zeitformat',
- 'settings.routeCalculation': 'Routenberechnung',
'settings.bookingLabels': 'Orts-Labels auf Buchungsrouten',
'settings.bookingLabelsHint': 'Zeigt Bahnhofs-/Flughafennamen auf der Karte. Wenn aus, wird nur das Icon angezeigt.',
'settings.blurBookingCodes': 'Buchungscodes verbergen',
diff --git a/client/src/i18n/translations/en.ts b/client/src/i18n/translations/en.ts
index a1c514f6..0fb72002 100644
--- a/client/src/i18n/translations/en.ts
+++ b/client/src/i18n/translations/en.ts
@@ -212,7 +212,6 @@ const en: Record = {
'settings.language': 'Language',
'settings.temperature': 'Temperature Unit',
'settings.timeFormat': 'Time Format',
- 'settings.routeCalculation': 'Route Calculation',
'settings.bookingLabels': 'Booking route labels',
'settings.bookingLabelsHint': 'Show station / airport names on the map. When off, only the icon is shown.',
'settings.blurBookingCodes': 'Blur Booking Codes',
diff --git a/client/src/i18n/translations/es.ts b/client/src/i18n/translations/es.ts
index b1865a73..70aec75f 100644
--- a/client/src/i18n/translations/es.ts
+++ b/client/src/i18n/translations/es.ts
@@ -196,7 +196,6 @@ const es: Record = {
'settings.language': 'Idioma',
'settings.temperature': 'Unidad de temperatura',
'settings.timeFormat': 'Formato de hora',
- 'settings.routeCalculation': 'Cálculo de ruta',
'settings.blurBookingCodes': 'Difuminar códigos de reserva',
'settings.notifications': 'Notificaciones',
'settings.notifyTripInvite': 'Invitaciones de viaje',
diff --git a/client/src/i18n/translations/fr.ts b/client/src/i18n/translations/fr.ts
index 8337a67c..56246dac 100644
--- a/client/src/i18n/translations/fr.ts
+++ b/client/src/i18n/translations/fr.ts
@@ -195,7 +195,6 @@ const fr: Record = {
'settings.language': 'Langue',
'settings.temperature': 'Unité de température',
'settings.timeFormat': 'Format de l\'heure',
- 'settings.routeCalculation': 'Calcul d\'itinéraire',
'settings.blurBookingCodes': 'Masquer les codes de réservation',
'settings.notifications': 'Notifications',
'settings.notifyTripInvite': 'Invitations de voyage',
diff --git a/client/src/i18n/translations/hu.ts b/client/src/i18n/translations/hu.ts
index 18450c69..9f365430 100644
--- a/client/src/i18n/translations/hu.ts
+++ b/client/src/i18n/translations/hu.ts
@@ -195,7 +195,6 @@ const hu: Record = {
'settings.language': 'Nyelv',
'settings.temperature': 'Hőmérséklet egység',
'settings.timeFormat': 'Időformátum',
- 'settings.routeCalculation': 'Útvonalszámítás',
'settings.blurBookingCodes': 'Foglalási kódok elrejtése',
'settings.notifications': 'Értesítések',
'settings.notifyTripInvite': 'Utazási meghívók',
diff --git a/client/src/i18n/translations/id.ts b/client/src/i18n/translations/id.ts
index 283c4e88..f1807dc0 100644
--- a/client/src/i18n/translations/id.ts
+++ b/client/src/i18n/translations/id.ts
@@ -198,7 +198,6 @@ const id: Record = {
'settings.language': 'Bahasa',
'settings.temperature': 'Satuan Suhu',
'settings.timeFormat': 'Format Waktu',
- 'settings.routeCalculation': 'Perhitungan Rute',
'settings.blurBookingCodes': 'Sembunyikan Kode Pemesanan',
'settings.notifications': 'Notifikasi',
'settings.notifyTripInvite': 'Undangan perjalanan',
diff --git a/client/src/i18n/translations/it.ts b/client/src/i18n/translations/it.ts
index 3e6aeae7..d4b0d59d 100644
--- a/client/src/i18n/translations/it.ts
+++ b/client/src/i18n/translations/it.ts
@@ -195,7 +195,6 @@ const it: Record = {
'settings.language': 'Lingua',
'settings.temperature': 'Unità di Temperatura',
'settings.timeFormat': 'Formato Ora',
- 'settings.routeCalculation': 'Calcolo Percorso',
'settings.blurBookingCodes': 'Nascondi codici di prenotazione',
'settings.notifications': 'Notifiche',
'settings.notifyTripInvite': 'Inviti di viaggio',
diff --git a/client/src/i18n/translations/ja.ts b/client/src/i18n/translations/ja.ts
index 51eb31b4..a431db16 100644
--- a/client/src/i18n/translations/ja.ts
+++ b/client/src/i18n/translations/ja.ts
@@ -212,7 +212,6 @@ const ja: Record = {
'settings.language': '言語',
'settings.temperature': '温度単位',
'settings.timeFormat': '時刻形式',
- 'settings.routeCalculation': '経路計算',
'settings.bookingLabels': '予約ルートのラベル',
'settings.bookingLabelsHint': '地図に駅・空港名を表示。オフ時はアイコンのみ。',
'settings.blurBookingCodes': '予約コードをぼかす',
diff --git a/client/src/i18n/translations/ko.ts b/client/src/i18n/translations/ko.ts
index 82a8dfc0..c3a4849f 100644
--- a/client/src/i18n/translations/ko.ts
+++ b/client/src/i18n/translations/ko.ts
@@ -212,7 +212,6 @@ const ko: Record = {
'settings.language': '언어',
'settings.temperature': '온도 단위',
'settings.timeFormat': '시간 형식',
- 'settings.routeCalculation': '경로 계산',
'settings.bookingLabels': '예약 경로 레이블',
'settings.bookingLabelsHint': '지도에 역 / 공항 이름을 표시합니다. 끄면 아이콘만 표시됩니다.',
'settings.blurBookingCodes': '예약 코드 흐리게',
diff --git a/client/src/i18n/translations/nl.ts b/client/src/i18n/translations/nl.ts
index 93694977..57af57ae 100644
--- a/client/src/i18n/translations/nl.ts
+++ b/client/src/i18n/translations/nl.ts
@@ -195,7 +195,6 @@ const nl: Record = {
'settings.language': 'Taal',
'settings.temperature': 'Temperatuureenheid',
'settings.timeFormat': 'Tijdnotatie',
- 'settings.routeCalculation': 'Routeberekening',
'settings.blurBookingCodes': 'Boekingscodes vervagen',
'settings.notifications': 'Meldingen',
'settings.notifyTripInvite': 'Reisuitnodigingen',
diff --git a/client/src/i18n/translations/pl.ts b/client/src/i18n/translations/pl.ts
index 205ccaab..ce085b8f 100644
--- a/client/src/i18n/translations/pl.ts
+++ b/client/src/i18n/translations/pl.ts
@@ -178,7 +178,6 @@ const pl: Record = {
'settings.language': 'Język',
'settings.temperature': 'Jednostka temperatury',
'settings.timeFormat': 'Format czasu',
- 'settings.routeCalculation': 'Obliczanie trasy',
'settings.blurBookingCodes': 'Rozmyj kody rezerwacji',
'settings.notifications': 'Powiadomienia',
'settings.notifyTripInvite': 'Zaproszenia do podróży',
diff --git a/client/src/i18n/translations/ru.ts b/client/src/i18n/translations/ru.ts
index 75b2141c..967f5d3a 100644
--- a/client/src/i18n/translations/ru.ts
+++ b/client/src/i18n/translations/ru.ts
@@ -195,7 +195,6 @@ const ru: Record = {
'settings.language': 'Язык',
'settings.temperature': 'Единица температуры',
'settings.timeFormat': 'Формат времени',
- 'settings.routeCalculation': 'Расчёт маршрута',
'settings.blurBookingCodes': 'Скрыть коды бронирования',
'settings.notifications': 'Уведомления',
'settings.notifyTripInvite': 'Приглашения в поездку',
diff --git a/client/src/i18n/translations/tr.ts b/client/src/i18n/translations/tr.ts
index f359f84d..d2637fb0 100644
--- a/client/src/i18n/translations/tr.ts
+++ b/client/src/i18n/translations/tr.ts
@@ -212,7 +212,6 @@ const tr: Record = {
'settings.language': 'Dil',
'settings.temperature': 'Sıcaklık birimi',
'settings.timeFormat': 'Saat biçimi',
- 'settings.routeCalculation': 'Route Calculation',
'settings.bookingLabels': 'Booking route labels',
'settings.bookingLabelsHint': 'Show station / airport names on the map. When off, only the icon is shown.',
'settings.blurBookingCodes': 'Blur Booking Codes',
diff --git a/client/src/i18n/translations/uk.ts b/client/src/i18n/translations/uk.ts
index 433016f6..01eb0609 100644
--- a/client/src/i18n/translations/uk.ts
+++ b/client/src/i18n/translations/uk.ts
@@ -209,7 +209,6 @@ const uk: Record = {
'settings.language': 'Мова',
'settings.temperature': 'Одиниця температури',
'settings.timeFormat': 'Формат часу',
- 'settings.routeCalculation': 'Розрахунок маршруту',
'settings.blurBookingCodes': 'Приховати коди бронювання',
'settings.notifications': 'Сповіщення',
'settings.notifyTripInvite': 'Запрошення до поїздки',
diff --git a/client/src/i18n/translations/zh.ts b/client/src/i18n/translations/zh.ts
index 5c8f4979..20b0e80f 100644
--- a/client/src/i18n/translations/zh.ts
+++ b/client/src/i18n/translations/zh.ts
@@ -195,7 +195,6 @@ const zh: Record = {
'settings.language': '语言',
'settings.temperature': '温度单位',
'settings.timeFormat': '时间格式',
- 'settings.routeCalculation': '路线计算',
'settings.blurBookingCodes': '模糊预订代码',
'settings.notifications': '通知',
'settings.notifyTripInvite': '旅行邀请',
diff --git a/client/src/i18n/translations/zhTw.ts b/client/src/i18n/translations/zhTw.ts
index 695eb974..b89ce88f 100644
--- a/client/src/i18n/translations/zhTw.ts
+++ b/client/src/i18n/translations/zhTw.ts
@@ -195,7 +195,6 @@ const zhTw: Record = {
'settings.language': '語言',
'settings.temperature': '溫度單位',
'settings.timeFormat': '時間格式',
- 'settings.routeCalculation': '路線計算',
'settings.blurBookingCodes': '模糊預訂程式碼',
'settings.notifications': '通知',
'settings.notifyTripInvite': '旅行邀請',
diff --git a/client/src/pages/DashboardPage.test.tsx b/client/src/pages/DashboardPage.test.tsx
index 2a3530ee..9e26acaf 100644
--- a/client/src/pages/DashboardPage.test.tsx
+++ b/client/src/pages/DashboardPage.test.tsx
@@ -857,7 +857,6 @@ describe('DashboardPage', () => {
temperature_unit: 'fahrenheit',
time_format: '12h',
show_place_description: false,
- route_calculation: false,
blur_booking_codes: false,
dashboard_currency: 'on',
dashboard_timezone: 'on',
diff --git a/client/src/pages/TripPlannerPage.tsx b/client/src/pages/TripPlannerPage.tsx
index f314bea8..27826347 100644
--- a/client/src/pages/TripPlannerPage.tsx
+++ b/client/src/pages/TripPlannerPage.tsx
@@ -830,7 +830,7 @@ export default function TripPlannerPage(): React.ReactElement | null {
hasInspector={!!selectedPlace}
hasDayDetail={!!showDayDetail && !selectedPlace}
reservations={reservations}
- showReservationStats={settings.route_calculation !== false}
+ showReservationStats={true}
visibleConnectionIds={visibleConnections}
onReservationClick={(rid) => {
const r = reservations.find(x => x.id === rid)
diff --git a/client/src/types.ts b/client/src/types.ts
index 0886ddf6..4572c558 100644
--- a/client/src/types.ts
+++ b/client/src/types.ts
@@ -215,7 +215,6 @@ export interface Settings {
temperature_unit: string
time_format: string
show_place_description: boolean
- route_calculation?: boolean
blur_booking_codes?: boolean
map_booking_labels?: boolean
map_provider?: 'leaflet' | 'mapbox-gl'
diff --git a/client/tests/helpers/factories.ts b/client/tests/helpers/factories.ts
index 8bc8b468..835518ff 100644
--- a/client/tests/helpers/factories.ts
+++ b/client/tests/helpers/factories.ts
@@ -258,7 +258,6 @@ export function buildSettings(overrides: Partial = {}): Settings {
temperature_unit: 'fahrenheit',
time_format: '12h',
show_place_description: false,
- route_calculation: false,
blur_booking_codes: false,
...overrides,
};
diff --git a/client/tests/integration/hooks/useRouteCalculation.test.ts b/client/tests/integration/hooks/useRouteCalculation.test.ts
index 18fc38d1..125b39ba 100644
--- a/client/tests/integration/hooks/useRouteCalculation.test.ts
+++ b/client/tests/integration/hooks/useRouteCalculation.test.ts
@@ -1,7 +1,6 @@
import { renderHook, act } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { useRouteCalculation } from '../../../src/hooks/useRouteCalculation';
-import { useSettingsStore } from '../../../src/store/settingsStore';
import { useTripStore } from '../../../src/store/tripStore';
import { buildAssignment, buildPlace } from '../../helpers/factories';
import type { TripStoreState } from '../../../src/store/tripStore';
@@ -47,8 +46,6 @@ const MOCK_ROUTE_WITH_LEGS = {
describe('useRouteCalculation', () => {
beforeEach(() => {
vi.clearAllMocks();
- // Default: route_calculation disabled
- useSettingsStore.setState({ settings: { route_calculation: false } as any });
// Reset trip store assignments so each test starts clean
useTripStore.setState({ assignments: {} } as any);
(calculateRouteWithLegs as ReturnType).mockResolvedValue(MOCK_ROUTE_WITH_LEGS);
@@ -93,9 +90,7 @@ describe('useRouteCalculation', () => {
]);
});
- it('FE-HOOK-ROUTE-004: with route_calculation enabled, calls calculateRouteWithLegs', async () => {
- useSettingsStore.setState({ settings: { route_calculation: true } as any });
-
+ it('FE-HOOK-ROUTE-004: calls calculateRouteWithLegs and exposes the returned segments', async () => {
const p1 = buildPlace({ lat: 48.8566, lng: 2.3522 });
const p2 = buildPlace({ lat: 51.5074, lng: -0.1278 });
const a1 = buildAssignment({ day_id: 5, order_index: 0, place: p1 });
@@ -112,28 +107,7 @@ describe('useRouteCalculation', () => {
expect(result.current.routeSegments).toEqual(MOCK_SEGMENTS);
});
- it('FE-HOOK-ROUTE-005: with route_calculation disabled, does not call calculateRouteWithLegs', async () => {
- useSettingsStore.setState({ settings: { route_calculation: false } as any });
-
- const p1 = buildPlace({ lat: 48.8566, lng: 2.3522 });
- const p2 = buildPlace({ lat: 51.5074, lng: -0.1278 });
- const a1 = buildAssignment({ day_id: 5, order_index: 0, place: p1 });
- const a2 = buildAssignment({ day_id: 5, order_index: 1, place: p2 });
- const store = buildMockStore({ '5': [a1, a2] });
-
- const { result } = renderHook(() =>
- useRouteCalculation(store as TripStoreState, 5)
- );
-
- await act(async () => {});
-
- expect(calculateRouteWithLegs).not.toHaveBeenCalled();
- expect(result.current.routeSegments).toEqual([]);
- });
-
it('FE-HOOK-ROUTE-006: assignments are sorted by order_index before extracting waypoints', async () => {
- useSettingsStore.setState({ settings: { route_calculation: true } as any });
-
const p1 = buildPlace({ lat: 10, lng: 10 });
const p2 = buildPlace({ lat: 20, lng: 20 });
// order_index 1 comes before 0 in the array, but should be sorted
@@ -170,7 +144,6 @@ describe('useRouteCalculation', () => {
});
it('FE-HOOK-ROUTE-008: AbortController.abort() is called when selectedDayId changes', async () => {
- useSettingsStore.setState({ settings: { route_calculation: true } as any });
// Make calculateRouteWithLegs resolve slowly
let resolveSegments!: (val: typeof MOCK_ROUTE_WITH_LEGS) => void;
@@ -209,7 +182,6 @@ describe('useRouteCalculation', () => {
});
it('FE-HOOK-ROUTE-009: AbortError from calculateSegments does not set routeSegments to []', async () => {
- useSettingsStore.setState({ settings: { route_calculation: true } as any });
const abortError = new Error('Aborted');
abortError.name = 'AbortError';
@@ -231,7 +203,6 @@ describe('useRouteCalculation', () => {
});
it('FE-HOOK-ROUTE-010: non-AbortError from calculateSegments sets routeSegments to []', async () => {
- useSettingsStore.setState({ settings: { route_calculation: true } as any });
(calculateRouteWithLegs as ReturnType).mockRejectedValueOnce(new Error('Network error'));
@@ -282,7 +253,6 @@ describe('useRouteCalculation', () => {
});
it('FE-HOOK-ROUTE-013: route recalculates when assignments change via store update', async () => {
- useSettingsStore.setState({ settings: { route_calculation: true } as any });
const p1 = buildPlace({ lat: 10, lng: 10 });
const p2 = buildPlace({ lat: 20, lng: 20 });
diff --git a/server/src/services/settingsService.ts b/server/src/services/settingsService.ts
index 57f0e6c0..c1ccf9b3 100644
--- a/server/src/services/settingsService.ts
+++ b/server/src/services/settingsService.ts
@@ -10,7 +10,6 @@ export const DEFAULTABLE_USER_SETTING_KEYS = [
'temperature_unit',
'dark_mode',
'time_format',
- 'route_calculation',
'blur_booking_codes',
'map_tile_url',
] as const;
@@ -23,7 +22,7 @@ const VALID_VALUES: Partial> = {
dark_mode: [true, false, 'light', 'dark', 'auto'],
};
-const BOOLEAN_KEYS = new Set(['route_calculation', 'blur_booking_codes']);
+const BOOLEAN_KEYS = new Set(['blur_booking_codes']);
function parseValue(raw: string): unknown {
try { return JSON.parse(raw); } catch { return raw; }