From 61880ce7d6b35097c7a1ac9d56ec35ee578b8655 Mon Sep 17 00:00:00 2001 From: Maurice Date: Sun, 13 Sep 2026 23:14:00 +0200 Subject: [PATCH] fix(roadtrip): the vias, the alternatives, the pacing and the missing warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Choosing another road on a leg that already carried a via appended the new point behind the old one, so the day drove south to the first and north to the second: a zigzag matching neither the line drawn under the button nor the distance printed on it. The alternatives are computed for the two bare endpoints, so the write has to replace the leg, which is what the direct branch beside it already did. A day's vias were only loaded while road-trip mode was being looked at, and the three handlers that re-anchor them after a stop is added, removed or reordered are reachable from the place inspector in both modes. With the switch off they computed their correction from an empty list and wrote nothing, so a deleted stop left the detour on a leg nobody chose, for the traveller and for every collaborator. They are loaded whenever the addon is on now. Seam routing paced itself by sleeping after each request, and storing a result shortened the key its own effect depends on: React tore the effect down mid-sleep, the cleanup aborted it, and the next request went out immediately. Thirteen seams left at round-trip speed, the shared routing hosts refused the tail, and a refused seam changes no state so nothing ever retried it. The wait now happens before the request, against a clock that outlives the effect. The "avoidance not honoured" badge could never appear on the rail: the field behind it was published every round and never written. Only the second engine reports what it achieved against what was asked, and the rail plans in the browser, so it never saw the server's own copy — a motorway crossing read as a motorway-free drive. Two smaller ones. `trip.toast.loadError` has been called since the first commit and exists in no locale, so both call sites printed the key itself; it is written now in all 23. And the phone shell honoured the road-trip session flag while having no rail, no drive lines and no switch to leave it, so narrowing a desktop window took the trip overview away and listed every booked night twice. --- .../components/Roadtrip/useRoadtripRoutes.ts | 31 +++++++++++- .../useTripPlanner.roadtrip.test.tsx | 10 ++-- .../src/pages/tripPlanner/useTripPlanner.ts | 49 +++++++++++++++---- shared/src/i18n/ar/trip.ts | 1 + shared/src/i18n/br/trip.ts | 1 + shared/src/i18n/ca/trip.ts | 1 + shared/src/i18n/cs/trip.ts | 1 + shared/src/i18n/de/trip.ts | 1 + shared/src/i18n/en/trip.ts | 1 + shared/src/i18n/es/trip.ts | 1 + shared/src/i18n/fr/trip.ts | 1 + shared/src/i18n/gr/trip.ts | 1 + shared/src/i18n/hu/trip.ts | 1 + shared/src/i18n/id/trip.ts | 1 + shared/src/i18n/it/trip.ts | 1 + shared/src/i18n/ja/trip.ts | 1 + shared/src/i18n/ko/trip.ts | 1 + shared/src/i18n/nl/trip.ts | 1 + shared/src/i18n/pl/trip.ts | 1 + shared/src/i18n/ru/trip.ts | 1 + shared/src/i18n/sv/trip.ts | 1 + shared/src/i18n/tr/trip.ts | 1 + shared/src/i18n/uk/trip.ts | 1 + shared/src/i18n/vi/trip.ts | 1 + shared/src/i18n/zh-TW/trip.ts | 1 + shared/src/i18n/zh/trip.ts | 1 + 26 files changed, 99 insertions(+), 14 deletions(-) diff --git a/client/src/components/Roadtrip/useRoadtripRoutes.ts b/client/src/components/Roadtrip/useRoadtripRoutes.ts index 928e96596..62dcd5d0f 100644 --- a/client/src/components/Roadtrip/useRoadtripRoutes.ts +++ b/client/src/components/Roadtrip/useRoadtripRoutes.ts @@ -332,6 +332,20 @@ export function useRoadtripRoutes( if (s) daySnaps[stopKey(stop)] = s }) } + // What was asked for against what the road turned out to be. Only + // the second engine reports it, and only when it answered: an OSRM + // fallback leaves `avoidance` absent, which is the honest reading + // of "the weighting never happened". Collected here because the + // rail plans in the browser and never sees the server's own copy + // of this field — without it the "not honoured" badge could not + // appear at all, and a motorway-free drive that is not one read as + // if the setting had held. + if (r.avoidance) { + const missed = r.avoidance.asked.filter(cls => !r.avoidance!.achieved.includes(cls)) + if (missed.length) { + collectedMisses[day.dayId] = [...new Set([...(collectedMisses[day.dayId] ?? []), ...missed])] + } + } Object.assign(dayLegs, foldRouteRun(run, stopAt, r, mode)) return } catch (err) { @@ -443,6 +457,8 @@ export function useRoadtripRoutes( return out }, [chains, plan, quietDays, window, legsByDay, seamLegs, viasByDay, connectDays]) const seamKey = seams.map(s => `${legKey(s.from, s.to)}#${seamShape(s.from, viasByDay)}`).join(';') + /** When the last seam request went out, across every run of the effect below. */ + const lastSeamRequestAt = useRef(0) useEffect(() => { if (!seams.length) return @@ -450,6 +466,20 @@ export function useRoadtripRoutes( void (async () => { for (const seam of seams) { if (controller.signal.aborted) return + // Paced before the request, against a clock that outlives this effect. + // + // Waiting AFTER one instead spaced nothing: storing a seam changes + // seamLegs, which is a dependency of the seams memo, which shortens + // seamKey, which is this effect's first dependency — so React tore the + // effect down mid-wait, the cleanup aborted the sleep, and the next run + // fired straight away. Thirteen seams went out at round-trip speed, the + // shared routing hosts answered the tail with 429, and a refused seam + // writes no state, so nothing changed to make the effect try again: the + // map drew the trip in pieces and the totals came back short. + const since = performance.now() - lastSeamRequestAt.current + if (since < REQUEST_SPACING_MS) await sleep(REQUEST_SPACING_MS - since, controller.signal) + if (controller.signal.aborted) return + lastSeamRequestAt.current = performance.now() const mode = resolveLegMode( { isPlace: true, leg_transport_mode: seam.from.legMode }, { isPlace: true, incoming_leg_transport_mode: seam.to.incomingLegMode }, @@ -496,7 +526,6 @@ export function useRoadtripRoutes( // invented. Retried on the next run of this effect. if (controller.signal.aborted) return } - await sleep(REQUEST_SPACING_MS, controller.signal) } })() return () => controller.abort() diff --git a/client/src/pages/tripPlanner/useTripPlanner.roadtrip.test.tsx b/client/src/pages/tripPlanner/useTripPlanner.roadtrip.test.tsx index 4947af668..833343af6 100644 --- a/client/src/pages/tripPlanner/useTripPlanner.roadtrip.test.tsx +++ b/client/src/pages/tripPlanner/useTripPlanner.roadtrip.test.tsx @@ -963,7 +963,7 @@ describe('useTripPlanner road trip: other ways of driving a leg', () => { expect(rt.alt.close).not.toHaveBeenCalled() }) - it('FE-TP-ROAD-040: another road is stored as a via where it differs most, not as a polyline', async () => { + it('FE-TP-ROAD-040: another road replaces the leg it reshapes, as a via rather than a polyline', async () => { routedDay() rt.alt.open = { dayId: 5, index: 0, loading: false, error: false, @@ -973,7 +973,11 @@ describe('useTripPlanner road trip: other ways of driving a leg', () => { await act(async () => { await result.current.chooseRouteAlternative(0) }) - expect(rt.vias.add).toHaveBeenCalledWith(5, 0, 53.1, 11.9) + // Replacing, not appending: the alternatives were computed for the two bare + // endpoints, so a leg that still carries its old via routes somewhere the + // preview never drew. + expect(rt.vias.addMany).toHaveBeenCalledWith(5, [{ after_order_index: 0, lat: 53.1, lng: 11.9 }], [0]) + expect(rt.vias.add).not.toHaveBeenCalled() expect(rt.alt.close).toHaveBeenCalled() }) @@ -983,7 +987,7 @@ describe('useTripPlanner road trip: other ways of driving a leg', () => { dayId: 5, index: 0, loading: false, error: false, routes: [{ divergence: { lat: 53.1, lng: 11.9 } }], } - rt.vias.add.mockRejectedValue(new Error('rejected')) + rt.vias.addMany.mockRejectedValue(new Error('rejected')) const { result } = await renderRoadtrip() rt.alt.close.mockClear() diff --git a/client/src/pages/tripPlanner/useTripPlanner.ts b/client/src/pages/tripPlanner/useTripPlanner.ts index 0ec888c56..fd8c498d5 100644 --- a/client/src/pages/tripPlanner/useTripPlanner.ts +++ b/client/src/pages/tripPlanner/useTripPlanner.ts @@ -128,7 +128,23 @@ export function useTripPlanner() { // drive-first reading of the same trip. Per trip and per session, like the tab choice: // someone planning a road trip stays in it across reloads without it leaking into // their next, non-driving trip. - const [roadtripMode, setRoadtripMode] = useState(() => sessionStorage.getItem(`trip-roadtrip-${tripId}`) === '1') + const [storedRoadtripMode, setRoadtripMode] = useState(() => sessionStorage.getItem(`trip-roadtrip-${tripId}`) === '1') + // Declared here rather than with the other layout state further down, because + // road-trip mode is decided on it and the assignment and place lists below are + // decided on that. One subscriber for the whole hook. + const [isMobile, setIsMobile] = useState(() => window.innerWidth < 768) + useEffect(() => { + const mq = window.matchMedia('(max-width: 767px)') + const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches) + mq.addEventListener('change', handler) + return () => mq.removeEventListener('change', handler) + }, []) + // The phone shell has no road-trip surface at all: no rail, no drive lines, and + // no switch to turn the mode back off. Narrowing a desktop window past the + // phone breakpoint used to carry the flag across anyway, which took the trip + // overview pill away with nothing in its place and listed every booked night + // twice. The flag is kept, so widening the window again returns to the drive. + const roadtripMode = storedRoadtripMode && !isMobile // Two reasons a stop can be road-trip-only, and they are not the same reason. // // The switch is the traveller's: it hides the petrol stations and rest areas @@ -488,13 +504,6 @@ export function useTripPlanner() { }, [alwaysShowRoutesDefault]) const [mapTransportDetail, setMapTransportDetail] = useState(null) - const [isMobile, setIsMobile] = useState(() => window.innerWidth < 768) - useEffect(() => { - const mq = window.matchMedia('(max-width: 767px)') - const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches) - mq.addEventListener('change', handler) - return () => mq.removeEventListener('change', handler) - }, []) // Layout is width-driven (isMobile); the drag bridge is pointer-driven (isTouch). // Conflating them is what left a tablet's places list undraggable-but-unscrollable (#1432). const isTouch = useIsTouch() @@ -618,7 +627,14 @@ export function useTripPlanner() { for (const boundary of dayBoundaries.boundaries) await dayBoundaries.save(boundary.day_number, null) } catch (err: unknown) { toast.error(err instanceof Error ? err.message : t('common.unknownError')) } } : undefined - const roadtripVias = useRoadtripVias(tripId, roadtripActive) + // Fed whenever the addon is on, not only while the mode is being looked at. + // The three handlers that re-anchor a day's vias — assign, remove, reorder — + // are reachable from the place inspector in both modes, and with an empty list + // they computed an empty correction and wrote nothing while the server kept + // every via pointing at a position that had moved. Deleting a stop with the + // switch off then left the detour on the wrong leg, for the traveller and for + // a collaborator who never turned the mode on at all. + const roadtripVias = useRoadtripVias(tripId, !!enabledAddons.roadtrip) const refuel = useRefuelSearch() const roadtripRoutes = useRoadtripRoutes( tripId, @@ -1382,8 +1398,21 @@ export function useTripPlanner() { const day = roadtripRoutes.days.find(d => d.dayId === open.dayId) const stop = day?.stops[open.index] if (!day || !stop) return + const ownerDayId = stop.ownerDayId ?? day.dayId + const legIndex = stop.ownerIndex ?? open.index try { - await roadtripVias.add(stop.ownerDayId ?? day.dayId, stop.ownerIndex ?? open.index, alt.divergence.lat, alt.divergence.lng) + // Replaces the leg rather than appending to it. The alternatives under the + // button were computed for the two bare endpoints — the road already being + // driven is offered separately as `current` — so a leg that already carries + // a via cannot produce the line the preview drew. Appending put the new + // point behind the old one and routed A, south to the old via, north to the + // new one, then B: a zigzag matching neither the preview nor the distance + // printed on it. Same write the direct branch above already uses. + await roadtripVias.addMany( + ownerDayId, + [{ after_order_index: legIndex, lat: alt.divergence.lat, lng: alt.divergence.lng }], + [legIndex], + ) routeAlternatives.close() } catch (err: unknown) { toast.error(err instanceof Error ? err.message : t('common.unknownError')) diff --git a/shared/src/i18n/ar/trip.ts b/shared/src/i18n/ar/trip.ts index 80fab2148..a39c7aaea 100644 --- a/shared/src/i18n/ar/trip.ts +++ b/shared/src/i18n/ar/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'تم حذف المكان', 'trip.toast.selectDay': 'يرجى اختيار يوم أولًا', 'trip.toast.assignedToDay': 'تم إسناد المكان إلى اليوم', + 'trip.toast.loadError': 'تعذر تحميل الرحلة', 'trip.toast.reorderError': 'فشل إعادة الترتيب', 'trip.toast.reservationUpdated': 'تم تحديث الحجز', 'trip.toast.reservationAdded': 'تمت إضافة الحجز', diff --git a/shared/src/i18n/br/trip.ts b/shared/src/i18n/br/trip.ts index 48c6dbc4e..ea2cd0410 100644 --- a/shared/src/i18n/br/trip.ts +++ b/shared/src/i18n/br/trip.ts @@ -20,6 +20,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Lugar excluído', 'trip.toast.selectDay': 'Selecione um dia primeiro', 'trip.toast.assignedToDay': 'Lugar atribuído ao dia', + 'trip.toast.loadError': 'Não foi possível carregar a viagem', 'trip.toast.reorderError': 'Falha ao reordenar', 'trip.toast.reservationUpdated': 'Reserva atualizada', 'trip.toast.reservationAdded': 'Reserva adicionada', diff --git a/shared/src/i18n/ca/trip.ts b/shared/src/i18n/ca/trip.ts index caa24f908..e521ba59a 100644 --- a/shared/src/i18n/ca/trip.ts +++ b/shared/src/i18n/ca/trip.ts @@ -20,6 +20,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Lloc eliminat', 'trip.toast.selectDay': 'Selecciona un dia primer', 'trip.toast.assignedToDay': 'Lloc assignat al dia', + 'trip.toast.loadError': "No s'ha pogut carregar el viatge", 'trip.toast.reorderError': "No s'ha pogut reordenar", 'trip.toast.reservationUpdated': 'Reserva actualitzada', 'trip.toast.reservationAdded': 'Reserva afegida', diff --git a/shared/src/i18n/cs/trip.ts b/shared/src/i18n/cs/trip.ts index 5298554e3..a7131943a 100644 --- a/shared/src/i18n/cs/trip.ts +++ b/shared/src/i18n/cs/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Místo bylo smazáno', 'trip.toast.selectDay': 'Prosím nejdříve vyberte den', 'trip.toast.assignedToDay': 'Místo bylo přiřazeno ke dni', + 'trip.toast.loadError': 'Cestu se nepodařilo načíst', 'trip.toast.reorderError': 'Nepodařilo se změnit pořadí', 'trip.toast.reservationUpdated': 'Rezervace aktualizována', 'trip.toast.reservationAdded': 'Rezervace přidána', diff --git a/shared/src/i18n/de/trip.ts b/shared/src/i18n/de/trip.ts index f49779719..6c851bf1e 100644 --- a/shared/src/i18n/de/trip.ts +++ b/shared/src/i18n/de/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Ort gelöscht', 'trip.toast.selectDay': 'Bitte wähle zuerst einen Tag aus', 'trip.toast.assignedToDay': 'Ort wurde dem Tag zugewiesen', + 'trip.toast.loadError': 'Reise konnte nicht geladen werden', 'trip.toast.reorderError': 'Fehler beim Sortieren', 'trip.toast.reservationUpdated': 'Reservierung aktualisiert', 'trip.toast.reservationAdded': 'Reservierung hinzugefügt', diff --git a/shared/src/i18n/en/trip.ts b/shared/src/i18n/en/trip.ts index 1c63d19c4..de458bbf4 100644 --- a/shared/src/i18n/en/trip.ts +++ b/shared/src/i18n/en/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Place deleted', 'trip.toast.selectDay': 'Please select a day first', 'trip.toast.assignedToDay': 'Place assigned to day', + 'trip.toast.loadError': 'Could not load the trip', 'trip.toast.reorderError': 'Failed to reorder', 'trip.toast.reservationUpdated': 'Reservation updated', 'trip.toast.reservationAdded': 'Reservation added', diff --git a/shared/src/i18n/es/trip.ts b/shared/src/i18n/es/trip.ts index 86ce081f0..6ae8c10bf 100644 --- a/shared/src/i18n/es/trip.ts +++ b/shared/src/i18n/es/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Lugar eliminado', 'trip.toast.selectDay': 'Selecciona primero un día', 'trip.toast.assignedToDay': 'Lugar asignado al día', + 'trip.toast.loadError': 'No se pudo cargar el viaje', 'trip.toast.reorderError': 'No se pudo reordenar', 'trip.toast.reservationUpdated': 'Reserva actualizada', 'trip.toast.reservationAdded': 'Reserva añadida', diff --git a/shared/src/i18n/fr/trip.ts b/shared/src/i18n/fr/trip.ts index 50aa864fe..f3e7d4c0b 100644 --- a/shared/src/i18n/fr/trip.ts +++ b/shared/src/i18n/fr/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Lieu supprimé', 'trip.toast.selectDay': "Veuillez d'abord sélectionner un jour", 'trip.toast.assignedToDay': 'Lieu attribué au planning', + 'trip.toast.loadError': 'Impossible de charger le voyage', 'trip.toast.reorderError': 'Échec de la réorganisation', 'trip.toast.reservationUpdated': 'Réservation mise à jour', 'trip.toast.reservationAdded': 'Réservation ajoutée', diff --git a/shared/src/i18n/gr/trip.ts b/shared/src/i18n/gr/trip.ts index 2a2f2956c..4c74bec7c 100644 --- a/shared/src/i18n/gr/trip.ts +++ b/shared/src/i18n/gr/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Το μέρος διαγράφηκε', 'trip.toast.selectDay': 'Παρακαλώ επιλέξτε πρώτα μια ημέρα', 'trip.toast.assignedToDay': 'Το μέρος ανατέθηκε στην ημέρα', + 'trip.toast.loadError': 'Δεν ήταν δυνατή η φόρτωση του ταξιδιού', 'trip.toast.reorderError': 'Η αναδιάταξη απέτυχε', 'trip.toast.reservationUpdated': 'Η κράτηση ενημερώθηκε', 'trip.toast.reservationAdded': 'Η κράτηση προστέθηκε', diff --git a/shared/src/i18n/hu/trip.ts b/shared/src/i18n/hu/trip.ts index 203e34c9a..fb7722a0a 100644 --- a/shared/src/i18n/hu/trip.ts +++ b/shared/src/i18n/hu/trip.ts @@ -20,6 +20,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Hely törölve', 'trip.toast.selectDay': 'Kérjük, először válassz egy napot', 'trip.toast.assignedToDay': 'Hely hozzárendelve a naphoz', + 'trip.toast.loadError': 'Az utazást nem sikerült betölteni', 'trip.toast.reorderError': 'Nem sikerült átrendezni', 'trip.toast.reservationUpdated': 'Foglalás frissítve', 'trip.toast.reservationAdded': 'Foglalás hozzáadva', diff --git a/shared/src/i18n/id/trip.ts b/shared/src/i18n/id/trip.ts index 0cccd756a..0bffcaeb5 100644 --- a/shared/src/i18n/id/trip.ts +++ b/shared/src/i18n/id/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Tempat dihapus', 'trip.toast.selectDay': 'Pilih hari terlebih dahulu', 'trip.toast.assignedToDay': 'Tempat ditambahkan ke hari', + 'trip.toast.loadError': 'Tidak dapat memuat perjalanan', 'trip.toast.reorderError': 'Gagal mengurutkan ulang', 'trip.toast.reservationUpdated': 'Reservasi diperbarui', 'trip.toast.reservationAdded': 'Reservasi ditambahkan', diff --git a/shared/src/i18n/it/trip.ts b/shared/src/i18n/it/trip.ts index a32af2a24..c387edb1e 100644 --- a/shared/src/i18n/it/trip.ts +++ b/shared/src/i18n/it/trip.ts @@ -20,6 +20,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Luogo eliminato', 'trip.toast.selectDay': 'Seleziona prima un giorno', 'trip.toast.assignedToDay': 'Luogo assegnato al giorno', + 'trip.toast.loadError': 'Impossibile caricare il viaggio', 'trip.toast.reorderError': 'Impossibile riordinare', 'trip.toast.reservationUpdated': 'Prenotazione aggiornata', 'trip.toast.reservationAdded': 'Prenotazione aggiunta', diff --git a/shared/src/i18n/ja/trip.ts b/shared/src/i18n/ja/trip.ts index 73334682c..c30584a26 100644 --- a/shared/src/i18n/ja/trip.ts +++ b/shared/src/i18n/ja/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': '場所を削除しました', 'trip.toast.selectDay': 'まず日を選択してください', 'trip.toast.assignedToDay': '場所を日に割り当てました', + 'trip.toast.loadError': '旅行を読み込めませんでした', 'trip.toast.reorderError': '並び替えに失敗しました', 'trip.toast.reservationUpdated': '予約を更新しました', 'trip.toast.reservationAdded': '予約を追加しました', diff --git a/shared/src/i18n/ko/trip.ts b/shared/src/i18n/ko/trip.ts index e915ef9d3..e29db7c70 100644 --- a/shared/src/i18n/ko/trip.ts +++ b/shared/src/i18n/ko/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': '장소가 삭제되었습니다', 'trip.toast.selectDay': '먼저 날을 선택하세요', 'trip.toast.assignedToDay': '장소가 날에 배정되었습니다', + 'trip.toast.loadError': '여행을 불러오지 못했습니다', 'trip.toast.reorderError': '순서 변경 실패', 'trip.toast.reservationUpdated': '예약이 업데이트되었습니다', 'trip.toast.reservationAdded': '예약이 추가되었습니다', diff --git a/shared/src/i18n/nl/trip.ts b/shared/src/i18n/nl/trip.ts index e661947f4..96268a1f6 100644 --- a/shared/src/i18n/nl/trip.ts +++ b/shared/src/i18n/nl/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Plaats verwijderd', 'trip.toast.selectDay': 'Selecteer eerst een dag', 'trip.toast.assignedToDay': 'Plaats toegewezen aan dag', + 'trip.toast.loadError': 'Kan de reis niet laden', 'trip.toast.reorderError': 'Herordenen mislukt', 'trip.toast.reservationUpdated': 'Reservering bijgewerkt', 'trip.toast.reservationAdded': 'Reservering toegevoegd', diff --git a/shared/src/i18n/pl/trip.ts b/shared/src/i18n/pl/trip.ts index 2d9d1b4af..3e7fe6093 100644 --- a/shared/src/i18n/pl/trip.ts +++ b/shared/src/i18n/pl/trip.ts @@ -20,6 +20,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Miejsce zostało usunięte', 'trip.toast.selectDay': 'Proszę najpierw wybrać dzień', 'trip.toast.assignedToDay': 'Miejsce przypisane do dnia', + 'trip.toast.loadError': 'Nie udało się wczytać podróży', 'trip.toast.reorderError': 'Nie udało się zmienić kolejności', 'trip.toast.reservationUpdated': 'Rezerwacja została zaktualizowana', 'trip.toast.reservationAdded': 'Rezerwacja została dodana', diff --git a/shared/src/i18n/ru/trip.ts b/shared/src/i18n/ru/trip.ts index 03ab8fa3e..d4af42394 100644 --- a/shared/src/i18n/ru/trip.ts +++ b/shared/src/i18n/ru/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Место удалено', 'trip.toast.selectDay': 'Сначала выберите день', 'trip.toast.assignedToDay': 'Место назначено на день', + 'trip.toast.loadError': 'Не удалось загрузить поездку', 'trip.toast.reorderError': 'Ошибка изменения порядка', 'trip.toast.reservationUpdated': 'Бронирование обновлено', 'trip.toast.reservationAdded': 'Бронирование добавлено', diff --git a/shared/src/i18n/sv/trip.ts b/shared/src/i18n/sv/trip.ts index 5698736a7..fdbe3a270 100644 --- a/shared/src/i18n/sv/trip.ts +++ b/shared/src/i18n/sv/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Plats raderad', 'trip.toast.selectDay': 'Vänligen välj en dag först', 'trip.toast.assignedToDay': 'Plats tilldelad till dag', + 'trip.toast.loadError': 'Det gick inte att ladda resan', 'trip.toast.reorderError': 'Misslyckades att ordna om', 'trip.toast.reservationUpdated': 'Reservation uppdaterad', 'trip.toast.reservationAdded': 'Reservation tillagd', diff --git a/shared/src/i18n/tr/trip.ts b/shared/src/i18n/tr/trip.ts index dea377b73..5ca806d1a 100644 --- a/shared/src/i18n/tr/trip.ts +++ b/shared/src/i18n/tr/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Yer silindi', 'trip.toast.selectDay': 'Lütfen önce bir gün seçin', 'trip.toast.assignedToDay': 'Yer güne atandı', + 'trip.toast.loadError': 'Gezi yüklenemedi', 'trip.toast.reorderError': 'Sıralama yapılamadı', 'trip.toast.reservationUpdated': 'Rezervasyon güncellendi', 'trip.toast.reservationAdded': 'Rezervasyon eklendi', diff --git a/shared/src/i18n/uk/trip.ts b/shared/src/i18n/uk/trip.ts index 26daa19a1..52056a901 100644 --- a/shared/src/i18n/uk/trip.ts +++ b/shared/src/i18n/uk/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Місце видалено', 'trip.toast.selectDay': 'Спочатку виберіть день', 'trip.toast.assignedToDay': 'Місце призначено на день', + 'trip.toast.loadError': 'Не вдалося завантажити подорож', 'trip.toast.reorderError': 'Помилка зміни порядку', 'trip.toast.reservationUpdated': 'Бронювання оновлено', 'trip.toast.reservationAdded': 'Бронювання додано', diff --git a/shared/src/i18n/vi/trip.ts b/shared/src/i18n/vi/trip.ts index f65b205b5..3d59efe1c 100644 --- a/shared/src/i18n/vi/trip.ts +++ b/shared/src/i18n/vi/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': 'Địa điểm đã bị xóa', 'trip.toast.selectDay': 'Vui lòng chọn một ngày trước', 'trip.toast.assignedToDay': 'Địa điểm đã được gán vào ngày', + 'trip.toast.loadError': 'Không thể tải chuyến đi', 'trip.toast.reorderError': 'Không thể sắp xếp lại', 'trip.toast.reservationUpdated': 'Đã cập nhật đặt chỗ', 'trip.toast.reservationAdded': 'Đã thêm đặt chỗ', diff --git a/shared/src/i18n/zh-TW/trip.ts b/shared/src/i18n/zh-TW/trip.ts index db60279bc..9c7f3615b 100644 --- a/shared/src/i18n/zh-TW/trip.ts +++ b/shared/src/i18n/zh-TW/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': '地點已刪除', 'trip.toast.selectDay': '請先選擇一天', 'trip.toast.assignedToDay': '地點已分配到當天', + 'trip.toast.loadError': '無法載入行程', 'trip.toast.reorderError': '排序失敗', 'trip.toast.reservationUpdated': '預訂已更新', 'trip.toast.reservationAdded': '預訂已新增', diff --git a/shared/src/i18n/zh/trip.ts b/shared/src/i18n/zh/trip.ts index 43c95cfcb..4f70b3c6e 100644 --- a/shared/src/i18n/zh/trip.ts +++ b/shared/src/i18n/zh/trip.ts @@ -24,6 +24,7 @@ const trip: TranslationStrings = { 'trip.toast.placeDeleted': '地点已删除', 'trip.toast.selectDay': '请先选择一天', 'trip.toast.assignedToDay': '地点已分配到当天', + 'trip.toast.loadError': '无法加载行程', 'trip.toast.reorderError': '排序失败', 'trip.toast.reservationUpdated': '预订已更新', 'trip.toast.reservationAdded': '预订已添加',