mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
7fffd4300f
PAD-06 and PAD-09 on the client's data side. A tour's cached row keeps its checklist beside its provenance, written through one cache helper by the repository and the queue replay, which also keeps provenance an answer lacks. The checklist is read for the bench the list shows and served from the cache while its revision matches. Decisions made offline, or behind a queued write of the same tour, change the cached checklist and bench at once under a local revision and replay with their idempotency key; a route written offline marks the checklist stale until the server judged it. The obstacle store learns a camera focus: a click in the rail moves the camera onto an obstacle and the other parts of its lock, the newest of such a focus and a picked search result wins, and a selected lock lights up whole on both maps. The checklist hook and its model hold the logic the cards will show.
60 lines
2.2 KiB
TypeScript
60 lines
2.2 KiB
TypeScript
import { useCallback, useState } from 'react';
|
|
import type { LocationPoint } from '../../components/Planner/LocationSelect';
|
|
import type { PaddleFocus } from '../../store/paddleObstacleStore';
|
|
|
|
interface CameraIntent {
|
|
plannerFocusKey: number;
|
|
sequence: number;
|
|
/** A picked search result, or an obstacle or area the paddle checklist asked for. */
|
|
kind: 'search' | 'paddle';
|
|
points: [number, number][];
|
|
}
|
|
|
|
/**
|
|
* The TOUR-PLANNER location search: a picked result only moves the camera.
|
|
* A focus the paddle checklist asks for (PAD-06) is an intent of the same
|
|
* kind, and the newest of them wins until the planner bumps its own focus key.
|
|
*/
|
|
export function useMapLocationSearch(
|
|
plannerFocusKey: number,
|
|
focusPoints: [number, number][],
|
|
paddleFocus: PaddleFocus | null = null
|
|
) {
|
|
const [locationSearchValue, setLocationSearchValue] = useState<LocationPoint | null>(null);
|
|
const [intent, setIntent] = useState<CameraIntent | null>(null);
|
|
const [seenPaddleSeq, setSeenPaddleSeq] = useState(paddleFocus?.seq ?? null);
|
|
// A new focus from the checklist becomes the newest intent, adjusted while rendering as React advises for a changed prop.
|
|
if ((paddleFocus?.seq ?? null) !== seenPaddleSeq) {
|
|
setSeenPaddleSeq(paddleFocus?.seq ?? null);
|
|
if (paddleFocus && paddleFocus.points.length > 0) {
|
|
const points = paddleFocus.points;
|
|
setIntent((current) => ({ plannerFocusKey, sequence: (current?.sequence ?? 0) + 1, kind: 'paddle', points }));
|
|
}
|
|
}
|
|
const onLocationSearchChange = useCallback(
|
|
(location: LocationPoint | null) => {
|
|
setLocationSearchValue(location);
|
|
if (!location) return;
|
|
setIntent((current) => ({
|
|
plannerFocusKey,
|
|
sequence: (current?.sequence ?? 0) + 1,
|
|
kind: 'search',
|
|
points: [[location.lat, location.lng]],
|
|
}));
|
|
},
|
|
[plannerFocusKey]
|
|
);
|
|
|
|
const current = intent?.plannerFocusKey === plannerFocusKey ? intent : null;
|
|
const mapFocusPoints = current ? current.points : focusPoints;
|
|
const mapFocusKey = current
|
|
? `tour:${plannerFocusKey}:${current.kind}:${current.sequence}`
|
|
: `tour:${plannerFocusKey}`;
|
|
|
|
return {
|
|
mapFocusPoints,
|
|
mapFocusKey,
|
|
locationSearch: { value: locationSearchValue, onChange: onLocationSearchChange },
|
|
};
|
|
}
|