fix(planner): let the day list see which stop a booking wrote

The row shapers name every column they pass on, and accommodation_id was in
none of them. So the field the day list hides on never reached the client, and
the booked night was listed as an ordinary place next to the overnight block
that already named it. The stop was correct in the table the whole time; the
three read paths just dropped it on the way out.

The stamp on the freshly written stop had the same hole from the other side: the
INSERT went in without the booking id and an UPDATE added it afterwards, so the
row handed back in the answer, the one the client that booked the night puts
straight into its store, carried none. It goes in with the INSERT now.

The shared link gains the same filter. It has no road trip view to need the stop
and already shows the booking as its own chip on the day, so the row was only
ever the same hotel twice.
This commit is contained in:
Maurice
2026-09-13 12:59:19 +02:00
parent e3471e2dc8
commit d0d3f455a8
9 changed files with 72 additions and 9 deletions
@@ -255,11 +255,13 @@ export class AccommodationsService {
// Through AssignmentsService, so the stop lands at the end of the day with the
// order_index every other new assignment gets. Evening is where you arrive at a
// hotel, and the day planner has no drive to position it against anyway.
const created = this.assignments.createAssignment(dayId, placeId);
if (created) {
this.db.run('UPDATE day_assignments SET accommodation_id = ? WHERE id = ?', accommodationId, created.id);
mirror.created = created;
}
//
// The booking id goes in with the INSERT, not as an UPDATE afterwards: what this
// returns is the row the answer hands the client, and stamping the id on later
// would leave that copy without it. The day list has nothing else to tell the
// stop from a place the traveller added, so it would show the hotel a second
// time until the next reload.
mirror.created = this.assignments.createAssignment(dayId, placeId, null, { accommodationId });
return mirror;
}
@@ -124,14 +124,21 @@ export class AssignmentsService {
return !!this.dbs.get('SELECT id FROM places WHERE id = ? AND trip_id = ?', placeId, tripId);
}
createAssignment(dayId: string | number, placeId: unknown, notes?: string | null) {
/**
* @param opts.accommodationId The lodging booking this stop belongs to, when a
* booking is what put it there. Written by the INSERT rather than stamped on
* afterwards: the row this returns is what the answer hands the client, and a
* stop that reaches it without its booking id is one the day list cannot tell
* from a place the traveller added, so it draws the hotel a second time.
*/
createAssignment(dayId: string | number, placeId: unknown, notes?: string | null, opts: { accommodationId?: number } = {}) {
const result = this.dbs.transaction(() => {
const maxOrder = this.dbs.get<{ max: number | null }>('SELECT MAX(order_index) as max FROM day_assignments WHERE day_id = ?', dayId)!;
const orderIndex = (maxOrder.max !== null ? maxOrder.max : -1) + 1;
return this.dbs.run(
'INSERT INTO day_assignments (day_id, place_id, order_index, notes) VALUES (?, ?, ?, ?)',
dayId, placeId, orderIndex, notes || null
'INSERT INTO day_assignments (day_id, place_id, order_index, notes, accommodation_id) VALUES (?, ?, ?, ?, ?)',
dayId, placeId, orderIndex, notes || null, opts.accommodationId ?? null
);
});
+4
View File
@@ -21,6 +21,10 @@ export function formatAssignmentWithPlace(a: AssignmentRow, tags: Partial<Tag>[]
end_day: a.end_day === 1,
leg_transport_mode: a.leg_transport_mode ?? null,
incoming_leg_transport_mode: a.incoming_leg_transport_mode ?? null,
// Which booking put this stop here, if a booking did. The day list has nothing
// else to tell it from a place the traveller added, and it must not draw the
// hotel a second time under the overnight block that already names it.
accommodation_id: a.accommodation_id ?? null,
participants: participants || [],
created_at: a.created_at,
place: {
+3
View File
@@ -114,6 +114,9 @@ export class DaysService {
order_index: a.order_index,
end_day: a.end_day === 1,
notes: a.notes,
// Repeated here for the same reason stop_type is: the day list hides the stop
// a booking wrote, and this copy is one of the paths that feed it.
accommodation_id: a.accommodation_id ?? null,
created_at: a.created_at,
place: {
id: a.place_id,
+3
View File
@@ -316,6 +316,9 @@ export class ShareService {
if (!byDay[a.day_id]) byDay[a.day_id] = [];
byDay[a.day_id].push({
id: a.id, day_id: a.day_id, order_index: a.order_index, notes: a.notes,
// The shared page shows the booking as its own chip on the day, so it needs
// to know which stop is that booking and leave it out of the list.
accommodation_id: a.accommodation_id ?? null,
place: {
id: a.place_id, name: a.place_name, description: a.place_description,
lat: a.lat, lng: a.lng, address: a.address, category_id: a.category_id,
+2
View File
@@ -120,6 +120,8 @@ export interface DayAssignment {
end_day?: number;
leg_transport_mode?: string | null;
incoming_leg_transport_mode?: string | null;
/** The lodging booking that put this stop on the day, when one did. */
accommodation_id?: number | null;
created_at?: string;
}