fix(sync): re-hydrate active trip store on reconnect/online (H1) (#1181)

setRefetchCallback was dead code, so on reconnect the queue flushed and Dexie
re-seeded but the open trip's Zustand store was never refreshed — a
collaborator's edits made while we were offline didn't appear until navigating
away and back.

- new tripStore.hydrateActiveTrip(): silent refresh of the active trip's
  collaborative state (days/places/packing/todo/budget/reservations/files),
  no resetTrip and no isLoading toggle so there's no splash on reconnect
- syncTriggers wires setRefetchCallback to it (WS layer awaits the flush hook
  first) and re-hydrates open trips after the online-event syncAll; cleared on
  unregister
- websocket exposes getActiveTrips() for the online-event path
- tests: refetch wiring + ordering, silent hydrate without reset/splash
This commit is contained in:
jubnl
2026-06-15 09:32:28 +02:00
committed by GitHub
parent 1eb2cb8eb2
commit 39b5af790e
5 changed files with 160 additions and 4 deletions
+17
View File
@@ -66,6 +66,7 @@ export interface TripStoreState
handleRemoteEvent: (event: WebSocketEvent) => void
resetTrip: () => void
loadTrip: (tripId: number | string) => Promise<void>
hydrateActiveTrip: (tripId: number | string) => Promise<void>
refreshDays: (tripId: number | string) => Promise<void>
updateTrip: (tripId: number | string, data: Partial<Trip>) => Promise<Trip>
addTag: (data: Partial<Tag> & { name: string }) => Promise<Tag>
@@ -164,6 +165,22 @@ export const useTripStore = create<TripStoreState>((set, get) => ({
}
},
// Silently re-fetch the active trip's collaborative state into the store after
// the network comes back (WS reconnect or `online` event) so edits missed while
// offline appear in place — no splash, no resetTrip. Each resource is
// best-effort; a failure on one must not wipe the others.
hydrateActiveTrip: async (tripId: number | string) => {
await Promise.all([
get().refreshDays(tripId),
placeRepo.list(tripId).then(d => set({ places: d.places })).catch(() => {}),
packingRepo.list(tripId).then(d => set({ packingItems: d.items })).catch(() => {}),
todoRepo.list(tripId).then(d => set({ todoItems: d.items })).catch(() => {}),
get().loadBudgetItems(tripId),
get().loadReservations(tripId),
get().loadFiles(tripId),
])
},
refreshDays: async (tripId: number | string) => {
try {
const daysData = await dayRepo.list(tripId)