summaryrefslogtreecommitdiff
path: root/packages/auditor-backoffice-ui/src/hooks/index.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/auditor-backoffice-ui/src/hooks/index.ts')
-rw-r--r--packages/auditor-backoffice-ui/src/hooks/index.ts151
1 files changed, 151 insertions, 0 deletions
diff --git a/packages/auditor-backoffice-ui/src/hooks/index.ts b/packages/auditor-backoffice-ui/src/hooks/index.ts
new file mode 100644
index 000000000..61afbc94a
--- /dev/null
+++ b/packages/auditor-backoffice-ui/src/hooks/index.ts
@@ -0,0 +1,151 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021-2024 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 <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { buildCodecForObject, codecForMap, codecForString, codecForTimestamp } from "@gnu-taler/taler-util";
+import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
+import { StateUpdater, useEffect, useState } from "preact/hooks";
+import { LoginToken } from "../declaration.js";
+import { ValueOrFunction } from "../utils/types.js";
+import { useMatchMutate } from "./backend.js";
+
+const calculateRootPath = () => {
+ const rootPath =
+ typeof window !== undefined
+ ? window.location.origin + window.location.pathname
+ : "/";
+
+ /**
+ * By default, merchant backend serves the html content
+ * from the /webui root. This should cover most of the
+ * cases and the rootPath will be the merchant backend
+ * URL where the instances are
+ */
+ return rootPath.replace("/webui/", "");
+};
+
+const loginTokenCodec = buildCodecForObject<LoginToken>()
+ .property("token", codecForString())
+ .property("expiration", codecForTimestamp)
+ .build("loginToken")
+const TOKENS_KEY = buildStorageKey("auditor-token", codecForMap(loginTokenCodec));
+
+
+export function useBackendURL(
+ url?: string,
+): [string, StateUpdater<string>] {
+ const [value, setter] = useSimpleLocalStorage(
+ "auditor-base-url",
+ url || calculateRootPath(),
+ );
+
+ const checkedSetter = (v: ValueOrFunction<string>) => {
+ return setter((p) => (v instanceof Function ? v(p ?? "") : v).replace(/\/$/, ""));
+ };
+
+ return [value!, checkedSetter];
+}
+
+export function useBackendDefaultToken(
+): [LoginToken | undefined, ((d: LoginToken | undefined) => void)] {
+ const { update: setToken, value: tokenMap, reset } = useLocalStorage(TOKENS_KEY, {})
+
+ const tokenOfDefaultInstance = tokenMap["default"]
+ const clearCache = useMatchMutate()
+ useEffect(() => {
+ clearCache()
+ }, [tokenOfDefaultInstance])
+
+ function updateToken(
+ value: (LoginToken | undefined)
+ ): void {
+ if (value === undefined) {
+ reset()
+ } else {
+ const res = { ...tokenMap, "default": value }
+ setToken(res)
+ }
+ }
+ return [tokenMap["default"], updateToken];
+}
+
+export function useBackendInstanceToken(
+ id: string,
+): [LoginToken | undefined, ((d: LoginToken | undefined) => void)] {
+ const { update: setToken, value: tokenMap, reset } = useLocalStorage(TOKENS_KEY, {})
+ const [defaultToken, defaultSetToken] = useBackendDefaultToken();
+
+ // instance named 'default' use the default token
+ if (id === "default") {
+ return [defaultToken, defaultSetToken];
+ }
+ function updateToken(
+ value: (LoginToken | undefined)
+ ): void {
+ if (value === undefined) {
+ reset()
+ } else {
+ const res = { ...tokenMap, [id]: value }
+ setToken(res)
+ }
+ }
+
+ return [tokenMap[id], updateToken];
+}
+
+export function useLang(initial?: string): [string, StateUpdater<string>] {
+ const browserLang =
+ typeof window !== "undefined"
+ ? navigator.language || (navigator as any).userLanguage
+ : undefined;
+ const defaultLang = (browserLang || initial || "en").substring(0, 2);
+ return useSimpleLocalStorage("lang-preference", defaultLang) as [string, StateUpdater<string>];
+}
+
+export function useSimpleLocalStorage(
+ key: string,
+ initialValue?: string,
+): [string | undefined, StateUpdater<string | undefined>] {
+ const [storedValue, setStoredValue] = useState<string | undefined>(
+ (): string | undefined => {
+ return typeof window !== "undefined"
+ ? window.localStorage.getItem(key) || initialValue
+ : initialValue;
+ },
+ );
+
+ const setValue = (
+ value?: string | ((val?: string) => string | undefined),
+ ) => {
+ setStoredValue((p) => {
+ const toStore = value instanceof Function ? value(p) : value;
+ if (typeof window !== "undefined") {
+ if (!toStore) {
+ window.localStorage.removeItem(key);
+ } else {
+ window.localStorage.setItem(key, toStore);
+ }
+ }
+ return toStore;
+ });
+ };
+
+ return [storedValue, setValue];
+}