Files
TREK/client/src/components/shared/useDiscardGuard.ts
T
Maurice e4ed4bfc7b fix(mobile): the booking, transport and place sheets ask before dropping what was typed
On the phone a flick of the sheet's top edge, a tap on the scrim or
Escape closed the booking, transport and place forms and threw away
whatever had been typed, without a word; the desktop dialogs have asked
since #2253. The question moves into a shared hook that DialogShell and
MSheet both use, and the three sheets pass their form state to it.
2026-10-07 17:10:14 +02:00

37 lines
1.6 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react'
const snapshot = (value: unknown): string | null => {
try { return JSON.stringify(value) ?? null } catch { return null }
}
/**
* The unsaved-changes question (#2253) for a dialog or a sheet. `guard` is the
* editor's state, JSON-serialisable; undefined turns the question off. The
* state at the first key or pointer press (`markStart`) is the starting point,
* so whatever the editor loaded on open does not count as a change. The ways
* out a hand takes by accident go through `requestClose`, which asks before
* throwing away a state that differs from that starting point.
*/
export function useDiscardGuard(guard: unknown, onClose: () => void) {
const baseline = useRef<string | null>(null)
const guardRef = useRef(guard)
useEffect(() => { guardRef.current = guard })
const [asking, setAsking] = useState(false)
const markStart = useCallback(() => {
if (guardRef.current !== undefined && baseline.current === null) baseline.current = snapshot(guardRef.current)
}, [])
const requestClose = useCallback(() => {
if (guardRef.current !== undefined && baseline.current !== null && snapshot(guardRef.current) !== baseline.current) setAsking(true)
else onClose()
}, [onClose])
const keepEditing = useCallback(() => setAsking(false), [])
const discard = useCallback(() => { setAsking(false); onClose() }, [onClose])
/** Forget the starting point, for a surface that stays mounted between openings. */
const reset = useCallback(() => { baseline.current = null; setAsking(false) }, [])
return { asking, markStart, requestClose, keepEditing, discard, reset }
}