aboutsummaryrefslogtreecommitdiff
path: root/packages/aml-backoffice-ui/src/route.ts
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-06-05 10:04:09 -0300
committerSebastian <sebasjm@gmail.com>2023-06-05 10:04:09 -0300
commitc680f5aa71b08e978444df07f93c381f9d47ab82 (patch)
tree81903fac003bb1e202cf69551e06ba41a6e960a5 /packages/aml-backoffice-ui/src/route.ts
parentdf53866e6b148ea5fd2ab57e906a4aa36b535ed3 (diff)
downloadwallet-core-c680f5aa71b08e978444df07f93c381f9d47ab82.tar.xz
rename aml
Diffstat (limited to 'packages/aml-backoffice-ui/src/route.ts')
-rw-r--r--packages/aml-backoffice-ui/src/route.ts167
1 files changed, 167 insertions, 0 deletions
diff --git a/packages/aml-backoffice-ui/src/route.ts b/packages/aml-backoffice-ui/src/route.ts
new file mode 100644
index 000000000..d54f9be83
--- /dev/null
+++ b/packages/aml-backoffice-ui/src/route.ts
@@ -0,0 +1,167 @@
+import { createHashHistory } from "history";
+import { h as create, VNode } from "preact";
+import { useEffect, useState } from "preact/hooks";
+const history = createHashHistory();
+
+type PageDefinition<DynamicPart extends Record<string, string>> = {
+ pattern: string;
+ (params: DynamicPart): string;
+};
+
+function replaceAll(
+ pattern: string,
+ vars: Record<string, string>,
+ values: Record<string, string>,
+): string {
+ let result = pattern;
+ for (const v in vars) {
+ result = result.replace(vars[v], !values[v] ? "" : values[v]);
+ }
+ return result;
+}
+
+export function pageDefinition<T extends Record<string, string>>(
+ pattern: string,
+): PageDefinition<T> {
+ 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<string, string>);
+
+ const f = (values: T): string => replaceAll(pattern, vars, values);
+ f.pattern = pattern;
+ return f;
+}
+
+export type PageEntry<T = unknown> = T extends Record<string, string>
+ ? {
+ url: PageDefinition<T>;
+ view: (props: T) => VNode;
+ }
+ : T extends unknown
+ ? {
+ url: string;
+ view: (props: {}) => VNode;
+ }
+ : never;
+
+export function Router({
+ pageList,
+ onNotFound,
+}: {
+ pageList: Array<PageEntry<any>>;
+ onNotFound: () => VNode;
+}): VNode {
+ const current = useCurrentLocation(pageList);
+ if (current !== undefined) {
+ return create(current.page.view, current.values);
+ }
+ return onNotFound();
+}
+
+type Location = {
+ page: PageEntry<any>;
+ path: string;
+ values: Record<string, string>;
+};
+export function useCurrentLocation(pageList: Array<PageEntry<any>>) {
+ const [currentLocation, setCurrentLocation] = useState<Location>();
+ /**
+ * Search path in the pageList
+ * get the values from the path found
+ * add params from searchParams
+ *
+ * @param path
+ * @param params
+ */
+ function doSync(path: string, params: URLSearchParams) {
+ let result: typeof currentLocation;
+ for (let idx = 0; idx < pageList.length; idx++) {
+ const page = pageList[idx];
+ if (typeof page.url === "string") {
+ if (page.url === path) {
+ const values: Record<string, string> = {};
+ params.forEach((v, k) => {
+ values[k] = v;
+ });
+ result = { page, values, path };
+ break;
+ }
+ } else {
+ const values = doestUrlMatchToRoute(path, page.url.pattern);
+ if (values !== undefined) {
+ params.forEach((v, k) => {
+ values[k] = v;
+ });
+ result = { page, values, path };
+ break;
+ }
+ }
+ }
+ setCurrentLocation(result);
+ }
+ useEffect(() => {
+ doSync(window.location.hash, new URLSearchParams(window.location.search));
+ return history.listen(() => {
+ doSync(window.location.hash, new URLSearchParams(window.location.search));
+ });
+ }, []);
+ return currentLocation;
+}
+
+function doestUrlMatchToRoute(
+ url: string,
+ route: string,
+): undefined | Record<string, string> {
+ const paramsPattern = /(?:\?([^#]*))?$/;
+ // const paramsPattern = /(?:\?([^#]*))?(#.*)?$/;
+ const params = url.match(paramsPattern);
+ const urlWithoutParams = url.replace(paramsPattern, "");
+
+ const result: Record<string, string> = {};
+ 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<string, string> = {};