From d1d654ebac2d51e3841675faeb56480e440f622f Mon Sep 17 00:00:00 2001 From: Wolfgang Müller Date: Tue, 5 Mar 2024 18:08:09 +0100 Subject: Initial commit --- frontend/src/lib/Navigation.ts | 114 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 frontend/src/lib/Navigation.ts (limited to 'frontend/src/lib/Navigation.ts') diff --git a/frontend/src/lib/Navigation.ts b/frontend/src/lib/Navigation.ts new file mode 100644 index 0000000..e6b17cd --- /dev/null +++ b/frontend/src/lib/Navigation.ts @@ -0,0 +1,114 @@ +import { goto as svelteGoto } from '$app/navigation'; +import { SortDirection } from '$gql/graphql'; +import JsonURL from '@jsonurl/jsonurl'; +import { type PaginationData } from './Pagination'; +import { type SortData } from './Sort'; +import { toastError } from './Toasts'; + +function paramToNum(value: string | null, fallback: T) { + if (value) { + const number = +value; + + if (Number.isNaN(number) || number < 0) { + return fallback; + } + + return number; + } + + return fallback; +} + +export function parseSortData(params: URLSearchParams, fallback: T): SortData { + return { + on: (params.get('s') as T) || fallback, + direction: (params.get('d') as SortDirection) || SortDirection.Ascending, + seed: paramToNum(params.get('r'), undefined) + }; +} + +export function parsePaginationData(params: URLSearchParams, defaultItems = 120): PaginationData { + return { + page: paramToNum(params.get('p'), 1), + items: paramToNum(params.get('i'), defaultItems) + }; +} + +export function parseFilter(params: URLSearchParams): T { + const param = params.get('f'); + + if (!param) return {} as T; + + try { + return JsonURL.parse(param, { AQF: true, impliedObject: {} }) as T; + } catch (e) { + return {} as T; + } +} + +interface NavigationOptions { + to?: string; + params: URLSearchParams; + options?: Parameters[1]; +} + +export function goto({ to = '', params, options }: NavigationOptions) { + svelteGoto(`${to}?${params.toString()}`, options).catch(() => toastError('Navigation failed')); +} + +interface NavigationParameters { + filter?: T; + sort?: Partial>; + pagination?: Partial; +} + +function paramsFrom( + { pagination, filter, sort }: NavigationParameters, + current?: URLSearchParams +) { + const params = new URLSearchParams(current); + + if (filter !== undefined) { + const json = JsonURL.stringify(filter, { AQF: true, impliedObject: true }); + if (json) { + params.set('f', json); + } else { + params.delete('f'); + } + } + + if (sort !== undefined) { + if (sort.on !== undefined) { + params.set('s', sort.on); + } + if (sort.direction !== undefined) { + params.set('d', sort.direction); + } + if (sort.seed !== undefined) { + params.set('r', sort.seed.toString()); + } + } + + params.delete('p'); + + if (pagination?.items) { + params.set('i', pagination.items.toString()); + } + + if (pagination?.page) { + params.set('p', pagination.page.toString()); + } + + return params; +} + +export function navigate(parameters: NavigationParameters, current?: URLSearchParams) { + goto({ + params: paramsFrom(parameters, current), + options: { noScroll: false, keepFocus: true, replaceState: true } + }); +} + +export function href(base: string, params: NavigationParameters) { + return `/${base}/?${paramsFrom(params).toString()}`; +} -- cgit v1.2.3-2-gb3c3