diff --git a/client/src/components/Admin/paddle/PaddleRegionsPanel.tsx b/client/src/components/Admin/paddle/PaddleRegionsPanel.tsx index 52d64e777..10f333bbf 100644 --- a/client/src/components/Admin/paddle/PaddleRegionsPanel.tsx +++ b/client/src/components/Admin/paddle/PaddleRegionsPanel.tsx @@ -3,6 +3,7 @@ import { Check, ChevronRight, Loader2, Plus, RefreshCw, Search, Trash2, Waves, W import { useId } from 'react'; import { useDateFormat } from '../../../hooks/useDateFormat'; import { useTranslation } from '../../../i18n'; +import { formatDisplayDate } from '../../../utils/dateFormat'; import { SettingRows, SETTINGS_BUTTON, @@ -16,7 +17,6 @@ import { EditorField, INPUT } from '../../shared/dialogParts'; import { fs } from '../../shared/DialogShell'; import ErrorBoundary from '../../shared/ErrorBoundary'; import { Tooltip } from '../../shared/Tooltip'; -import { formatDisplayDate } from '../../../utils/dateFormat'; import { AutoLoadSettings, AutoOriginPill, RequestList } from './PaddleAutoLoadParts'; import { progressPercent, regionStatusTone } from './paddleRegionsModel'; import { usePaddleRegionsAdmin } from './usePaddleRegionsAdmin'; diff --git a/client/src/components/Map/MapView.leaflet.test.tsx b/client/src/components/Map/MapView.leaflet.test.tsx index 4bc8b7ab1..7e8ea5b09 100644 --- a/client/src/components/Map/MapView.leaflet.test.tsx +++ b/client/src/components/Map/MapView.leaflet.test.tsx @@ -506,6 +506,8 @@ describe('MapView on a real Leaflet map', () => { return found as L.Marker | null } await waitFor(() => expect(marker()?.getLatLng().lng).toBeCloseTo(23.73, 6)) - expect(map.getBounds().contains(marker()!.getLatLng())).toBe(true) + const drawnMarker = marker() + expect(drawnMarker).not.toBeNull() + expect(drawnMarker && map.getBounds().contains(drawnMarker.getLatLng())).toBe(true) }) }) diff --git a/client/src/components/Packing/PackingBringersCard.test.tsx b/client/src/components/Packing/PackingBringersCard.test.tsx index fd72a28b4..c7357d877 100644 --- a/client/src/components/Packing/PackingBringersCard.test.tsx +++ b/client/src/components/Packing/PackingBringersCard.test.tsx @@ -1,7 +1,8 @@ // FE-PACK-BRINGERCARD-001 to FE-PACK-BRINGERCARD-004 import { describe, expect, it } from 'vitest'; import { render, screen } from '../../../tests/helpers/render'; -import { BringersCard, MoreBringers, bringersOf } from './PackingBringersCard'; +import { BringersCard, MoreBringers } from './PackingBringersCard'; +import { bringersOf } from './packingBringers'; const members = [ { id: 1, username: 'anna', avatar_url: '/uploads/avatars/anna.jpg' }, diff --git a/client/src/components/Packing/PackingBringersCard.tsx b/client/src/components/Packing/PackingBringersCard.tsx index b2437e080..021644063 100644 --- a/client/src/components/Packing/PackingBringersCard.tsx +++ b/client/src/components/Packing/PackingBringersCard.tsx @@ -1,37 +1,6 @@ import type { CSSProperties } from 'react'; import { useTranslation } from '../../i18n'; -import type { TripMember } from './usePackingListPanel'; - -/** One person bringing a common item: the name, and the picture when the trip knows one. */ -export interface Bringer { - name: string; - avatar: string | null; -} - -/** The item's bringer first, then whoever also brings it, each once, with their picture from the trip's members. */ -export function bringersOf( - item: { - owner_id?: number | null; - owner_username?: string | null; - contributors?: { user_id: number; username: string }[] | null; - }, - members: readonly TripMember[] -): Bringer[] { - const avatarOf = (id: number | null | undefined) => { - const member = id == null ? undefined : members.find((m) => m.id === id); - return member?.avatar_url ?? member?.avatar ?? null; - }; - const all = [ - ...(item.owner_username ? [{ id: item.owner_id ?? null, name: item.owner_username }] : []), - ...(item.contributors ?? []).map((c) => ({ id: c.user_id, name: c.username })), - ]; - const bringers: Bringer[] = []; - for (const person of all) { - if (bringers.some((b) => b.name === person.name)) continue; - bringers.push({ name: person.name, avatar: avatarOf(person.id) }); - } - return bringers; -} +import type { Bringer } from './packingBringers'; const CIRCLE: CSSProperties = { width: 20, diff --git a/client/src/components/Packing/PackingListPanelItemRow.tsx b/client/src/components/Packing/PackingListPanelItemRow.tsx index ada2259b6..1bf4be338 100644 --- a/client/src/components/Packing/PackingListPanelItemRow.tsx +++ b/client/src/components/Packing/PackingListPanelItemRow.tsx @@ -18,9 +18,9 @@ import { PopoverItem } from './PackingPopover' import { POPOVER, POPOVER_CAPTION, POPOVER_DIVIDER } from './packingPopoverStyles' import type { TripMember } from './usePackingListPanel' import { NumericInput } from '../shared/NumericInput' -import { packingBringerNames } from './packingBringers' +import { bringersOf, packingBringerNames } from './packingBringers' import { Tooltip } from '../shared/Tooltip' -import { BringerAvatar, BringersCard, MoreBringers, bringersOf } from './PackingBringersCard' +import { BringerAvatar, BringersCard, MoreBringers } from './PackingBringersCard' interface ArtikelZeileProps { item: PackingItem diff --git a/client/src/components/Packing/packingBringers.ts b/client/src/components/Packing/packingBringers.ts index a0dd70883..0550c9d76 100644 --- a/client/src/components/Packing/packingBringers.ts +++ b/client/src/components/Packing/packingBringers.ts @@ -1,3 +1,5 @@ +import type { TripMember } from './usePackingListPanel'; + interface BroughtItem { owner_username?: string | null; contributors?: { username: string }[] | null; @@ -12,3 +14,34 @@ export function packingBringerNames(item: BroughtItem): string { const names = [item.owner_username, ...(item.contributors ?? []).map((c) => c.username)]; return [...new Set(names.filter((n): n is string => !!n))].join(', '); } + +/** One person bringing a common item: the name, and the picture when the trip knows one. */ +export interface Bringer { + name: string; + avatar: string | null; +} + +/** The item's bringer first, then whoever also brings it, each once, with their picture from the trip's members. */ +export function bringersOf( + item: { + owner_id?: number | null; + owner_username?: string | null; + contributors?: { user_id: number; username: string }[] | null; + }, + members: readonly TripMember[] +): Bringer[] { + const avatarOf = (id: number | null | undefined) => { + const member = id == null ? undefined : members.find((m) => m.id === id); + return member?.avatar_url ?? member?.avatar ?? null; + }; + const all = [ + ...(item.owner_username ? [{ id: item.owner_id ?? null, name: item.owner_username }] : []), + ...(item.contributors ?? []).map((c) => ({ id: c.user_id, name: c.username })), + ]; + const bringers: Bringer[] = []; + for (const person of all) { + if (bringers.some((b) => b.name === person.name)) continue; + bringers.push({ name: person.name, avatar: avatarOf(person.id) }); + } + return bringers; +} diff --git a/client/src/components/Roadtrip/RoadtripSidebarHeaders.test.tsx b/client/src/components/Roadtrip/RoadtripSidebarHeaders.test.tsx index dcfc2d35a..2adc1c1ae 100644 --- a/client/src/components/Roadtrip/RoadtripSidebarHeaders.test.tsx +++ b/client/src/components/Roadtrip/RoadtripSidebarHeaders.test.tsx @@ -108,7 +108,7 @@ describe('DayHeader', () => { const tileDate = (time_format: string, date_format: string): string | null => { useSettingsStore.setState({ settings: { distance_unit: 'metric', time_format, date_format } as never }) const { container, unmount } = wrap() - const text = container.querySelector('time')!.textContent + const text = container.querySelector('time')?.textContent ?? null unmount() return text } diff --git a/client/src/utils/dayMerge.test.ts b/client/src/utils/dayMerge.test.ts index d9610f70a..3925d604b 100644 --- a/client/src/utils/dayMerge.test.ts +++ b/client/src/utils/dayMerge.test.ts @@ -740,7 +740,7 @@ describe('getMergedItems: bookings in different time zones (#2929)', () => { const laxSea = { ...toSeattle, endpoints: ends(LAX, SEA) } const stopAt = (id: number, time: string, lat: number, lng: number) => ({ id, order_index: id, place: { place_time: time, lat, lng } }) - const drawn = (dayAssignments: any[], dayTransports: any[]) => + const drawn = (dayAssignments: Parameters[0]['dayAssignments'], dayTransports: Parameters[0]['dayTransports']) => getMergedItems({ dayAssignments, dayNotes: [], dayTransports, dayId: DAY }) const labels = (items: MergedItem[]) => items.map(i => `${i.type}:${i.data.id}`) diff --git a/server/tests/unit/nest/assistant/assistant-history.test.ts b/server/tests/unit/nest/assistant/assistant-history.test.ts index ab7a12038..1e1b59e2d 100644 --- a/server/tests/unit/nest/assistant/assistant-history.test.ts +++ b/server/tests/unit/nest/assistant/assistant-history.test.ts @@ -671,7 +671,10 @@ describe('toChatHistory: calls the model made of the server tools (#2845)', () = const chat = toChatMessages({ system: '', messages: anthropic, tools: [] }); chat.forEach((message, index) => { if (message.role !== 'tool') return; - const before = chat.slice(0, index).reverse().find((earlier) => earlier.role === 'assistant'); + const before = chat + .slice(0, index) + .reverse() + .find((earlier) => earlier.role === 'assistant'); const named = ((before?.tool_calls ?? []) as Array<{ id: string }>).map((call) => call.id); expect(named).toContain(message.tool_call_id); }); diff --git a/shared/src/budget/cost-category.spec.ts b/shared/src/budget/cost-category.spec.ts index 4f4b98f3a..c7150cf69 100644 --- a/shared/src/budget/cost-category.spec.ts +++ b/shared/src/budget/cost-category.spec.ts @@ -1,7 +1,7 @@ // COST-CATEGORY-001 to COST-CATEGORY-007: a typed category read as one of the fixed keys. +import { RESERVATION_TYPES } from '../reservation/reservation-types'; import { COST_CATEGORIES } from './budget.schema'; import { COST_CATEGORY_HINT, costCategoryOf, storedCostCategory, typeToCostCategory } from './cost-category'; -import { RESERVATION_TYPES } from '../reservation/reservation-types'; import { describe, expect, it } from 'vitest';