From a1c5917e626856f2abd9dbe6ddaa71c1458334c6 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 26 Apr 2024 14:31:48 -0300 Subject: update code to match others --- packages/aml-backoffice-ui/src/route.ts | 239 -------------------------------- 1 file changed, 239 deletions(-) delete mode 100644 packages/aml-backoffice-ui/src/route.ts (limited to 'packages/aml-backoffice-ui/src/route.ts') diff --git a/packages/aml-backoffice-ui/src/route.ts b/packages/aml-backoffice-ui/src/route.ts deleted file mode 100644 index ffd54d6af..000000000 --- a/packages/aml-backoffice-ui/src/route.ts +++ /dev/null @@ -1,239 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ -import { TranslatedString } from "@gnu-taler/taler-util"; -import { createHashHistory } from "history"; -import { ComponentChildren, h as create, createContext, VNode } from "preact"; -import { useContext, useEffect, useState } from "preact/hooks"; - -type ContextType = { - onChange: (listener: () => void) => VoidFunction; -}; -const nullChangeListener = { onChange: () => () => {} }; -const Context = createContext(nullChangeListener); - -export const usePathChangeContext = (): ContextType => useContext(Context); - -export function HashPathProvider({ - children, -}: { - children: ComponentChildren; -}): VNode { - const history = createHashHistory(); - return create( - Context.Provider, - { value: { onChange: history.listen }, children }, - children, - ); -} - -type PageDefinition> = { - pattern: string; - (params: DynamicPart): string; -}; - -function replaceAll( - pattern: string, - vars: Record, - values: Record, -): string { - let result = pattern; - for (const v in vars) { - result = result.replace(vars[v], !values[v] ? "" : values[v]); - } - return result; -} - -export function pageDefinition>( - pattern: string, -): PageDefinition { - const patternParams = pattern.match(/(:[\w?]*)/g); - if (!patternParams) - throw Error( - `page definition pattern ${pattern} doesn't have any parameter`, - ); - - const vars = patternParams.reduce( - (prev, cur) => { - const pName = cur.match(/(\w+)/g); - - //skip things like :? in the path pattern - if (!pName || !pName[0]) return prev; - const name = pName[0]; - return { ...prev, [name]: cur }; - }, - {} as Record, - ); - - const f = (values: T): string => replaceAll(pattern, vars, values); - f.pattern = pattern; - return f; -} - -export type PageEntry = T extends Record - ? { - url: PageDefinition; - view: (props: T) => VNode; - name: TranslatedString; - Icon?: () => VNode; - } - : T extends unknown - ? { - url: string; - view: (props: {}) => VNode; - name: TranslatedString; - Icon?: () => VNode; - } - : never; - -export function Router({ - pageList, - onNotFound, -}: { - pageList: Array>; - onNotFound: () => VNode; -}): VNode { - const current = useCurrentLocation(pageList); - if (current !== undefined) { - return create(current.page.view, current.values); - } - return onNotFound(); -} - -type Location = { - page: PageEntry; - path: string; - values: Record; -}; -export function useCurrentLocation( - pageList: Array>, -): Location | undefined { - const [currentLocation, setCurrentLocation] = useState< - Location | null | undefined - >(null); - const path = usePathChangeContext(); - useEffect(() => { - return path.onChange(() => { - const result = doSync( - window.location.hash, - new URLSearchParams(window.location.search), - pageList, - ); - setCurrentLocation(result); - }); - }, []); - if (currentLocation === null) { - return doSync( - window.location.hash, - new URLSearchParams(window.location.search), - pageList, - ); - } - return currentLocation; -} - -export function useChangeLocation() { - const [location, setLocation] = useState(window.location.hash); - const path = usePathChangeContext(); - useEffect(() => { - return path.onChange(() => { - setLocation(window.location.hash); - }); - }, []); - return location; -} - -/** - * Search path in the pageList - * get the values from the path found - * add params from searchParams - * - * @param path - * @param params - */ -export function doSync( - path: string, - params: URLSearchParams, - pageList: Array>, -): Location | undefined { - for (let idx = 0; idx < pageList.length; idx++) { - const page = pageList[idx]; - if (typeof page.url === "string") { - if (page.url === path) { - const values: Record = {}; - params.forEach((v, k) => { - values[k] = v; - }); - return { page, values, path }; - } - } else { - const values = doestUrlMatchToRoute(path, page.url.pattern); - if (values !== undefined) { - params.forEach((v, k) => { - values[k] = v; - }); - return { page, values, path }; - } - } - } - return undefined; -} - -function doestUrlMatchToRoute( - url: string, - route: string, -): undefined | Record { - const paramsPattern = /(?:\?([^#]*))?$/; - // const paramsPattern = /(?:\?([^#]*))?(#.*)?$/; - const params = url.match(paramsPattern); - const urlWithoutParams = url.replace(paramsPattern, ""); - - const result: Record = {}; - if (params && params[1]) { - const paramList = params[1].split("&"); - for (let i = 0; i < paramList.length; i++) { - const idx = paramList[i].indexOf("="); - const name = paramList[i].substring(0, idx); - const value = paramList[i].substring(idx + 1); - result[decodeURIComponent(name)] = decodeURIComponent(value); - } - } - const urlSeg = urlWithoutParams.split("/"); - const routeSeg = route.split("/"); - let max = Math.max(urlSeg.length, routeSeg.length); - for (let i = 0; i < max; i++) { - if (routeSeg[i] && routeSeg[i].charAt(0) === ":") { - const param = routeSeg[i].replace(/(^:|[+*?]+$)/g, ""); - - const flags = (routeSeg[i].match(/[+*?]+$/) || EMPTY)[0] || ""; - const plus = ~flags.indexOf("+"); - const star = ~flags.indexOf("*"); - const val = urlSeg[i] || ""; - - if (!val && !star && (flags.indexOf("?") < 0 || plus)) { - return undefined; - } - result[param] = decodeURIComponent(val); - if (plus || star) { - result[param] = urlSeg.slice(i).map(decodeURIComponent).join("/"); - break; - } - } else if (routeSeg[i] !== urlSeg[i]) { - return undefined; - } - } - return result; -} -const EMPTY: Record = {}; -- cgit v1.2.3