Files
TREK/client/src/components/Planner/assignmentOptions.ts
T
Maurice 07e4a558e6 fix(bookings): the phone keeps a booking's stop and shows the files it already has (#2216, #2217)
Editing a booking on the phone erased the stop it was linked to. The sheet
seeded its assignment from the create-for-a-stop flag, which is null on an
edit, and saved that straight back over a link the user had made on the
desktop; the server writes the field whenever the key is present. It now
seeds from the booking being edited, and the picker the desktop dialog has
always had sits in the sheet too, so a stop can be seen, changed and cleared
from a phone. The option list moved to its own module rather than being
copied.

Two more of the same shape, found on the way. The endpoint set was sent as an
empty list on every save, and the server swaps the whole set when that key is
present, so editing a transit booking dropped its stations; neither form
edits endpoints, so an edit no longer sends the key at all. And the sheet's
Files block listed only what was picked in this session, so a file uploaded
from the desktop was invisible on the phone. It lists what is attached now,
resolved the way the desktop resolves it.

A place also shows the files of the bookings that sit on it, on the phone and
on the desktop: a confirmation lives on the booking, and the place card was
the one screen that could not reach it.
2026-09-03 15:51:13 +02:00

53 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Assignment, Day, TranslationFn } from '../../types'
/** Day and month only, the shape the booking dialog has always shown here. */
function dayBadge(dateStr: string, locale?: string): string {
return new Date(dateStr + 'T00:00:00Z')
.toLocaleDateString(locale || undefined, { day: 'numeric', month: 'short', timeZone: 'UTC' })
}
export interface AssignmentOption {
value: number | string
label: string
searchLabel?: string
groupLabel?: string
dayDate?: string | null
disabled?: boolean
isHeader?: boolean
}
/**
* The day plan as a flat option list: a disabled header per day, then its stops
* in plan order. Shared by the desktop booking dialog and the phone sheet so a
* booking can be linked to the same stop from either (#2216).
*/
export function buildAssignmentOptions(
days: Day[] | undefined,
assignments: Record<string, Assignment[]> | undefined,
t: TranslationFn,
locale?: string,
): AssignmentOption[] {
const options: AssignmentOption[] = []
for (const day of (days || [])) {
const da = (assignments?.[String(day.id)] || []).slice().sort((a, b) => a.order_index - b.order_index)
if (da.length === 0) continue
const dayLabel = day.title || t('dayplan.dayN', { n: day.day_number })
const dateStr = day.date ? ` · ${dayBadge(day.date, locale)}` : ''
const groupLabel = `${dayLabel}${dateStr}`
options.push({ value: `_header_${day.id}`, label: groupLabel, disabled: true, isHeader: true })
for (let i = 0; i < da.length; i++) {
const place = da[i].place
if (!place) continue
const timeStr = place.place_time ? ` · ${place.place_time}${place.end_time ? ' – ' + place.end_time : ''}` : ''
options.push({
value: da[i].id,
label: ` ${i + 1}. ${place.name}${timeStr}`,
searchLabel: place.name,
groupLabel,
dayDate: day.date || null,
})
}
}
return options
}