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()}`; }