type CalcSearchDraft = { from: string to: string cargo: string fromLat: number | null fromLng: number | null toLat: number | null toLng: number | null } type CalcSearchDraftPatch = Partial const initialCalcSearchDraft = (): CalcSearchDraft => ({ from: '', to: '', cargo: '', fromLat: null, fromLng: null, toLat: null, toLng: null, }) function stringParam(value: unknown) { return typeof value === 'string' ? value.trim() : '' } function numberParam(value: unknown) { const num = Number(value) return Number.isFinite(num) ? num : null } export function useCalcSearchDraft() { const draft = useState('calc-search-draft', initialCalcSearchDraft) function hydrateFromQuery(query: Record) { const nextDraft = { ...draft.value } const from = stringParam(query.from) const to = stringParam(query.to) const cargo = stringParam(query.cargo) const fromLat = numberParam(query.fromLat) const fromLng = numberParam(query.fromLng) const toLat = numberParam(query.toLat) const toLng = numberParam(query.toLng) if (from) nextDraft.from = from if (to) nextDraft.to = to if (cargo) nextDraft.cargo = cargo if (fromLat !== null) nextDraft.fromLat = fromLat if (fromLng !== null) nextDraft.fromLng = fromLng if (toLat !== null) nextDraft.toLat = toLat if (toLng !== null) nextDraft.toLng = toLng draft.value = nextDraft } function patchDraft(patch: CalcSearchDraftPatch) { draft.value = { ...draft.value, ...patch, } } function buildQuery(patch: CalcSearchDraftPatch = {}) { const nextDraft = { ...draft.value, ...patch, } return { ...(nextDraft.from.trim() ? { from: nextDraft.from.trim() } : {}), ...(nextDraft.to.trim() ? { to: nextDraft.to.trim() } : {}), ...(nextDraft.cargo.trim() ? { cargo: nextDraft.cargo.trim() } : {}), ...(nextDraft.fromLat !== null ? { fromLat: String(nextDraft.fromLat) } : {}), ...(nextDraft.fromLng !== null ? { fromLng: String(nextDraft.fromLng) } : {}), ...(nextDraft.toLat !== null ? { toLat: String(nextDraft.toLat) } : {}), ...(nextDraft.toLng !== null ? { toLng: String(nextDraft.toLng) } : {}), } } return { draft, hydrateFromQuery, patchDraft, buildQuery, } }