Files
TREK/client/src/components/Tours/walk/useTourVisitsSync.ts
T
Maurice e803d28bf1 feat(tours): check a city walk's stops off for the day it is on (CW-03)
The walk's detail opened from a day lists its stops in order, each with its
stay, importance and protection, and marks one visited or skipped for that
day, or takes it back. The day row shows how many were visited. Marks reach
the other travellers at once and change no route, place or order; a copy or
another day starts with none.
2026-10-20 02:49:47 +00:00

40 lines
1.5 KiB
TypeScript

import { tourVisitSchema } from '@trek/shared';
import { useEffect } from 'react';
import { addListener, removeListener } from '../../../api/websocket';
import { useTourVisitStore } from '../../../store/tourVisitStore';
import type { WebSocketEvent } from '../../../types';
/**
* CW-03: the visits of a trip's city walks, read when the trip opens and kept
* current by its socket, so a station another traveller checks off shows on
* every day plan at once. Offline the day plan shows none until it is back.
*/
export function useTourVisitsSync(tripId: number | string | undefined, enabled: boolean) {
useEffect(() => {
if (!enabled || tripId === undefined) return;
let current = true;
useTourVisitStore
.getState()
.load(tripId)
.catch(() => {
// Offline or refused, the day plan shows no progress rather than another trip's.
if (current) useTourVisitStore.getState().reset(tripId);
});
const onEvent = (event: WebSocketEvent) => {
if (event?.type !== 'tours:visits' || String(event.tripId ?? '') !== String(tripId)) return;
const visits = Array.isArray(event.visits)
? event.visits.flatMap((raw) => {
const parsed = tourVisitSchema.safeParse(raw);
return parsed.success ? [parsed.data] : [];
})
: [];
useTourVisitStore.getState().applyRemote(Number(event.assignmentId), visits);
};
addListener(onEvent);
return () => {
current = false;
removeListener(onEvent);
};
}, [enabled, tripId]);
}