50 lines
2.4 KiB
TypeScript
50 lines
2.4 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useMemo, useState } from "react"
|
|
import { useSearchParams } from "next/navigation"
|
|
import type { FilterQuery } from "@/components/reui/filters/filters-types"
|
|
import { encodeBackupQuery, patchBackupsUrl, readBackupsUrl, validateBackupQuery, type BackupKindFilter, type BackupsTab } from "@/lib/data-filters/backups-url-state"
|
|
|
|
export function useBackupsUrlState() {
|
|
const params = useSearchParams()
|
|
const raw = params.toString()
|
|
const state = useMemo(() => readBackupsUrl(new URLSearchParams(raw)), [raw])
|
|
const filterKey = params.get("filters")
|
|
const [draft, setDraft] = useState<{ key: string | null; query: FilterQuery; error: string | null } | null>(null)
|
|
useEffect(() => {
|
|
const reset = () => setDraft(null)
|
|
window.addEventListener("popstate", reset)
|
|
return () => window.removeEventListener("popstate", reset)
|
|
}, [])
|
|
function write(changes: Record<string, string | null>, replace = false) {
|
|
const href = patchBackupsUrl(new URLSearchParams(window.location.search), changes) + window.location.hash
|
|
if (href === window.location.pathname + window.location.search + window.location.hash) return
|
|
if (replace) window.history.replaceState(null, "", href)
|
|
else window.history.pushState(null, "", href)
|
|
}
|
|
function setFilters(query: FilterQuery) {
|
|
if (validateBackupQuery(query) === "draft") { setDraft({ key: filterKey, query, error: null }); return }
|
|
try {
|
|
const encoded = encodeBackupQuery(query)
|
|
setDraft(null)
|
|
write({ filters: encoded })
|
|
} catch (error) {
|
|
setDraft({ key: filterKey, query, error: error instanceof Error ? error.message : "Некорректный фильтр." })
|
|
}
|
|
}
|
|
const currentDraft = draft?.key === filterKey ? draft : null
|
|
return {
|
|
search: state.search,
|
|
kindFilter: state.kind,
|
|
tab: state.tab,
|
|
filters: currentDraft?.query ?? state.query,
|
|
error: state.error ?? currentDraft?.error ?? null,
|
|
hasFilters: params.has("q") || params.has("kind") || params.has("filters") || currentDraft !== null,
|
|
setSearch: (value: string) => write({ q: value }, true),
|
|
setKindFilter: (value: BackupKindFilter) => write({ kind: value === "all" ? null : value }),
|
|
setTab: (value: BackupsTab) => write({ tab: value === "history" ? null : value }),
|
|
setFilters,
|
|
reset: () => { setDraft(null); write({ q: null, kind: null, tab: null, filters: null }) },
|
|
}
|
|
}
|