From 204ee2ef86b93917fa67184ece63c8fee5a6b0e8 Mon Sep 17 00:00:00 2001 From: Maurice Date: Tue, 20 Oct 2026 18:39:58 +0200 Subject: [PATCH] chore(ci): give the server test typecheck room, format new client files The server's src and tests together are past 570,000 lines and the test typecheck needs about 4.3 GB, over Node's default heap; it now gets 8 GB like the test jobs. Forty new client files are formatted, and the react-hooks/refs baseline drops by the one warning a split hook removed. --- .github/workflows/test.yml | 5 +++- client/scripts/eslint-baseline.json | 2 +- client/src/api/tourSki.ts | 3 +- .../AtlasTourActivityPane.test.tsx | 2 +- .../TourActivityStatsDialog.test.tsx | 2 +- .../src/components/Tours/ReadStatusNotice.tsx | 3 +- .../src/components/Tours/TourDetailDialog.tsx | 2 +- .../Tours/activity/TourActivityDialog.tsx | 4 +-- .../activity/TourActivitySection.test.tsx | 17 +++++++++-- .../activity/useActivityCompareMap.test.ts | 4 ++- .../components/Tours/bike/routeWays.test.ts | 7 ++++- .../Tours/bike/useRouteWays.test.tsx | 2 +- .../components/Tours/gpxImportChoices.test.ts | 8 ++++-- .../Tours/hike/useHikeWays.test.tsx | 2 +- .../src/components/Tours/hike/wayTagFacets.ts | 11 +------- .../Tours/horse/HorseLegRow.test.tsx | 8 +++--- .../components/Tours/horse/HorseLegRow.tsx | 2 +- .../components/Tours/horse/horseModel.test.ts | 21 ++++++++++++-- .../Tours/horse/horseRouting.test.ts | 2 +- .../Tours/packing/tourPacking.test.tsx | 11 +++++++- .../Tours/planner/RoundHikeCard.tsx | 2 +- .../Tours/planner/TourEditorFields.tsx | 2 +- .../Tours/planner/WaypointLegRows.tsx | 2 +- .../Tours/planner/roundHikeGeometry.ts | 6 ++-- .../Tours/planner/roundHikeRouting.test.ts | 2 +- .../Tours/planner/roundHikeRouting.ts | 2 +- .../components/Tours/planner/roundHikes.ts | 12 +++++--- .../components/Tours/planner/routeLegAt.ts | 3 +- .../planner/useTourPlanner.winter.test.tsx | 10 ++----- client/src/components/Tours/run/RunFields.tsx | 7 +---- client/src/components/Tours/ski/skiChoice.ts | 2 +- .../Tours/ski/useSkiClassification.ts | 3 +- .../Tours/stages/StageDayPicker.tsx | 22 ++++++++++++--- .../Tours/stages/savedTourStages.ts | 12 ++++++-- .../Tours/stages/tourStages.test.ts | 4 +-- .../components/Tours/terrain/terrainLayers.ts | 7 ++++- .../src/components/Tours/winter/PisteKey.tsx | 7 +++-- client/src/db/cacheTour.test.ts | 8 ++++-- client/src/pages/tripPlanner/tourMapFocus.ts | 28 ++++++++++--------- client/src/repo/tourPackingLinkRepo.test.ts | 6 +++- client/tests/helpers/msw/handlers/tours.ts | 11 ++++++-- client/tests/helpers/storeRegistry.ts | 3 +- 42 files changed, 176 insertions(+), 103 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d4219ea66..ef0389629 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -261,8 +261,11 @@ jobs: # constructor parameter does not break its hand-wired call sites at # compile time: the argument arrives as undefined and throws at # runtime, if anything reads it at all. This is the step that - # catches it. + # catches it. src and tests together are past 570,000 lines and need + # about 4.3 GB, over Node's default heap. run: cd server && npm run typecheck:tests + env: + NODE_OPTIONS: --max-old-space-size=8192 - name: Typecheck entity generator # tsconfig.scripts.json covers generate-entities.ts and migrate-encryption.ts; diff --git a/client/scripts/eslint-baseline.json b/client/scripts/eslint-baseline.json index ad5eb6d1f..6836a5f7e 100644 --- a/client/scripts/eslint-baseline.json +++ b/client/scripts/eslint-baseline.json @@ -8,7 +8,7 @@ "trek/no-swallowed-catch": 133, "max-params": 35, "trek/store-without-selector": 69, - "react-hooks/refs": 559, + "react-hooks/refs": 558, "react-hooks/set-state-in-effect": 197, "@typescript-eslint/no-floating-promises": 167, "react-hooks/exhaustive-deps": 121, diff --git a/client/src/api/tourSki.ts b/client/src/api/tourSki.ts index c3a485d2e..660a2f083 100644 --- a/client/src/api/tourSki.ts +++ b/client/src/api/tourSki.ts @@ -7,6 +7,5 @@ export const tourSkiApi = { tripId: number | string, placeId: number | string, body: TourSkiClassificationRequest - ): Promise => - apiClient.put(`/trips/${tripId}/tours/${placeId}/ski`, body).then((r) => r.data), + ): Promise => apiClient.put(`/trips/${tripId}/tours/${placeId}/ski`, body).then((r) => r.data), }; diff --git a/client/src/components/Atlas/tourActivity/AtlasTourActivityPane.test.tsx b/client/src/components/Atlas/tourActivity/AtlasTourActivityPane.test.tsx index 09ed42f71..29b8b26ac 100644 --- a/client/src/components/Atlas/tourActivity/AtlasTourActivityPane.test.tsx +++ b/client/src/components/Atlas/tourActivity/AtlasTourActivityPane.test.tsx @@ -5,8 +5,8 @@ import userEvent from '@testing-library/user-event'; import { summarizeTourActivities, type TourActivityStatsEntry, type TourActivityStatsResponse } from '@trek/shared'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { render, screen } from '../../../../tests/helpers/render'; import { buildSettings } from '../../../../tests/helpers/factories'; +import { render, screen } from '../../../../tests/helpers/render'; import { resetAllStores, seedStore } from '../../../../tests/helpers/store'; import { useSettingsStore } from '../../../store/settingsStore'; import { AtlasTourActivityPane } from './AtlasTourActivityPane'; diff --git a/client/src/components/Atlas/tourActivity/TourActivityStatsDialog.test.tsx b/client/src/components/Atlas/tourActivity/TourActivityStatsDialog.test.tsx index 91c365a0c..c669d4be9 100644 --- a/client/src/components/Atlas/tourActivity/TourActivityStatsDialog.test.tsx +++ b/client/src/components/Atlas/tourActivity/TourActivityStatsDialog.test.tsx @@ -5,9 +5,9 @@ import userEvent from '@testing-library/user-event'; import { summarizeTourActivities, type TourActivityStatsEntry, type TourActivityStatsResponse } from '@trek/shared'; import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { buildSettings } from '../../../../tests/helpers/factories'; import { render, screen, within } from '../../../../tests/helpers/render'; import { resetAllStores, seedStore } from '../../../../tests/helpers/store'; -import { buildSettings } from '../../../../tests/helpers/factories'; import { useSettingsStore } from '../../../store/settingsStore'; import { TourActivityStatsDialog } from './TourActivityStatsDialog'; import type { TourActivityStats } from './useTourActivityStats'; diff --git a/client/src/components/Tours/ReadStatusNotice.tsx b/client/src/components/Tours/ReadStatusNotice.tsx index 5d26ead77..ba5ef0d45 100644 --- a/client/src/components/Tours/ReadStatusNotice.tsx +++ b/client/src/components/Tours/ReadStatusNotice.tsx @@ -25,7 +25,8 @@ export function ReadStatusNotice({ {messages.loading} ); - if (status === 'offline') return }>{messages.offline}; + if (status === 'offline') + return }>{messages.offline}; if (status !== 'failed') return null; return ( }> diff --git a/client/src/components/Tours/TourDetailDialog.tsx b/client/src/components/Tours/TourDetailDialog.tsx index 4bf4da07d..c05e83490 100644 --- a/client/src/components/Tours/TourDetailDialog.tsx +++ b/client/src/components/Tours/TourDetailDialog.tsx @@ -52,8 +52,8 @@ import { TourGpxExportButton } from './TourGpxExportButton'; import TourActivitySection from './activity/TourActivitySection'; import type { PlanValues } from './activity/planComparison'; import { TourSaveToCollectionButton } from './collection/TourSaveToCollectionButton'; -import { PaddleCheckSection } from './paddle/PaddleCheckSection'; import { TourPackingSection } from './packing/TourPackingSection'; +import { PaddleCheckSection } from './paddle/PaddleCheckSection'; import { PaddleWindSection } from './paddle/PaddleWindCard'; import { TourProvenanceBlock } from './provenance/TourProvenanceSection'; import { RunHeadPills } from './run/RunHeadPills'; diff --git a/client/src/components/Tours/activity/TourActivityDialog.tsx b/client/src/components/Tours/activity/TourActivityDialog.tsx index 75f1fbcb3..c8e8a4edc 100644 --- a/client/src/components/Tours/activity/TourActivityDialog.tsx +++ b/client/src/components/Tours/activity/TourActivityDialog.tsx @@ -236,9 +236,7 @@ export default function TourActivityDialog({ variant="primary" data-testid="tour-activity-confirm" disabled={!assignment.ready || state.busy || importing} - icon={ - state.busy ? : - } + icon={state.busy ? : } onClick={confirm} > {t('tours.activity.confirm')} diff --git a/client/src/components/Tours/activity/TourActivitySection.test.tsx b/client/src/components/Tours/activity/TourActivitySection.test.tsx index bab399245..293a9ef5b 100644 --- a/client/src/components/Tours/activity/TourActivitySection.test.tsx +++ b/client/src/components/Tours/activity/TourActivitySection.test.tsx @@ -120,7 +120,17 @@ describe('TourActivitySection (ACT-01)', () => { expect(current.askRemove).toHaveBeenCalledWith(current.activities?.[0]); hook.state = state({ assigning: {}, removing: activity() }); - rerender(); + rerender( + + ); expect(screen.getByTestId('tour-activity-dialog')).toBeInTheDocument(); expect(screen.getByText('tours.activity.removeTitle')).toBeInTheDocument(); }); @@ -193,6 +203,9 @@ describe('TourActivitySection (ACT-01)', () => { expect(screen.queryByRole('button', { name: /tours.activity.compare.(show|hide)/ })).toBeNull(); act(() => useTourActivityCompareStore.getState().setMapAvailable(true)); - expect(screen.getByRole('button', { name: /tours.activity.compare.show/ })).toHaveAttribute('aria-pressed', 'false'); + expect(screen.getByRole('button', { name: /tours.activity.compare.show/ })).toHaveAttribute( + 'aria-pressed', + 'false' + ); }); }); diff --git a/client/src/components/Tours/activity/useActivityCompareMap.test.ts b/client/src/components/Tours/activity/useActivityCompareMap.test.ts index 7521dbd45..0628cd620 100644 --- a/client/src/components/Tours/activity/useActivityCompareMap.test.ts +++ b/client/src/components/Tours/activity/useActivityCompareMap.test.ts @@ -117,7 +117,9 @@ describe('useActivityCompareMap (ACT-02)', () => { }); it('FE-ACT-COMPARE-MAP-006: tells the store whether it can compare, and ends a comparison where it no longer can or is gone', () => { - const { rerender, unmount } = renderHook((props: typeof input) => useActivityCompareMap(props), { initialProps: input }); + const { rerender, unmount } = renderHook((props: typeof input) => useActivityCompareMap(props), { + initialProps: input, + }); expect(useTourActivityCompareStore.getState().mapAvailable).toBe(true); act(() => useTourActivityCompareStore.getState().show({ tourPlaceId: 7, trackPlaceId: 20 })); diff --git a/client/src/components/Tours/bike/routeWays.test.ts b/client/src/components/Tours/bike/routeWays.test.ts index 9b3436ff9..dfd86d007 100644 --- a/client/src/components/Tours/bike/routeWays.test.ts +++ b/client/src/components/Tours/bike/routeWays.test.ts @@ -183,7 +183,12 @@ describe('the paints and the highlight (BIK-01 to BIK-05)', () => { it('FE-TOUR-WAYS-014: lines of different paints each take their own, an unknown key the accent (MAP-03)', () => { const drawn = withRouteHighlight( - { id: 'sac', lines: [LINE.slice(0, 2), LINE.slice(1, 3), LINE.slice(2)], paint: 'gravel', paints: ['way', 'nope'] }, + { + id: 'sac', + lines: [LINE.slice(0, 2), LINE.slice(1, 3), LINE.slice(2)], + paint: 'gravel', + paints: ['way', 'nope'], + }, [LINE], null, null, diff --git a/client/src/components/Tours/bike/useRouteWays.test.tsx b/client/src/components/Tours/bike/useRouteWays.test.tsx index 12caacb8b..7e38f4f2c 100644 --- a/client/src/components/Tours/bike/useRouteWays.test.tsx +++ b/client/src/components/Tours/bike/useRouteWays.test.tsx @@ -1,5 +1,5 @@ -import { TOUR_TRAIL_GRADE_MAX_WAYS } from '@trek/shared'; import { act, renderHook } from '@testing-library/react'; +import { TOUR_TRAIL_GRADE_MAX_WAYS } from '@trek/shared'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { encodePolyline } from '../../../../tests/helpers/polyline'; import { OnlineOnlyError } from '../../../repo/onlineOnly'; diff --git a/client/src/components/Tours/gpxImportChoices.test.ts b/client/src/components/Tours/gpxImportChoices.test.ts index cad77195c..012750760 100644 --- a/client/src/components/Tours/gpxImportChoices.test.ts +++ b/client/src/components/Tours/gpxImportChoices.test.ts @@ -34,9 +34,11 @@ describe('GPX import choices', () => { tour_type: 'ski', ski_discipline: 'touring', }); - expect( - importFields({ ...base, type: 'ski', ski: { discipline: 'cross_country', technique: 'unknown' } }) - ).toEqual({ tour_type: 'ski', ski_discipline: 'cross_country', ski_technique: 'unknown' }); + expect(importFields({ ...base, type: 'ski', ski: { discipline: 'cross_country', technique: 'unknown' } })).toEqual({ + tour_type: 'ski', + ski_discipline: 'cross_country', + ski_technique: 'unknown', + }); }); it('FE-TOUR-GPX-CHOICES-002: holds the import back while a paddle tour or a ski track lacks what it must name', () => { diff --git a/client/src/components/Tours/hike/useHikeWays.test.tsx b/client/src/components/Tours/hike/useHikeWays.test.tsx index 9ceaecaed..2b9b7e7b6 100644 --- a/client/src/components/Tours/hike/useHikeWays.test.tsx +++ b/client/src/components/Tours/hike/useHikeWays.test.tsx @@ -1,5 +1,5 @@ -import type { TourTrailGrade } from '@trek/shared'; import { act, renderHook } from '@testing-library/react'; +import type { TourTrailGrade } from '@trek/shared'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { useTourRouteHighlightStore } from '../../../store/tourRouteHighlightStore'; import type { RouteWayEdge, RouteWays } from '../bike/routeWays'; diff --git a/client/src/components/Tours/hike/wayTagFacets.ts b/client/src/components/Tours/hike/wayTagFacets.ts index 5fcfd917e..83aac0280 100644 --- a/client/src/components/Tours/hike/wayTagFacets.ts +++ b/client/src/components/Tours/hike/wayTagFacets.ts @@ -13,16 +13,7 @@ import type { HikePaintKey } from './hikePaint'; */ type HikeSurfaceClass = - | 'paved' - | 'sett' - | 'compacted' - | 'gravel' - | 'ground' - | 'grass' - | 'rock' - | 'wood' - | 'unpaved' - | 'other'; + 'paved' | 'sett' | 'compacted' | 'gravel' | 'ground' | 'grass' | 'rock' | 'wood' | 'unpaved' | 'other'; type HikeWayClass = 'path' | 'footway' | 'steps' | 'track' | 'cycleway' | 'quietRoad' | 'road' | 'viaFerrata' | 'other'; diff --git a/client/src/components/Tours/horse/HorseLegRow.test.tsx b/client/src/components/Tours/horse/HorseLegRow.test.tsx index cee5e88c5..2666ae0f8 100644 --- a/client/src/components/Tours/horse/HorseLegRow.test.tsx +++ b/client/src/components/Tours/horse/HorseLegRow.test.tsx @@ -1,16 +1,16 @@ import { renderHook } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import { render, screen, within } from '../../../../tests/helpers/render'; -import { TourDayRowIcon } from '../TourDayRowFacts'; -import { tourDayRowIcon } from '../tourDayRowIcon'; -import { movingTimeLabel } from '../tourFacts'; import type { TourPlannerWaypoint } from '../planner/tourPlannerWaypoints'; import { useShapingClick } from '../planner/useShapingClick'; import type { TourPlannerController } from '../planner/useTourPlanner'; import { WaypointLegRows } from '../planner/WaypointLegRows'; +import { TourDayRowIcon } from '../TourDayRowFacts'; +import { tourDayRowIcon } from '../tourDayRowIcon'; +import { movingTimeLabel } from '../tourFacts'; import { HorseLegRow } from './HorseLegRow'; -import { Horseshoe } from './HorseshoeIcon'; import type { HorseSectionLeg } from './horseSection'; +import { Horseshoe } from './HorseshoeIcon'; // FE-HORSE-LEG-001 to FE-HORSE-LEG-005 diff --git a/client/src/components/Tours/horse/HorseLegRow.tsx b/client/src/components/Tours/horse/HorseLegRow.tsx index c96a4166a..8d040c26f 100644 --- a/client/src/components/Tours/horse/HorseLegRow.tsx +++ b/client/src/components/Tours/horse/HorseLegRow.tsx @@ -6,8 +6,8 @@ import { fs } from '../../shared/DialogShell'; import { Tooltip } from '../../shared/Tooltip'; import { lineLengthM } from '../planner/tourFixedLegs'; import { ACCESS_TONE_DOT, accessText, accessToneOf } from './horseAccess'; -import { Horseshoe } from './HorseshoeIcon'; import type { HorseSectionLeg } from './horseSection'; +import { Horseshoe } from './HorseshoeIcon'; /** * HOR-01: a section of a horse route the ride follows, as a badge on its leg diff --git a/client/src/components/Tours/horse/horseModel.test.ts b/client/src/components/Tours/horse/horseModel.test.ts index 1474ef13d..d3a4a7ecc 100644 --- a/client/src/components/Tours/horse/horseModel.test.ts +++ b/client/src/components/Tours/horse/horseModel.test.ts @@ -132,9 +132,24 @@ describe('horse route sections on a ride (HOR-01)', () => { expect(accessToneOf(undefined)).toBeNull(); expect(accessToneOf([])).toBeNull(); expect(accessToneOf([{ value: 'yes', length_m: 10 }])).toBe('open'); - expect(accessToneOf([{ value: 'yes', length_m: 10 }, { value: 'unknown', length_m: 1 }])).toBe('unknown'); - expect(accessToneOf([{ value: 'unknown', length_m: 10 }, { value: 'destination', length_m: 1 }])).toBe('limited'); - expect(accessToneOf([{ value: 'designated', length_m: 10 }, { value: 'private', length_m: 1 }])).toBe('closed'); + expect( + accessToneOf([ + { value: 'yes', length_m: 10 }, + { value: 'unknown', length_m: 1 }, + ]) + ).toBe('unknown'); + expect( + accessToneOf([ + { value: 'unknown', length_m: 10 }, + { value: 'destination', length_m: 1 }, + ]) + ).toBe('limited'); + expect( + accessToneOf([ + { value: 'designated', length_m: 10 }, + { value: 'private', length_m: 1 }, + ]) + ).toBe('closed'); }); it('FE-HORSE-MODEL-009: spells the tags out with the metres each covers', () => { diff --git a/client/src/components/Tours/horse/horseRouting.test.ts b/client/src/components/Tours/horse/horseRouting.test.ts index 86568db7a..eb7b2e349 100644 --- a/client/src/components/Tours/horse/horseRouting.test.ts +++ b/client/src/components/Tours/horse/horseRouting.test.ts @@ -1,9 +1,9 @@ import type { TourFixedLeg } from '@trek/shared'; import { describe, expect, it } from 'vitest'; -import { tourMapLayersFor } from '../tourMapLayers'; import { normalizePlannerWaypoints, tourWaypointKey, type TourPlannerWaypoint } from '../planner/tourPlannerWaypoints'; import { toggleFreeLeg } from '../planner/tourRouteActions'; import { rideTour, routeWalkingTour } from '../planner/tourRouting'; +import { tourMapLayersFor } from '../tourMapLayers'; // FE-HORSE-ROUTE-001 to FE-HORSE-ROUTE-006 diff --git a/client/src/components/Tours/packing/tourPacking.test.tsx b/client/src/components/Tours/packing/tourPacking.test.tsx index d5cf95455..e213a596a 100644 --- a/client/src/components/Tours/packing/tourPacking.test.tsx +++ b/client/src/components/Tours/packing/tourPacking.test.tsx @@ -22,7 +22,16 @@ const GEAR: TourPackingLink = { category: 'Hiking gear', linked_at: '2026-10-20 let nextId = 1; function item(name: string, category: string | null, over: Partial = {}): PackingItem { - return { id: nextId++, trip_id: 5, name, category, checked: 0, sort_order: nextId, quantity: 1, ...over } as PackingItem; + return { + id: nextId++, + trip_id: 5, + name, + category, + checked: 0, + sort_order: nextId, + quantity: 1, + ...over, + } as PackingItem; } const ITEMS = [ diff --git a/client/src/components/Tours/planner/RoundHikeCard.tsx b/client/src/components/Tours/planner/RoundHikeCard.tsx index 98674364d..8872feb96 100644 --- a/client/src/components/Tours/planner/RoundHikeCard.tsx +++ b/client/src/components/Tours/planner/RoundHikeCard.tsx @@ -6,8 +6,8 @@ import type { DistanceUnit } from '../../../types'; import { formatDistance, getDistanceUnitLabel } from '../../../utils/units'; import { SoftPill } from '../../Planner/planParts'; import ConfirmDialog from '../../shared/ConfirmDialog'; -import { fs } from '../../shared/DialogShell'; import { INPUT, LABEL, PillSelect } from '../../shared/dialogParts'; +import { fs } from '../../shared/DialogShell'; import { Tooltip } from '../../shared/Tooltip'; import { TourNotice } from '../tourParts'; import { MapCard, MapCardActions, MapCornerOverlay, StopDisc, VariantFigures, WayChoice } from './mapCardParts'; diff --git a/client/src/components/Tours/planner/TourEditorFields.tsx b/client/src/components/Tours/planner/TourEditorFields.tsx index 36d2f53fb..97b056978 100644 --- a/client/src/components/Tours/planner/TourEditorFields.tsx +++ b/client/src/components/Tours/planner/TourEditorFields.tsx @@ -7,9 +7,9 @@ import { INPUT, LABEL } from '../../shared/dialogParts'; import { fs } from '../../shared/DialogShell'; import { FoldButton, InfoDot, TourNotice, TourSection } from '../tourParts'; import { HikingPreferencesField } from './HikingPreferencesField'; -import { WinterActivityField } from './WinterActivityField'; import { TOUR_DURATION_INPUT_MAX_LENGTH, formatTourDuration, parseTourDuration } from './tourDurationInput'; import type { TourPlannerController } from './useTourPlanner'; +import { WinterActivityField } from './WinterActivityField'; type Difficulty = 1 | 2 | 3 | 4 | 5 | 6; diff --git a/client/src/components/Tours/planner/WaypointLegRows.tsx b/client/src/components/Tours/planner/WaypointLegRows.tsx index 6b08a4616..e1cc0377c 100644 --- a/client/src/components/Tours/planner/WaypointLegRows.tsx +++ b/client/src/components/Tours/planner/WaypointLegRows.tsx @@ -5,9 +5,9 @@ import { useSettingsStore } from '../../../store/settingsStore'; import type { TourFerrataCrossing } from '../../../store/tourFerrataCrossingStore'; import { formatDistance } from '../../../utils/units'; import { FerrataGlyph } from '../../Ferratas/FerrataGlyph'; -import { HorseLegRow } from '../horse/HorseLegRow'; import { fs } from '../../shared/DialogShell'; import { Tooltip } from '../../shared/Tooltip'; +import { HorseLegRow } from '../horse/HorseLegRow'; import { PaddleLegFailureRow, PaddleLegNotes } from '../paddle/PaddleLegParts'; import { isRegionLoadPending, regionLoadFailure } from '../paddle/paddleRegionLoad'; import { PaddleRegionLoadRow } from '../paddle/PaddleRegionLoadRow'; diff --git a/client/src/components/Tours/planner/roundHikeGeometry.ts b/client/src/components/Tours/planner/roundHikeGeometry.ts index 88da72017..ec9bbe8b0 100644 --- a/client/src/components/Tours/planner/roundHikeGeometry.ts +++ b/client/src/components/Tours/planner/roundHikeGeometry.ts @@ -102,9 +102,9 @@ function hasNeighbour(grid: Map, sample: Sample, counts: (othe const cy = cellOf(sample.y); for (let dx = -1; dx <= 1; dx += 1) { for (let dy = -1; dy <= 1; dy += 1) { - const near = grid.get(`${cx + dx}:${cy + dy}`)?.some( - (other) => Math.hypot(other.x - sample.x, other.y - sample.y) <= SAME_GROUND_M && counts(other) - ); + const near = grid + .get(`${cx + dx}:${cy + dy}`) + ?.some((other) => Math.hypot(other.x - sample.x, other.y - sample.y) <= SAME_GROUND_M && counts(other)); if (near) return true; } } diff --git a/client/src/components/Tours/planner/roundHikeRouting.test.ts b/client/src/components/Tours/planner/roundHikeRouting.test.ts index 4289629be..ccbddfa4f 100644 --- a/client/src/components/Tours/planner/roundHikeRouting.test.ts +++ b/client/src/components/Tours/planner/roundHikeRouting.test.ts @@ -10,9 +10,9 @@ const { valhallaRun, enrichTourElevations } = vi.hoisted(() => ({ vi.mock('../../Map/valhallaRoute', () => ({ valhallaRun })); vi.mock('./tourRouting', () => ({ enrichTourElevations })); -import { fitsWish, type RoundRequest } from './roundHikes'; import { spotToward } from './roundHikeGeometry'; import { findRoundHikes, MAX_ROUND_ASKS, type RoundSearchReport } from './roundHikeRouting'; +import { fitsWish, type RoundRequest } from './roundHikes'; type Spot = { lat: number; lng: number }; diff --git a/client/src/components/Tours/planner/roundHikeRouting.ts b/client/src/components/Tours/planner/roundHikeRouting.ts index f552f672d..4cf407c29 100644 --- a/client/src/components/Tours/planner/roundHikeRouting.ts +++ b/client/src/components/Tours/planner/roundHikeRouting.ts @@ -3,8 +3,8 @@ import { valhallaRun } from '../../Map/valhallaRoute'; import { figuresOf } from './legVariants'; import { loopSpots, retracedShare, sharedShare, STRAIGHT_PER_RADIUS_M } from './roundHikeGeometry'; import { fitsWish, ROUND_KEYS, type RoundCandidate, type RoundRequest } from './roundHikes'; -import { enrichTourElevations } from './tourRouting'; import { MAX_TOUR_SNAP_M } from './tourRouteOutcome'; +import { enrichTourElevations } from './tourRouting'; type Spot = { lat: number; lng: number }; diff --git a/client/src/components/Tours/planner/roundHikes.ts b/client/src/components/Tours/planner/roundHikes.ts index ed38d9d0e..96e6526e4 100644 --- a/client/src/components/Tours/planner/roundHikes.ts +++ b/client/src/components/Tours/planner/roundHikes.ts @@ -4,8 +4,8 @@ import { convertDistance } from '../../../utils/units'; import type { CostingOptions } from '../../Map/valhallaRoute'; import { OTHER_WAY_KEYS, type LegVariant } from './legVariants'; import { spotToward } from './roundHikeGeometry'; -import { closeLoop } from './tourRouteActions'; import type { TourPlannerWaypoint } from './tourPlannerWaypoints'; +import { closeLoop } from './tourRouteActions'; /** * RTE-03: round hikes of about a wished length out of a start point, as a @@ -139,9 +139,13 @@ export function roundPlanOf( newId: () => string ): TourPlannerWaypoint[] { const { fixedLeg: _leg, lock: _lock, carryNext: _carry, auto: _auto, shaping: _shaping, ...own } = start; - const steering = via.map( - ({ lat, lng }): TourPlannerWaypoint => ({ id: newId(), lat, lng, role: 'via', shaping: true }) - ); + const steering = via.map(({ lat, lng }): TourPlannerWaypoint => ({ + id: newId(), + lat, + lng, + role: 'via', + shaping: true, + })); return closeLoop([{ ...own, role: 'start' }, ...steering], newId()); } diff --git a/client/src/components/Tours/planner/routeLegAt.ts b/client/src/components/Tours/planner/routeLegAt.ts index ea294e998..09cb54cc3 100644 --- a/client/src/components/Tours/planner/routeLegAt.ts +++ b/client/src/components/Tours/planner/routeLegAt.ts @@ -25,7 +25,8 @@ function alongLine( const t = length === 0 ? 0 : Math.max(0, Math.min(1, ((lng - aLng) * cos * dx + (lat - aLat) * dy) / (length * length))); const distance = Math.hypot(aLng * cos + dx * t - lng * cos, aLat + dy * t - lat); - if (distance < best.distance) best = { at: travelled + length * t, index: i, vertex: t < 0.5 ? i : i + 1, distance }; + if (distance < best.distance) + best = { at: travelled + length * t, index: i, vertex: t < 0.5 ? i : i + 1, distance }; } travelled += length; } diff --git a/client/src/components/Tours/planner/useTourPlanner.winter.test.tsx b/client/src/components/Tours/planner/useTourPlanner.winter.test.tsx index 12c9794c0..22d5bb64f 100644 --- a/client/src/components/Tours/planner/useTourPlanner.winter.test.tsx +++ b/client/src/components/Tours/planner/useTourPlanner.winter.test.tsx @@ -87,10 +87,7 @@ describe('useTourPlanner, the winter label of a hike (HIK-01)', () => { await act(async () => { await result.current.save(); }); - expect(createTour).toHaveBeenCalledWith( - 61, - expect.objectContaining({ tour_type: 'hike', winter_activity: null }) - ); + expect(createTour).toHaveBeenCalledWith(61, expect.objectContaining({ tour_type: 'hike', winter_activity: null })); }); it('FE-TOUR-WINTER-002: the label plans nothing again, is no step of the history and is kept in the draft', async () => { @@ -179,10 +176,7 @@ describe('useTourPlanner, the winter label of a hike (HIK-01)', () => { await act(async () => { await result.current.save(); }); - expect(createTour).toHaveBeenCalledWith( - 65, - expect.objectContaining({ tour_type: 'walk', winter_activity: null }) - ); + expect(createTour).toHaveBeenCalledWith(65, expect.objectContaining({ tour_type: 'walk', winter_activity: null })); }); it('FE-TOUR-WINTER-006: keeps the label the switch brings back with the tour, winter hiking for the next one', async () => { diff --git a/client/src/components/Tours/run/RunFields.tsx b/client/src/components/Tours/run/RunFields.tsx index 2f725acf4..5d7c938d3 100644 --- a/client/src/components/Tours/run/RunFields.tsx +++ b/client/src/components/Tours/run/RunFields.tsx @@ -1,9 +1,4 @@ -import { - MAX_RUN_PACE_SECONDS_PER_KM, - MIN_RUN_PACE_SECONDS_PER_KM, - RUN_PROFILES, - type RunProfile, -} from '@trek/shared'; +import { MAX_RUN_PACE_SECONDS_PER_KM, MIN_RUN_PACE_SECONDS_PER_KM, RUN_PROFILES, type RunProfile } from '@trek/shared'; import { Clock, Gauge, Info, Ruler } from 'lucide-react'; import { useState } from 'react'; import { useTranslation } from '../../../i18n'; diff --git a/client/src/components/Tours/ski/skiChoice.ts b/client/src/components/Tours/ski/skiChoice.ts index a2fb6db2f..f04d8820d 100644 --- a/client/src/components/Tours/ski/skiChoice.ts +++ b/client/src/components/Tours/ski/skiChoice.ts @@ -20,7 +20,7 @@ export function skiChoiceMissing(choice: SkiChoice): 'discipline' | 'technique' /** The fields a complete choice is sent as; null while something is missing. */ export function skiFieldsOf( - choice: SkiChoice, + choice: SkiChoice ): Pick | null { if (choice.discipline === null || skiChoiceMissing(choice)) return null; return choice.discipline === 'cross_country' diff --git a/client/src/components/Tours/ski/useSkiClassification.ts b/client/src/components/Tours/ski/useSkiClassification.ts index eccbbd949..32ce12108 100644 --- a/client/src/components/Tours/ski/useSkiClassification.ts +++ b/client/src/components/Tours/ski/useSkiClassification.ts @@ -29,8 +29,7 @@ export function useSkiClassification({ tripId, planner, tours, canEdit, onSaved const [draft, setDraft] = useState(null); const [saving, setSaving] = useState(false); const viewed = planner.mode.type === 'view-gpx' ? planner.mode.tour : null; - const tour = - viewed?.tour_type === 'ski' ? (tours.find((item) => item.place_id === viewed.place_id) ?? viewed) : null; + const tour = viewed?.tour_type === 'ski' ? (tours.find((item) => item.place_id === viewed.place_id) ?? viewed) : null; const saved = useMemo(() => (tour ? skiChoiceOf(tour) : NO_SKI_CHOICE), [tour]); const open = useCallback(() => { diff --git a/client/src/components/Tours/stages/StageDayPicker.tsx b/client/src/components/Tours/stages/StageDayPicker.tsx index 773a01def..51df26a55 100644 --- a/client/src/components/Tours/stages/StageDayPicker.tsx +++ b/client/src/components/Tours/stages/StageDayPicker.tsx @@ -18,7 +18,11 @@ interface StageDayPickerProps { } /** The days a stage can go on, the one it is on checked, and a way back to none. */ -function dayItems({ stageKey, days, stageDays }: StageDayPickerProps, label: (day: Day, index: number) => string, noDay: string) { +function dayItems( + { stageKey, days, stageDays }: StageDayPickerProps, + label: (day: Day, index: number) => string, + noDay: string +) { const current = stageDays.dayOf(stageKey); const items: MenuItems = days.map((day, index) => ({ label: label(day, index), @@ -27,7 +31,11 @@ function dayItems({ stageKey, days, stageDays }: StageDayPickerProps, label: (da onClick: () => void stageDays.setDay(stageKey, day.id), })); if (current === null) return items; - return [...items, { divider: true }, { label: noDay, icon: CalendarX2, onClick: () => void stageDays.setDay(stageKey, null) }]; + return [ + ...items, + { divider: true }, + { label: noDay, icon: CalendarX2, onClick: () => void stageDays.setDay(stageKey, null) }, + ]; } /** @@ -55,7 +63,11 @@ export function StageDayPicker(props: StageDayPickerProps) { menu.close(); return; } - menu.open(event, dayItems(props, (option, at) => dayMenuLabel(option, at, t, locale), t('tours.stages.noDay')), true); + menu.open( + event, + dayItems(props, (option, at) => dayMenuLabel(option, at, t, locale), t('tours.stages.noDay')), + true + ); }; const look = day @@ -86,7 +98,9 @@ export function StageDayPicker(props: StageDayPickerProps) { {day ? t('dayplan.dayN', { n: index + 1 }) : t('tours.stages.noDay')} - {interactive &&