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/hooks/form.ts | 124 ++++++++++++++++ packages/aml-backoffice-ui/src/hooks/officer.ts | 159 +++++++++++++++++++++ .../aml-backoffice-ui/src/hooks/preferences.ts | 85 +++++++++++ packages/aml-backoffice-ui/src/hooks/useBackend.ts | 48 ------- .../aml-backoffice-ui/src/hooks/useCaseDetails.ts | 8 +- packages/aml-backoffice-ui/src/hooks/useCases.ts | 50 +++++-- packages/aml-backoffice-ui/src/hooks/useOfficer.ts | 150 ------------------- .../aml-backoffice-ui/src/hooks/useSettings.ts | 71 --------- 8 files changed, 408 insertions(+), 287 deletions(-) create mode 100644 packages/aml-backoffice-ui/src/hooks/form.ts create mode 100644 packages/aml-backoffice-ui/src/hooks/officer.ts create mode 100644 packages/aml-backoffice-ui/src/hooks/preferences.ts delete mode 100644 packages/aml-backoffice-ui/src/hooks/useBackend.ts delete mode 100644 packages/aml-backoffice-ui/src/hooks/useOfficer.ts delete mode 100644 packages/aml-backoffice-ui/src/hooks/useSettings.ts (limited to 'packages/aml-backoffice-ui/src/hooks') diff --git a/packages/aml-backoffice-ui/src/hooks/form.ts b/packages/aml-backoffice-ui/src/hooks/form.ts new file mode 100644 index 000000000..fae11c05c --- /dev/null +++ b/packages/aml-backoffice-ui/src/hooks/form.ts @@ -0,0 +1,124 @@ +/* + This file is part of GNU Taler + (C) 2022-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 + */ + +import { AmountJson, TranslatedString } from "@gnu-taler/taler-util"; +import { useState } from "preact/hooks"; + +export type UIField = { + value: string | undefined; + onUpdate: (s: string) => void; + error: TranslatedString | undefined; +}; + +type FormHandler = { + [k in keyof T]?: T[k] extends string + ? UIField + : T[k] extends AmountJson + ? UIField + : FormHandler; +}; + +export type FormValues = { + [k in keyof T]: T[k] extends string + ? string | undefined + : T[k] extends AmountJson + ? string | undefined + : FormValues; +}; + +export type RecursivePartial = { + [k in keyof T]?: T[k] extends string + ? string + : T[k] extends AmountJson + ? AmountJson + : RecursivePartial; +}; + +export type FormErrors = { + [k in keyof T]?: T[k] extends string + ? TranslatedString + : T[k] extends AmountJson + ? TranslatedString + : FormErrors; +}; + +export type FormStatus = + | { + status: "ok"; + result: T; + errors: undefined; + } + | { + status: "fail"; + result: RecursivePartial; + errors: FormErrors; + }; + +function constructFormHandler( + form: FormValues, + updateForm: (d: FormValues) => void, + errors: FormErrors | undefined, +): FormHandler { + + const keys = Object.keys(form) as Array; + + const handler = keys.reduce((prev, fieldName) => { + const currentValue: unknown = form[fieldName]; + const currentError: unknown = errors ? errors[fieldName] : undefined; + function updater(newValue: unknown) { + updateForm({ ...form, [fieldName]: newValue }); + } + if (typeof currentValue === "object") { + // @ts-expect-error FIXME better typing + const group = constructFormHandler(currentValue, updater, currentError); + // @ts-expect-error FIXME better typing + prev[fieldName] = group; + return prev; + } + const field: UIField = { + // @ts-expect-error FIXME better typing + error: currentError, + // @ts-expect-error FIXME better typing + value: currentValue, + onUpdate: updater, + }; + // @ts-expect-error FIXME better typing + prev[fieldName] = field; + return prev; + }, {} as FormHandler); + + return handler; +} + +/** + * FIXME: Consider sending this to web-utils + * + * + * @param defaultValue + * @param check + * @returns + */ +export function useFormState( + defaultValue: FormValues, + check: (f: FormValues) => FormStatus, +): [FormHandler, FormStatus] { + const [form, updateForm] = useState>(defaultValue); + + const status = check(form); + const handler = constructFormHandler(form, updateForm, status.errors); + + return [handler, status]; +} diff --git a/packages/aml-backoffice-ui/src/hooks/officer.ts b/packages/aml-backoffice-ui/src/hooks/officer.ts new file mode 100644 index 000000000..3ac4c857c --- /dev/null +++ b/packages/aml-backoffice-ui/src/hooks/officer.ts @@ -0,0 +1,159 @@ +/* + This file is part of GNU Taler + (C) 2022-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 + */ +import { + AbsoluteTime, + Codec, + LockedAccount, + OfficerAccount, + OfficerId, + SigningKey, + buildCodecForObject, + codecForAbsoluteTime, + codecForString, + createNewOfficerAccount, + decodeCrock, + encodeCrock, + unlockOfficerAccount, +} from "@gnu-taler/taler-util"; +import { buildStorageKey, useExchangeApiContext, useLocalStorage } from "@gnu-taler/web-util/browser"; +import { useMemo } from "preact/hooks"; +import { usePreferences } from "./preferences.js"; + +export interface Officer { + account: LockedAccount; + when: AbsoluteTime; +} + +const codecForLockedAccount = codecForString() as Codec; + +type OfficerAccountString = { + id: string; + strKey: string; +}; + +export const codecForOfficerAccount = (): Codec => + buildCodecForObject() + .property("id", codecForString()) // FIXME + .property("strKey", codecForString()) // FIXME + .build("OfficerAccount"); + +export const codecForOfficer = (): Codec => + buildCodecForObject() + .property("account", codecForLockedAccount) // FIXME + .property("when", codecForAbsoluteTime) // FIXME + .build("Officer"); + +export type OfficerState = OfficerNotReady | OfficerReady; +export type OfficerNotReady = OfficerNotFound | OfficerLocked; +interface OfficerNotFound { + state: "not-found"; + create: (password: string) => Promise; +} +interface OfficerLocked { + state: "locked"; + forget: () => void; + tryUnlock: (password: string) => Promise; +} +interface OfficerReady { + state: "ready"; + account: OfficerAccount; + forget: () => void; + lock: () => void; +} + +const OFFICER_KEY = buildStorageKey("officer", codecForOfficer()); +const DEV_ACCOUNT_KEY = buildStorageKey( + "account-dev", + codecForOfficerAccount(), +); + +export function useOfficer(): OfficerState { + const exchangeContext = useExchangeApiContext(); + const [pref] = usePreferences(); + pref.keepSessionAfterReload; + // dev account, is kept on reloaded. + const accountStorage = useLocalStorage(DEV_ACCOUNT_KEY); + const account = useMemo(() => { + if (!accountStorage.value) return undefined; + + return { + id: accountStorage.value.id as OfficerId, + signingKey: decodeCrock(accountStorage.value.strKey) as SigningKey, + }; + }, [accountStorage.value?.id, accountStorage.value?.strKey]); + + const officerStorage = useLocalStorage(OFFICER_KEY); + const officer = useMemo(() => { + if (!officerStorage.value) return undefined; + return officerStorage.value; + }, [officerStorage.value?.account, officerStorage.value?.when.t_ms]); + + if (officer === undefined) { + return { + state: "not-found", + create: async (pwd: string) => { + const req = await fetch( + new URL("seed", exchangeContext.lib.exchange.baseUrl).href, + ); + const b = await req.blob(); + const ar = await b.arrayBuffer(); + const uintar = new Uint8Array(ar); + + const { id, safe, signingKey } = await createNewOfficerAccount( + pwd, + uintar, + ); + officerStorage.update({ + account: safe, + when: AbsoluteTime.now(), + }); + + // accountStorage.update({ id, signingKey }); + const strKey = encodeCrock(signingKey); + accountStorage.update({ id, strKey }); + }, + }; + } + + if (account === undefined) { + return { + state: "locked", + forget: () => { + officerStorage.reset(); + }, + tryUnlock: async (pwd: string) => { + const ac = await unlockOfficerAccount(officer.account, pwd); + // accountStorage.update(ac); + accountStorage.update({ + id: ac.id, + strKey: encodeCrock(ac.signingKey), + }); + }, + }; + } + + return { + state: "ready", + account, + lock: () => { + accountStorage.reset(); + }, + forget: () => { + officerStorage.reset(); + accountStorage.reset(); + }, + }; +} diff --git a/packages/aml-backoffice-ui/src/hooks/preferences.ts b/packages/aml-backoffice-ui/src/hooks/preferences.ts new file mode 100644 index 000000000..12e85d249 --- /dev/null +++ b/packages/aml-backoffice-ui/src/hooks/preferences.ts @@ -0,0 +1,85 @@ +/* + This file is part of GNU Taler + (C) 2022-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 + */ + +import { + Codec, + TranslatedString, + buildCodecForObject, + codecForBoolean +} from "@gnu-taler/taler-util"; +import { + buildStorageKey, + useLocalStorage, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; + +interface Preferences { + allowInsecurePassword: boolean; + keepSessionAfterReload: boolean; +} + +export const codecForPreferences = (): Codec => + buildCodecForObject() + .property("allowInsecurePassword", (codecForBoolean())) + .property("keepSessionAfterReload", (codecForBoolean())) + .build("Preferences"); + +const defaultPreferences: Preferences = { + allowInsecurePassword: false, + keepSessionAfterReload: false, +}; + +const PREFERENCES_KEY = buildStorageKey( + "exchange-preferences", + codecForPreferences(), +); +/** + * User preferences. + * + * @returns tuple of [state, update()] + */ +export function usePreferences(): [ + Readonly, + (key: T, value: Preferences[T]) => void, +] { + const { value, update } = useLocalStorage( + PREFERENCES_KEY, + defaultPreferences, + ); + + function updateField(k: T, v: Preferences[T]) { + const newValue = { ...value, [k]: v }; + update(newValue); + } + return [value, updateField]; +} + +export function getAllBooleanPreferences(): Array { + return [ + "allowInsecurePassword", + "keepSessionAfterReload", + ]; +} + +export function getLabelForPreferences( + k: keyof Preferences, + i18n: ReturnType["i18n"], +): TranslatedString { + switch (k) { + case "allowInsecurePassword": return i18n.str`Allow Insecure password` + case "keepSessionAfterReload": return i18n.str`Keep session after reload` + } +} diff --git a/packages/aml-backoffice-ui/src/hooks/useBackend.ts b/packages/aml-backoffice-ui/src/hooks/useBackend.ts deleted file mode 100644 index 310f7fe59..000000000 --- a/packages/aml-backoffice-ui/src/hooks/useBackend.ts +++ /dev/null @@ -1,48 +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 { canonicalizeBaseUrl } from "@gnu-taler/taler-util"; -import { uiSettings } from "../settings.js"; - - -export function getInitialBackendBaseURL(): string { - const overrideUrl = - typeof localStorage !== "undefined" - ? localStorage.getItem("exchange-base-url") - : undefined; - - let result: string; - - if (!overrideUrl) { - //normal path - if (!uiSettings.backendBaseURL) { - console.error( - "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'", - ); - result = typeof window !== "undefined" ? window.origin : "localhost" - } else { - result = uiSettings.backendBaseURL; - } - } else { - // testing/development path - result = overrideUrl - } - try { - return canonicalizeBaseUrl(result) - } catch (e) { - //fall back - return canonicalizeBaseUrl(window.origin) - } -} diff --git a/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts b/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts index de1c5af17..78574ada4 100644 --- a/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts +++ b/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2022 Taler Systems S.A. + (C) 2022-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 @@ -16,15 +16,15 @@ import { OfficerAccount, PaytoString, TalerExchangeResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 import _useSWR, { SWRHook } from "swr"; -import { useExchangeApiContext } from "../context/config.js"; -import { useOfficer } from "./useOfficer.js"; +import { useOfficer } from "./officer.js"; +import { useExchangeApiContext } from "@gnu-taler/web-util/browser"; const useSWR = _useSWR as unknown as SWRHook; export function useCaseDetails(paytoHash: string) { const officer = useOfficer(); const session = officer.state === "ready" ? officer.account : undefined; - const { api } = useExchangeApiContext(); + const { lib: {exchange: api} } = useExchangeApiContext(); async function fetcher([officer, account]: [OfficerAccount, PaytoString]) { return await api.getDecisionDetails(officer, account) diff --git a/packages/aml-backoffice-ui/src/hooks/useCases.ts b/packages/aml-backoffice-ui/src/hooks/useCases.ts index 7c8bb5bc1..59d1c9001 100644 --- a/packages/aml-backoffice-ui/src/hooks/useCases.ts +++ b/packages/aml-backoffice-ui/src/hooks/useCases.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2022 Taler Systems S.A. + (C) 2022-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 @@ -16,11 +16,16 @@ import { useState } from "preact/hooks"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 -import { OfficerAccount, OperationOk, TalerExchangeResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; +import { + OfficerAccount, + OperationOk, + TalerExchangeResultByMethod, + TalerHttpError, +} from "@gnu-taler/taler-util"; import _useSWR, { SWRHook } from "swr"; -import { useExchangeApiContext } from "../context/config.js"; import { AmlExchangeBackend } from "../utils/types.js"; -import { useOfficer } from "./useOfficer.js"; +import { useOfficer } from "./officer.js"; +import { useExchangeApiContext } from "@gnu-taler/web-util/browser"; const useSWR = _useSWR as unknown as SWRHook; export const PAGINATED_LIST_SIZE = 10; @@ -37,17 +42,28 @@ export const PAGINATED_LIST_REQUEST = PAGINATED_LIST_SIZE + 1; export function useCases(state: AmlExchangeBackend.AmlState) { const officer = useOfficer(); const session = officer.state === "ready" ? officer.account : undefined; - const { api } = useExchangeApiContext(); + const { + lib: { exchange: api }, + } = useExchangeApiContext(); const [offset, setOffset] = useState(); - async function fetcher([officer, state, offset]: [OfficerAccount, AmlExchangeBackend.AmlState, string | undefined]) { + async function fetcher([officer, state, offset]: [ + OfficerAccount, + AmlExchangeBackend.AmlState, + string | undefined, + ]) { return await api.getDecisionsByState(officer, state, { - order: "asc", offset, limit: PAGINATED_LIST_REQUEST - }) + order: "asc", + offset, + limit: PAGINATED_LIST_REQUEST, + }); } - const { data, error } = useSWR, TalerHttpError>( + const { data, error } = useSWR< + TalerExchangeResultByMethod<"getDecisionsByState">, + TalerHttpError + >( !session ? undefined : [session, state, offset, "getDecisionsByState"], fetcher, ); @@ -56,7 +72,9 @@ export function useCases(state: AmlExchangeBackend.AmlState) { if (data === undefined) return undefined; if (data.type !== "ok") return data; - return buildPaginatedResult(data.body.records, offset, setOffset, (d) => String(d.rowid)); + return buildPaginatedResult(data.body.records, offset, setOffset, (d) => + String(d.rowid), + ); } type PaginatedResult = OperationOk & { @@ -64,11 +82,15 @@ type PaginatedResult = OperationOk & { isFirstPage: boolean; loadNext(): void; loadFirst(): void; -} +}; //TODO: consider sending this to web-util -export function buildPaginatedResult(data: R[], offset: OffId | undefined, setOffset: (o: OffId | undefined) => void, getId: (r: R) => OffId): PaginatedResult { - +export function buildPaginatedResult( + data: R[], + offset: OffId | undefined, + setOffset: (o: OffId | undefined) => void, + getId: (r: R) => OffId, +): PaginatedResult { const isLastPage = data.length < PAGINATED_LIST_REQUEST; const isFirstPage = offset === undefined; @@ -83,7 +105,7 @@ export function buildPaginatedResult(data: R[], offset: OffId | undefi isFirstPage, loadNext: () => { if (!result.length) return; - const id = getId(result[result.length - 1]) + const id = getId(result[result.length - 1]); setOffset(id); }, loadFirst: () => { diff --git a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts b/packages/aml-backoffice-ui/src/hooks/useOfficer.ts deleted file mode 100644 index b49c9db26..000000000 --- a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts +++ /dev/null @@ -1,150 +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 { - AbsoluteTime, - Codec, - LockedAccount, - OfficerAccount, - OfficerId, - SigningKey, - buildCodecForObject, - codecForAbsoluteTime, - codecForString, - createNewOfficerAccount, - decodeCrock, - encodeCrock, - unlockOfficerAccount -} from "@gnu-taler/taler-util"; -import { - buildStorageKey, - useLocalStorage -} from "@gnu-taler/web-util/browser"; -import { useMemo } from "preact/hooks"; -import { useMaybeExchangeApiContext } from "../context/config.js"; - -export interface Officer { - account: LockedAccount; - when: AbsoluteTime; -} - -const codecForLockedAccount = codecForString() as Codec; - -type OfficerAccountString = { - id: string, - strKey: string; -} - -export const codecForOfficerAccount = (): Codec => - buildCodecForObject() - .property("id", codecForString()) // FIXME - .property("strKey", codecForString()) // FIXME - .build("OfficerAccount"); - -export const codecForOfficer = (): Codec => - buildCodecForObject() - .property("account", codecForLockedAccount) // FIXME - .property("when", codecForAbsoluteTime) // FIXME - .build("Officer"); - -export type OfficerState = OfficerNotReady | OfficerReady; -export type OfficerNotReady = OfficerNotFound | OfficerLocked; -interface OfficerNotFound { - state: "not-found"; - create: (password: string) => Promise; -} -interface OfficerLocked { - state: "locked"; - forget: () => void; - tryUnlock: (password: string) => Promise; -} -interface OfficerReady { - state: "ready"; - account: OfficerAccount; - forget: () => void; - lock: () => void; -} - -const OFFICER_KEY = buildStorageKey("officer", codecForOfficer()); -const DEV_ACCOUNT_KEY = buildStorageKey("account-dev", codecForOfficerAccount()); - -export function useOfficer(): OfficerState { - const exchangeContext = useMaybeExchangeApiContext(); - // dev account, is save when reloaded. - const accountStorage = useLocalStorage(DEV_ACCOUNT_KEY); - const account = useMemo(() => { - if (!accountStorage.value) return undefined - - return { - id: accountStorage.value.id as OfficerId, - signingKey: decodeCrock(accountStorage.value.strKey) as SigningKey - } - }, [accountStorage.value?.id, accountStorage.value?.strKey]) - - const officerStorage = useLocalStorage(OFFICER_KEY); - const officer = useMemo(() => { - if (!officerStorage.value) return undefined - return officerStorage.value - }, [officerStorage.value?.account, officerStorage.value?.when.t_ms]) - - if (officer === undefined) { - return { - state: "not-found", - create: async (pwd: string) => { - if (!exchangeContext) return; - const req = await fetch(new URL("seed", exchangeContext.api.baseUrl).href) - const b = await req.blob() - const ar = await b.arrayBuffer() - const uintar = new Uint8Array(ar) - - const { id, safe, signingKey } = await createNewOfficerAccount(pwd, uintar); - officerStorage.update({ - account: safe, - when: AbsoluteTime.now(), - }); - - // accountStorage.update({ id, signingKey }); - const strKey = encodeCrock(signingKey) - accountStorage.update({ id, strKey }) - }, - }; - } - - if (account === undefined) { - return { - state: "locked", - forget: () => { - officerStorage.reset(); - }, - tryUnlock: async (pwd: string) => { - const ac = await unlockOfficerAccount(officer.account, pwd); - // accountStorage.update(ac); - accountStorage.update({ id: ac.id, strKey: encodeCrock(ac.signingKey) }) - }, - }; - } - - return { - state: "ready", - account, - lock: () => { - accountStorage.reset(); - }, - forget: () => { - officerStorage.reset(); - accountStorage.reset(); - }, - }; -} diff --git a/packages/aml-backoffice-ui/src/hooks/useSettings.ts b/packages/aml-backoffice-ui/src/hooks/useSettings.ts deleted file mode 100644 index 55cdafb23..000000000 --- a/packages/aml-backoffice-ui/src/hooks/useSettings.ts +++ /dev/null @@ -1,71 +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 { - Codec, - TranslatedString, - buildCodecForObject, - codecForBoolean -} from "@gnu-taler/taler-util"; -import { buildStorageKey, useLocalStorage, useTranslationContext } from "@gnu-taler/web-util/browser"; - -interface Settings { - allowInsecurePassword: boolean; - keepSessionAfterReload: boolean; -} - -export function getAllBooleanSettings(): Array { - return ["allowInsecurePassword", "keepSessionAfterReload"] -} - -export function getLabelForSetting(k: keyof Settings, i18n: ReturnType["i18n"]): TranslatedString { - switch (k) { - case "allowInsecurePassword": return i18n.str`Allow Insecure password` - case "keepSessionAfterReload": return i18n.str`Keep session after reload` - } -} - -export const codecForSettings = (): Codec => - buildCodecForObject() - .property("allowInsecurePassword", (codecForBoolean())) - .property("keepSessionAfterReload", (codecForBoolean())) - .build("Settings"); - -const defaultSettings: Settings = { - allowInsecurePassword: false, - keepSessionAfterReload: false, -}; - -const EXCHANGE_SETTINGS_KEY = buildStorageKey( - "exchange-settings", - codecForSettings(), -); - -export function useSettings(): [ - Readonly, - (key: T, value: Settings[T]) => void, -] { - const { value, update } = useLocalStorage( - EXCHANGE_SETTINGS_KEY, - defaultSettings, - ); - - function updateField(k: T, v: Settings[T]) { - const newValue = { ...value, [k]: v }; - update(newValue); - } - return [value, updateField]; -} -- cgit v1.2.3