ptitlutins/app/utils/buildVoyageTree.ts
2026-06-15 23:34:49 +02:00

59 lines
1.6 KiB
TypeScript

import type { Event, Trip, Node, VoyageInfo } from "~/types"
import { byStart } from "./byStart"
import { eventToNode } from "./eventToNode"
import { formatDateRange } from "./formatDateRange"
/** Sentinel id for the synthetic voyage-root event; never sent to the API. */
const ROOT_EVENT_ID = -1
/** Build the unified node tree (voyage = root) from flat events + trips. */
export const buildVoyageTree = (
info: VoyageInfo,
events: Event[],
trips: Trip[],
): Node => {
const tripByStart = new Map<number, Trip>()
for (const t of trips) if (!tripByStart.has(t.eventStart)) tripByStart.set(t.eventStart, t)
const byParent = new Map<number | null, Event[]>()
for (const e of events) {
const p = e.parent ?? null
const arr = byParent.get(p) ?? []
arr.push(e)
byParent.set(p, arr)
}
const roots = (byParent.get(null) ?? [])
.slice()
.sort(byStart)
.map((e) => eventToNode(e, byParent, tripByStart))
const dated = roots.filter((n) => n.event.startDate)
const dateLabel = dated.length
? formatDateRange(
dated[0]!.event.startDate as string,
dated[dated.length - 1]!.event.startDate as string,
)
: undefined
// Synthetic root: gives the voyage a uniform `node.event` (so components read
// `node.event.title` at every level) without addressing a real event.
const rootEvent: Event = {
id: ROOT_EVENT_ID,
title: info.title,
startDate: null,
endDate: null,
location: null,
parent: null,
}
return {
id: "__voyage",
root: true,
event: rootEvent,
trip: null,
children: roots,
dateLabel,
lutins: info.lutins ?? [],
}
}