From 8855b5581d59f2e32804d9dd7ac9c93a3ea545e3 Mon Sep 17 00:00:00 2001 From: Maurice <61554723+mauriceboe@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:28:00 +0200 Subject: [PATCH] feat(places): planned pool filter + hotel-transfer day routing (#1666) * fix(dayplan): expose route tools on a hotel-to-hotel transfer day (#1297) * feat(places): add a Planned filter to the places pool (sidebar, map, mobile) * fix(places): stretch the mobile pool filter chips to fill the row --- .../Planner/DayPlanSidebar.test.tsx | 42 ++++++++++++++++++ .../src/components/Planner/DayPlanSidebar.tsx | 18 +++++++- .../components/Planner/PlacesSidebar.test.tsx | 12 +++++ .../Planner/PlacesSidebarHeader.tsx | 4 +- .../components/Planner/usePlacesSidebar.ts | 1 + .../screens/trip/places/MPlacesBrowser.tsx | 44 +++++++++---------- .../trip/places/placesBrowserModel.test.ts | 40 +++++++++++++++++ .../screens/trip/places/placesBrowserModel.ts | 2 + .../src/pages/tripPlanner/useTripPlanner.ts | 13 ++++-- shared/src/i18n/ar/places.ts | 1 + shared/src/i18n/br/places.ts | 1 + shared/src/i18n/ca/places.ts | 1 + shared/src/i18n/cs/places.ts | 1 + shared/src/i18n/de/places.ts | 1 + shared/src/i18n/en/places.ts | 1 + shared/src/i18n/es/places.ts | 1 + shared/src/i18n/fr/places.ts | 1 + shared/src/i18n/gr/places.ts | 1 + shared/src/i18n/hu/places.ts | 1 + shared/src/i18n/id/places.ts | 1 + shared/src/i18n/it/places.ts | 1 + shared/src/i18n/ja/places.ts | 1 + shared/src/i18n/ko/places.ts | 1 + shared/src/i18n/nl/places.ts | 1 + shared/src/i18n/pl/places.ts | 1 + shared/src/i18n/ru/places.ts | 1 + shared/src/i18n/sv/places.ts | 1 + shared/src/i18n/tr/places.ts | 1 + shared/src/i18n/uk/places.ts | 1 + shared/src/i18n/vi/places.ts | 1 + shared/src/i18n/zh-TW/places.ts | 1 + shared/src/i18n/zh/places.ts | 1 + 32 files changed, 169 insertions(+), 30 deletions(-) create mode 100644 client/src/mobile/screens/trip/places/placesBrowserModel.test.ts diff --git a/client/src/components/Planner/DayPlanSidebar.test.tsx b/client/src/components/Planner/DayPlanSidebar.test.tsx index 96d3040c3..3806433cd 100644 --- a/client/src/components/Planner/DayPlanSidebar.test.tsx +++ b/client/src/components/Planner/DayPlanSidebar.test.tsx @@ -210,6 +210,48 @@ describe('DayPlanSidebar', () => { expect(screen.queryByRole('button', { name: 'Open in Google Maps' })).not.toBeInTheDocument() }) + // ── #1297: route tools for a hotel-to-hotel transfer day with no stops ─────── + it('FE-PLANNER-DAYPLAN-005d: route tools show for a two-hotel transfer day with no places (#1297)', () => { + const dayA = buildDay({ id: 10, date: '2025-06-01', title: 'Day 1' }) + const dayTransfer = buildDay({ id: 11, date: '2025-06-02', title: 'Day 2' }) + const dayB = buildDay({ id: 12, date: '2025-06-03', title: 'Day 3' }) + // Check out of hotel A (slept there) and into hotel B on the same day — two distinct + // located hotels, zero places. The map draws A → B, so the tools must be reachable. + const accommodations = [ + { id: 1, start_day_id: 10, end_day_id: 11, place_lat: 48.85, place_lng: 2.35 }, + { id: 2, start_day_id: 11, end_day_id: 12, place_lat: 51.50, place_lng: -0.12 }, + ] + render() + expect(screen.getByRole('button', { name: 'Open in Google Maps' })).toBeInTheDocument() + }) + + it('FE-PLANNER-DAYPLAN-005e: no route tools on a same-hotel rest day with no places (#1297 guard)', () => { + const dayA = buildDay({ id: 10, date: '2025-06-01', title: 'Day 1' }) + const dayRest = buildDay({ id: 11, date: '2025-06-02', title: 'Day 2' }) + const dayC = buildDay({ id: 12, date: '2025-06-03', title: 'Day 3' }) + // One hotel spanning all three days: the middle day has morning === evening, so there is + // no transfer leg to draw and the tools stay hidden. + const accommodations = [{ id: 1, start_day_id: 10, end_day_id: 12, place_lat: 48.85, place_lng: 2.35 }] + render() + expect(screen.queryByRole('button', { name: 'Open in Google Maps' })).not.toBeInTheDocument() + }) + + it('FE-PLANNER-DAYPLAN-005f: no route tools on a plain arrival day with no places (#1297 guard)', () => { + const dayArrive = buildDay({ id: 11, date: '2025-06-02', title: 'Day 1' }) + const dayNext = buildDay({ id: 12, date: '2025-06-03', title: 'Day 2' }) + // Only a check-in today (no hotel slept in last night, no places): morning === evening, + // so there is no hotel → hotel leg and the tools stay hidden. + const accommodations = [{ id: 2, start_day_id: 11, end_day_id: 12, place_lat: 51.50, place_lng: -0.12 }] + render() + expect(screen.queryByRole('button', { name: 'Open in Google Maps' })).not.toBeInTheDocument() + }) + // ── Day expansion/collapse ────────────────────────────────────────────── it('FE-PLANNER-DAYPLAN-006: days are expanded by default', () => { diff --git a/client/src/components/Planner/DayPlanSidebar.tsx b/client/src/components/Planner/DayPlanSidebar.tsx index e9e7dca91..4b91d40d7 100644 --- a/client/src/components/Planner/DayPlanSidebar.tsx +++ b/client/src/components/Planner/DayPlanSidebar.tsx @@ -1448,7 +1448,21 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP (routeBookends?.morning?.place_lat != null && routeBookends?.morning?.place_lng != null) || (routeBookends?.evening?.place_lat != null && routeBookends?.evening?.place_lng != null) ) - const routeToolsRoutable = da.length >= 2 || (loc != null && hasRouteBookend) + // Transfer day with no stops at all: you check out of one hotel and into another, so + // the map already draws a hotel → hotel leg (see the transfer branch in + // useRouteCalculation) even with zero places. Mirror that exact gate here — two + // distinct bookend hotels you actually slept in / sleep in tonight — so the route + // tools appear when you click the day (#1297). A same-hotel rest day or a plain + // arrival/departure day has morning === evening and stays excluded. + const transferMorning = routeBookends?.morning + const transferEvening = routeBookends?.evening + const hasHotelTransfer = !!( + routeBookends?.morningIsSleptHere && routeBookends?.eveningIsOvernight && + transferMorning?.place_lat != null && transferMorning?.place_lng != null && + transferEvening?.place_lat != null && transferEvening?.place_lng != null && + (transferMorning.place_lat !== transferEvening.place_lat || transferMorning.place_lng !== transferEvening.place_lng) + ) + const routeToolsRoutable = da.length >= 2 || (loc != null && hasRouteBookend) || hasHotelTransfer // Is this day's inline route currently on? Mobile toggles it per day (its // own expandedRouteDayIds entry); desktop uses the global Route toggle on // the selected day (#1374). @@ -2444,7 +2458,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP )} - {/* Routen-Werkzeuge (ausgewählter Tag, 2+ Orte — oder 1 Ort mit Hotel-Bookend, #1330) */} + {/* Routen-Werkzeuge (ausgewählter Tag, 2+ Orte — oder 1 Ort mit Hotel-Bookend #1330 — oder Hotel-zu-Hotel-Transfertag ohne Orte #1297) */} {(isSelected || (showRouteToolsWhenExpanded && isExpanded)) && routeToolsRoutable && (
diff --git a/client/src/components/Planner/PlacesSidebar.test.tsx b/client/src/components/Planner/PlacesSidebar.test.tsx index 94bf45018..3e3118c91 100644 --- a/client/src/components/Planner/PlacesSidebar.test.tsx +++ b/client/src/components/Planner/PlacesSidebar.test.tsx @@ -242,6 +242,18 @@ describe('Filter tabs', () => { await user.click(screen.getByRole('button', { name: /Unplanned/i })); expect(screen.getByText(/All places are planned/i)).toBeInTheDocument(); }); + + it('FE-PLANNER-SIDEBAR-019b: "Planned" filter shows only planned places', () => { + const planned = buildPlace({ name: 'Planned Place' }); + const unplanned = buildPlace({ name: 'Unplanned Place' }); + const assignments = { '1': [buildAssignment({ place: planned, day_id: 1 })] }; + // Seed the pool filter directly: the tab label resolves from @trek/shared, but the + // filter behaviour (only day-assigned places survive) is what this guards. + seedStore(useTripStore, { placesFilter: 'planned' }); + render(); + expect(screen.getByText('Planned Place')).toBeInTheDocument(); + expect(screen.queryByText('Unplanned Place')).not.toBeInTheDocument(); + }); }); // ── Search ──────────────────────────────────────────────────────────────────── diff --git a/client/src/components/Planner/PlacesSidebarHeader.tsx b/client/src/components/Planner/PlacesSidebarHeader.tsx index daf418f74..a28f653b2 100644 --- a/client/src/components/Planner/PlacesSidebarHeader.tsx +++ b/client/src/components/Planner/PlacesSidebarHeader.tsx @@ -86,13 +86,15 @@ export function PlacesHeader(S: SidebarState) { const counts = { all: baseFiltered.length, unplanned: baseFiltered.filter(p => !plannedIds.has(p.id)).length, + planned: baseFiltered.filter(p => plannedIds.has(p.id)).length, tracks: baseFiltered.filter(p => p.route_geometry).length, } const tabs = ([ { id: 'all', label: t('places.all') }, { id: 'unplanned', label: t('places.unplanned') }, + { id: 'planned', label: t('places.planned') }, hasTracks ? { id: 'tracks', label: t('places.filterTracks') } : null, - ] as const).filter(Boolean) as Array<{ id: 'all' | 'unplanned' | 'tracks'; label: string }> + ] as const).filter(Boolean) as Array<{ id: 'all' | 'unplanned' | 'planned' | 'tracks'; label: string }> return (
{tabs.map(f => { diff --git a/client/src/components/Planner/usePlacesSidebar.ts b/client/src/components/Planner/usePlacesSidebar.ts index 12a1c8cfa..6dbd04b41 100644 --- a/client/src/components/Planner/usePlacesSidebar.ts +++ b/client/src/components/Planner/usePlacesSidebar.ts @@ -201,6 +201,7 @@ export function usePlacesSidebar(props: PlacesSidebarProps) { const filtered = useMemo(() => { const list = places.filter(p => { if (filter === 'unplanned' && plannedIds.has(p.id)) return false + if (filter === 'planned' && !plannedIds.has(p.id)) return false if (filter === 'tracks' && !p.route_geometry) return false if (categoryFilters.size > 0) { if (p.category_id == null) { diff --git a/client/src/mobile/screens/trip/places/MPlacesBrowser.tsx b/client/src/mobile/screens/trip/places/MPlacesBrowser.tsx index 71a8c4c3b..02301be56 100644 --- a/client/src/mobile/screens/trip/places/MPlacesBrowser.tsx +++ b/client/src/mobile/screens/trip/places/MPlacesBrowser.tsx @@ -13,7 +13,7 @@ import type { MPlacesBrowserProps } from '../MTripShell' import type { Place } from '../../../../types' import MPlacesBulkCategorySheet from './MPlacesBulkCategorySheet' import MPlacesSaveToCollectionSheet from './MPlacesSaveToCollectionSheet' -import { filterPool, firstPlannedDayNumbers, plannedPlaceIds, poolCounts } from './placesBrowserModel' +import { filterPool, firstPlannedDayNumbers, plannedPlaceIds } from './placesBrowserModel' /** * Fullscreen places pool (mode === 'browse'): All/Unplanned/Tracks filter @@ -56,10 +56,6 @@ export default function MPlacesBrowser({ planner, shell }: MPlacesBrowserProps) const plannedIds = useMemo(() => plannedPlaceIds(assignments), [assignments]) const dayNumberByPlace = useMemo(() => firstPlannedDayNumbers(assignments, days), [assignments, days]) - const counts = useMemo( - () => poolCounts(places, categoryFilters, search, plannedIds), - [places, categoryFilters, search, plannedIds], - ) const filtered = useMemo( () => filterPool(places, { filter, categoryFilters, search, plannedIds }), [places, filter, categoryFilters, search, plannedIds], @@ -121,38 +117,30 @@ export default function MPlacesBrowser({ planner, shell }: MPlacesBrowserProps) return (
- {/* ── Filter chips + Add + Import ── */} + {/* ── Filter chips + Import (Add sits in the search row below to free space) ── */}
{ setFilter('all'); setSelectedIds(new Set()) }} /> { setFilter('unplanned'); setSelectedIds(new Set()) }} /> + { setFilter('planned'); setSelectedIds(new Set()) }} + /> {hasTracks && ( { setFilter('tracks'); setSelectedIds(new Set()) }} /> )} - {canEditPlaces && ( - - )} {canEditPlaces && ( )} + {canEditPlaces && ( + + )}
{/* ── Selection toolbar ── */} @@ -359,18 +357,18 @@ export default function MPlacesBrowser({ planner, shell }: MPlacesBrowserProps) ) } -/** All / Unplanned / Tracks pool chip with its Geist count. */ -function FilterChip({ active, label, count, onClick }: { active: boolean; label: string; count: number; onClick: () => void }) { +/** All / Unplanned / Planned / Tracks pool chip. Counts are omitted on mobile to save row + * space; chips flex to share the row's full width up to the import button on the right. */ +function FilterChip({ active, label, onClick }: { active: boolean; label: string; onClick: () => void }) { return ( ) } diff --git a/client/src/mobile/screens/trip/places/placesBrowserModel.test.ts b/client/src/mobile/screens/trip/places/placesBrowserModel.test.ts new file mode 100644 index 000000000..6bee97075 --- /dev/null +++ b/client/src/mobile/screens/trip/places/placesBrowserModel.test.ts @@ -0,0 +1,40 @@ +import { describe, it, expect } from 'vitest' +import { filterPool, poolCounts } from './placesBrowserModel' +import type { Place } from '../../../../types' + +const mkPlace = (id: number, over: Partial = {}): Place => + ({ id, name: `Place ${id}`, lat: 0, lng: 0, address: null, category_id: null, ...over } as Place) + +describe('placesBrowserModel — planned pool', () => { + const places = [mkPlace(1), mkPlace(2), mkPlace(3)] + const plannedIds = new Set([1, 3]) // 1 and 3 are assigned to a day + const noCats = new Set() + + it('MOBILE-POOL-planned: keeps only planned places', () => { + const out = filterPool(places, { filter: 'planned', categoryFilters: noCats, search: '', plannedIds }) + expect(out.map(p => p.id)).toEqual([1, 3]) + }) + + it('MOBILE-POOL-unplanned: keeps only unplanned places (unchanged)', () => { + const out = filterPool(places, { filter: 'unplanned', categoryFilters: noCats, search: '', plannedIds }) + expect(out.map(p => p.id)).toEqual([2]) + }) + + it('MOBILE-POOL-all: keeps everything', () => { + const out = filterPool(places, { filter: 'all', categoryFilters: noCats, search: '', plannedIds }) + expect(out.map(p => p.id)).toEqual([1, 2, 3]) + }) + + it('MOBILE-POOL-planned+search: planned pool still honors the search box', () => { + const named = [mkPlace(1, { name: 'Louvre' }), mkPlace(3, { name: 'Eiffel' })] + const out = filterPool(named, { filter: 'planned', categoryFilters: noCats, search: 'eiff', plannedIds }) + expect(out.map(p => p.id)).toEqual([3]) + }) + + it('MOBILE-POOL-counts: poolCounts reports planned alongside all/unplanned', () => { + const c = poolCounts(places, noCats, '', plannedIds) + expect(c.all).toBe(3) + expect(c.planned).toBe(2) + expect(c.unplanned).toBe(1) + }) +}) diff --git a/client/src/mobile/screens/trip/places/placesBrowserModel.ts b/client/src/mobile/screens/trip/places/placesBrowserModel.ts index 8cfbbc980..1e62c9a76 100644 --- a/client/src/mobile/screens/trip/places/placesBrowserModel.ts +++ b/client/src/mobile/screens/trip/places/placesBrowserModel.ts @@ -57,6 +57,7 @@ interface PoolFilterArgs { export function filterPool(places: Place[], { filter, categoryFilters, search, plannedIds }: PoolFilterArgs): Place[] { return places.filter(p => { if (filter === 'unplanned' && plannedIds.has(p.id)) return false + if (filter === 'planned' && !plannedIds.has(p.id)) return false if (filter === 'tracks' && !p.route_geometry) return false return matchesCategoryFilter(p, categoryFilters) && matchesSearch(p, search) }) @@ -68,6 +69,7 @@ export function poolCounts(places: Place[], categoryFilters: Set, search return { all: base.length, unplanned: base.filter(p => !plannedIds.has(p.id)).length, + planned: base.filter(p => plannedIds.has(p.id)).length, tracks: base.filter(p => p.route_geometry).length, } } diff --git a/client/src/pages/tripPlanner/useTripPlanner.ts b/client/src/pages/tripPlanner/useTripPlanner.ts index 08404a57e..485244edc 100644 --- a/client/src/pages/tripPlanner/useTripPlanner.ts +++ b/client/src/pages/tripPlanner/useTripPlanner.ts @@ -371,8 +371,9 @@ export function useTripPlanner() { } } - // Build set of planned place IDs for unplanned filter - const plannedIds = placesFilter === 'unplanned' + // Planned place IDs — needed by both the 'unplanned' filter (exclude them) and + // the new 'planned' filter (keep only them). + const plannedIds = placesFilter === 'unplanned' || placesFilter === 'planned' ? new Set(Object.values(assignments).flatMap(da => da.map(a => a.place?.id).filter(Boolean))) : null @@ -384,8 +385,12 @@ export function useTripPlanner() { if (!placesCategoryFilter.has('uncategorized')) return false } else if (!placesCategoryFilter.has(String(p.category_id))) return false } - if (hiddenPlaceIds.has(p.id)) return false - if (plannedIds && plannedIds.has(p.id)) return false + // Collapsed-day declutter hides a day's stops on every filter EXCEPT 'planned': + // there the user asked to see the whole plan on the map, so a collapsed day + // must not drop its planned places. + if (placesFilter !== 'planned' && hiddenPlaceIds.has(p.id)) return false + if (placesFilter === 'unplanned' && plannedIds && plannedIds.has(p.id)) return false + if (placesFilter === 'planned' && plannedIds && !plannedIds.has(p.id)) return false return true }) }, [places, placesCategoryFilter, placesFilter, assignments, expandedDayIds]) diff --git a/shared/src/i18n/ar/places.ts b/shared/src/i18n/ar/places.ts index 108a16728..d2380ebb3 100644 --- a/shared/src/i18n/ar/places.ts +++ b/shared/src/i18n/ar/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'إلى أي يوم تريد الإضافة؟', 'places.all': 'الكل', 'places.unplanned': 'غير مخطط', + 'places.planned': 'مخطط لها', 'places.filterTracks': 'المسارات', 'places.sortByRating': 'الترتيب حسب التقييم', 'places.yourRating': 'تقييمك', diff --git a/shared/src/i18n/br/places.ts b/shared/src/i18n/br/places.ts index 829dc38ab..35c5fa411 100644 --- a/shared/src/i18n/br/places.ts +++ b/shared/src/i18n/br/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Adicionar a qual dia?', 'places.all': 'Todos', 'places.unplanned': 'Não planejados', + 'places.planned': 'Planejados', 'places.filterTracks': 'Trilhas', 'places.sortByRating': 'Ordenar por avaliação', 'places.yourRating': 'Sua avaliação', diff --git a/shared/src/i18n/ca/places.ts b/shared/src/i18n/ca/places.ts index 81b9f42b2..b6076d731 100644 --- a/shared/src/i18n/ca/places.ts +++ b/shared/src/i18n/ca/places.ts @@ -40,6 +40,7 @@ const places: TranslationStrings = { 'places.assignToDay': "A quin dia l'afegeixo?", 'places.all': 'Tot', 'places.unplanned': 'Sense planificar', + 'places.planned': 'Planificats', 'places.filterTracks': 'Rutes', 'places.sortByRating': 'Ordena per valoració', 'places.yourRating': 'La teva valoració', diff --git a/shared/src/i18n/cs/places.ts b/shared/src/i18n/cs/places.ts index 633394d97..f9d3b658c 100644 --- a/shared/src/i18n/cs/places.ts +++ b/shared/src/i18n/cs/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Přidat do kterého dne?', 'places.all': 'Vše', 'places.unplanned': 'Nezařazené', + 'places.planned': 'Naplánované', 'places.filterTracks': 'Trasy', 'places.sortByRating': 'Seřadit podle hodnocení', 'places.yourRating': 'Tvé hodnocení', diff --git a/shared/src/i18n/de/places.ts b/shared/src/i18n/de/places.ts index 53ec831e5..f291a3621 100644 --- a/shared/src/i18n/de/places.ts +++ b/shared/src/i18n/de/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Zu welchem Tag hinzufügen?', 'places.all': 'Alle', 'places.unplanned': 'Ungeplant', + 'places.planned': 'Geplant', 'places.filterTracks': 'Tracks', 'places.sortByRating': 'Nach Bewertung sortieren', 'places.yourRating': 'Deine Bewertung', diff --git a/shared/src/i18n/en/places.ts b/shared/src/i18n/en/places.ts index aac098b37..314a2b85a 100644 --- a/shared/src/i18n/en/places.ts +++ b/shared/src/i18n/en/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Add to which day?', 'places.all': 'All', 'places.unplanned': 'Unplanned', + 'places.planned': 'Planned', 'places.filterTracks': 'Tracks', 'places.sortByRating': 'Sort by rating', 'places.yourRating': 'Your rating', diff --git a/shared/src/i18n/es/places.ts b/shared/src/i18n/es/places.ts index 5ddbcc7f8..1a7040e63 100644 --- a/shared/src/i18n/es/places.ts +++ b/shared/src/i18n/es/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': '¿A qué día añadirlo?', 'places.all': 'Todo', 'places.unplanned': 'Sin planificar', + 'places.planned': 'Planificados', 'places.filterTracks': 'Rutas', 'places.sortByRating': 'Ordenar por valoración', 'places.yourRating': 'Tu valoración', diff --git a/shared/src/i18n/fr/places.ts b/shared/src/i18n/fr/places.ts index 0ac58d8ef..38cd449b3 100644 --- a/shared/src/i18n/fr/places.ts +++ b/shared/src/i18n/fr/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Ajouter à quel jour ?', 'places.all': 'Tous', 'places.unplanned': 'Non planifiés', + 'places.planned': 'Planifiés', 'places.filterTracks': 'Traces', 'places.sortByRating': 'Trier par note', 'places.yourRating': 'Ta note', diff --git a/shared/src/i18n/gr/places.ts b/shared/src/i18n/gr/places.ts index 8f330409f..c1f925da4 100644 --- a/shared/src/i18n/gr/places.ts +++ b/shared/src/i18n/gr/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Σε ποια ημέρα να προστεθεί;', 'places.all': 'Όλα', 'places.unplanned': 'Μη προγραμματισμένα', + 'places.planned': 'Προγραμματισμένα', 'places.filterTracks': 'Ίχνη', 'places.sortByRating': 'Ταξινόμηση κατά βαθμολογία', 'places.yourRating': 'Η βαθμολογία σου', diff --git a/shared/src/i18n/hu/places.ts b/shared/src/i18n/hu/places.ts index 3123ddb3f..ac9da52eb 100644 --- a/shared/src/i18n/hu/places.ts +++ b/shared/src/i18n/hu/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Melyik naphoz adod?', 'places.all': 'Összes', 'places.unplanned': 'Nem tervezett', + 'places.planned': 'Tervezett', 'places.filterTracks': 'Nyomvonalak', 'places.sortByRating': 'Rendezés értékelés szerint', 'places.yourRating': 'Az értékelésed', diff --git a/shared/src/i18n/id/places.ts b/shared/src/i18n/id/places.ts index dfc3e2cfc..ea04d1478 100644 --- a/shared/src/i18n/id/places.ts +++ b/shared/src/i18n/id/places.ts @@ -41,6 +41,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Tambah ke hari mana?', 'places.all': 'Semua', 'places.unplanned': 'Belum direncanakan', + 'places.planned': 'Direncanakan', 'places.filterTracks': 'Trek', 'places.sortByRating': 'Urutkan berdasarkan rating', 'places.yourRating': 'Rating kamu', diff --git a/shared/src/i18n/it/places.ts b/shared/src/i18n/it/places.ts index 7d965e7c6..21b5ccb69 100644 --- a/shared/src/i18n/it/places.ts +++ b/shared/src/i18n/it/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'A quale giorno aggiungere?', 'places.all': 'Tutti', 'places.unplanned': 'Non pianificati', + 'places.planned': 'Pianificati', 'places.filterTracks': 'Tracce', 'places.sortByRating': 'Ordina per valutazione', 'places.yourRating': 'La tua valutazione', diff --git a/shared/src/i18n/ja/places.ts b/shared/src/i18n/ja/places.ts index 556f2b92a..68a24dbba 100644 --- a/shared/src/i18n/ja/places.ts +++ b/shared/src/i18n/ja/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'どの日に追加しますか?', 'places.all': 'すべて', 'places.unplanned': '未計画', + 'places.planned': '計画済み', 'places.filterTracks': 'トラック', 'places.sortByRating': '評価順に並べ替え', 'places.yourRating': 'あなたの評価', diff --git a/shared/src/i18n/ko/places.ts b/shared/src/i18n/ko/places.ts index 3a78826c6..ddd780c49 100644 --- a/shared/src/i18n/ko/places.ts +++ b/shared/src/i18n/ko/places.ts @@ -41,6 +41,7 @@ const places: TranslationStrings = { 'places.assignToDay': '어느 날에 추가할까요?', 'places.all': '전체', 'places.unplanned': '미계획', + 'places.planned': '계획됨', 'places.filterTracks': '트랙', 'places.sortByRating': '평점순 정렬', 'places.yourRating': '내 평점', diff --git a/shared/src/i18n/nl/places.ts b/shared/src/i18n/nl/places.ts index 275aa1155..b212ae1d1 100644 --- a/shared/src/i18n/nl/places.ts +++ b/shared/src/i18n/nl/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Aan welke dag toevoegen?', 'places.all': 'Alle', 'places.unplanned': 'Ongepland', + 'places.planned': 'Gepland', 'places.filterTracks': 'Tracks', 'places.sortByRating': 'Sorteren op beoordeling', 'places.yourRating': 'Jouw beoordeling', diff --git a/shared/src/i18n/pl/places.ts b/shared/src/i18n/pl/places.ts index 08d8a531b..7eec513eb 100644 --- a/shared/src/i18n/pl/places.ts +++ b/shared/src/i18n/pl/places.ts @@ -33,6 +33,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Do którego dnia dodać?', 'places.all': 'Wszystkie', 'places.unplanned': 'Niezaplanowane', + 'places.planned': 'Zaplanowane', 'places.filterTracks': 'Trasy', 'places.sortByRating': 'Sortuj według oceny', 'places.yourRating': 'Twoja ocena', diff --git a/shared/src/i18n/ru/places.ts b/shared/src/i18n/ru/places.ts index 5eae4926d..b5a4e7498 100644 --- a/shared/src/i18n/ru/places.ts +++ b/shared/src/i18n/ru/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Добавить в какой день?', 'places.all': 'Все', 'places.unplanned': 'Незапланированные', + 'places.planned': 'Запланированные', 'places.filterTracks': 'Треки', 'places.sortByRating': 'Сортировать по рейтингу', 'places.yourRating': 'Твоя оценка', diff --git a/shared/src/i18n/sv/places.ts b/shared/src/i18n/sv/places.ts index 7573c11f7..e654a91a3 100644 --- a/shared/src/i18n/sv/places.ts +++ b/shared/src/i18n/sv/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Lägg till vilken dag?', 'places.all': 'Alla', 'places.unplanned': 'Oplanerat', + 'places.planned': 'Planerat', 'places.filterTracks': 'Spår', 'places.sortByRating': 'Sortera efter betyg', 'places.yourRating': 'Ditt betyg', diff --git a/shared/src/i18n/tr/places.ts b/shared/src/i18n/tr/places.ts index ef7e20ae4..d9dd5e92b 100644 --- a/shared/src/i18n/tr/places.ts +++ b/shared/src/i18n/tr/places.ts @@ -44,6 +44,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Hangi güne eklensin?', 'places.all': 'Tüm', 'places.unplanned': 'Planlanmamış', + 'places.planned': 'Planlanmış', 'places.filterTracks': 'Parçalar', 'places.sortByRating': 'Puana göre sırala', 'places.yourRating': 'Senin puanın', diff --git a/shared/src/i18n/uk/places.ts b/shared/src/i18n/uk/places.ts index 73c776180..8b5b523db 100644 --- a/shared/src/i18n/uk/places.ts +++ b/shared/src/i18n/uk/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Додати на який день?', 'places.all': 'Усі', 'places.unplanned': 'Незаплановані', + 'places.planned': 'Заплановані', 'places.filterTracks': 'Треки', 'places.sortByRating': 'Сортувати за рейтингом', 'places.yourRating': 'Твоя оцінка', diff --git a/shared/src/i18n/vi/places.ts b/shared/src/i18n/vi/places.ts index 78ba11fd2..629a15ce7 100644 --- a/shared/src/i18n/vi/places.ts +++ b/shared/src/i18n/vi/places.ts @@ -42,6 +42,7 @@ const places: TranslationStrings = { 'places.assignToDay': 'Thêm vào ngày nào?', 'places.all': 'Tất cả', 'places.unplanned': 'Không có kế hoạch', + 'places.planned': 'Có kế hoạch', 'places.filterTracks': 'Bài hát', 'places.sortByRating': 'Sắp xếp theo đánh giá', 'places.yourRating': 'Đánh giá của bạn', diff --git a/shared/src/i18n/zh-TW/places.ts b/shared/src/i18n/zh-TW/places.ts index ccad0b5f1..5c17d395a 100644 --- a/shared/src/i18n/zh-TW/places.ts +++ b/shared/src/i18n/zh-TW/places.ts @@ -41,6 +41,7 @@ const places: TranslationStrings = { 'places.assignToDay': '新增到哪一天?', 'places.all': '全部', 'places.unplanned': '未規劃', + 'places.planned': '已規劃', 'places.filterTracks': '路線', 'places.sortByRating': '依評分排序', 'places.yourRating': '你的評分', diff --git a/shared/src/i18n/zh/places.ts b/shared/src/i18n/zh/places.ts index 76e21bab4..b12907025 100644 --- a/shared/src/i18n/zh/places.ts +++ b/shared/src/i18n/zh/places.ts @@ -41,6 +41,7 @@ const places: TranslationStrings = { 'places.assignToDay': '添加到哪一天?', 'places.all': '全部', 'places.unplanned': '未规划', + 'places.planned': '已规划', 'places.filterTracks': '路线', 'places.sortByRating': '按评分排序', 'places.yourRating': '你的评分',