aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-04-26 14:31:48 -0300
committerSebastian <sebasjm@gmail.com>2024-04-26 14:31:48 -0300
commita1c5917e626856f2abd9dbe6ddaa71c1458334c6 (patch)
treed7456b0b27bda5b4b04b78384fd67d3d5f8db379
parent6837a9dc6f677babe798bc94c0baa1f11c0edb55 (diff)
downloadwallet-core-a1c5917e626856f2abd9dbe6ddaa71c1458334c6.tar.xz
update code to match others
-rw-r--r--packages/aml-backoffice-ui/copyleft-header.js2
-rw-r--r--packages/aml-backoffice-ui/src/App.tsx97
-rw-r--r--packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx (renamed from packages/aml-backoffice-ui/src/Dashboard.tsx)57
-rw-r--r--packages/aml-backoffice-ui/src/Routing.tsx151
-rw-r--r--packages/aml-backoffice-ui/src/context/config.ts100
-rw-r--r--packages/aml-backoffice-ui/src/context/settings.ts44
-rw-r--r--packages/aml-backoffice-ui/src/declaration.d.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_11e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_12e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_13e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_15e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_1e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_4e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_5e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/902_9e.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/declaration.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/icons.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/forms/index.ts2
-rw-r--r--packages/aml-backoffice-ui/src/forms/simplest.ts2
-rw-r--r--packages/aml-backoffice-ui/src/hooks/form.ts124
-rw-r--r--packages/aml-backoffice-ui/src/hooks/officer.ts (renamed from packages/aml-backoffice-ui/src/hooks/useOfficer.ts)67
-rw-r--r--packages/aml-backoffice-ui/src/hooks/preferences.ts (renamed from packages/aml-backoffice-ui/src/hooks/useSettings.ts)70
-rw-r--r--packages/aml-backoffice-ui/src/hooks/useBackend.ts48
-rw-r--r--packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts8
-rw-r--r--packages/aml-backoffice-ui/src/hooks/useCases.ts50
-rw-r--r--packages/aml-backoffice-ui/src/i18n/bank.pot2
-rw-r--r--packages/aml-backoffice-ui/src/i18n/fr.po2
-rw-r--r--packages/aml-backoffice-ui/src/i18n/poheader2
-rw-r--r--packages/aml-backoffice-ui/src/i18n/strings-prelude2
-rw-r--r--packages/aml-backoffice-ui/src/i18n/strings.ts2
-rw-r--r--packages/aml-backoffice-ui/src/index.html2
-rw-r--r--packages/aml-backoffice-ui/src/index.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages.ts58
-rw-r--r--packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.stories.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx20
-rw-r--r--packages/aml-backoffice-ui/src/pages/CaseDetails.tsx6
-rw-r--r--packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx (renamed from packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx)30
-rw-r--r--packages/aml-backoffice-ui/src/pages/Cases.stories.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages/Cases.tsx6
-rw-r--r--packages/aml-backoffice-ui/src/pages/CreateAccount.tsx8
-rw-r--r--packages/aml-backoffice-ui/src/pages/HandleAccountNotReady.tsx4
-rw-r--r--packages/aml-backoffice-ui/src/pages/Officer.tsx27
-rw-r--r--packages/aml-backoffice-ui/src/pages/ShowConsolidated.stories.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages/index.stories.ts2
-rw-r--r--packages/aml-backoffice-ui/src/route.ts239
-rw-r--r--packages/aml-backoffice-ui/src/settings.ts74
-rw-r--r--packages/aml-backoffice-ui/src/stories.test.ts23
-rw-r--r--packages/aml-backoffice-ui/src/stories.tsx51
-rw-r--r--packages/aml-backoffice-ui/src/utils/QR.tsx2
52 files changed, 744 insertions, 676 deletions
diff --git a/packages/aml-backoffice-ui/copyleft-header.js b/packages/aml-backoffice-ui/copyleft-header.js
index 2635717c5..7fa276bea 100644
--- a/packages/aml-backoffice-ui/copyleft-header.js
+++ b/packages/aml-backoffice-ui/copyleft-header.js
@@ -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
diff --git a/packages/aml-backoffice-ui/src/App.tsx b/packages/aml-backoffice-ui/src/App.tsx
index 55f03322d..d55de776b 100644
--- a/packages/aml-backoffice-ui/src/App.tsx
+++ b/packages/aml-backoffice-ui/src/App.tsx
@@ -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
@@ -13,26 +13,46 @@
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/>
*/
-import { TranslationProvider } from "@gnu-taler/web-util/browser";
-import { h, VNode } from "preact";
+import { canonicalizeBaseUrl } from "@gnu-taler/taler-util";
+import {
+ BrowserHashNavigationProvider,
+ ExchangeApiProvider,
+ Loading,
+ TranslationProvider,
+} from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+import { useEffect, useState } from "preact/hooks";
import { SWRConfig } from "swr";
-import { ExchangeApiProvider } from "./context/config.js";
-import { ExchangeAmlFrame } from "./Dashboard.js";
-import { getInitialBackendBaseURL } from "./hooks/useBackend.js";
-import { Pages } from "./pages.js";
-import { HashPathProvider, Router } from "./route.js";
+import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
+import { Routing } from "./Routing.js";
+import { SettingsProvider } from "./context/settings.js";
+import { strings } from "./i18n/strings.js";
import "./scss/main.css";
+import { UiSettings, fetchSettings } from "./settings.js";
const WITH_LOCAL_STORAGE_CACHE = false;
-const pageList = Object.values(Pages);
-
export function App(): VNode {
- const baseUrl = getInitialBackendBaseURL();
+ const [settings, setSettings] = useState<UiSettings>();
+ useEffect(() => {
+ fetchSettings(setSettings);
+ }, []);
+ if (!settings) return <Loading />;
+
+ const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL);
return (
- <TranslationProvider source={{}}>
- <ExchangeApiProvider baseUrl={baseUrl} frameOnError={ExchangeAmlFrame}>
- <HashPathProvider>
+ <SettingsProvider value={settings}>
+ <TranslationProvider
+ source={strings}
+ completeness={{
+ es: strings["es"].completeness,
+ de: strings["de"].completeness,
+ }}
+ >
+ <ExchangeApiProvider
+ baseUrl={new URL("/", baseUrl)}
+ frameOnError={ExchangeAmlFrame}
+ >
<SWRConfig
value={{
provider: WITH_LOCAL_STORAGE_CACHE
@@ -60,19 +80,13 @@ export function App(): VNode {
keepPreviousData: true,
}}
>
- <ExchangeAmlFrame>
- <Router
- pageList={pageList}
- onNotFound={() => {
- window.location.href = Pages.cases.url;
- return <div>not found</div>;
- }}
- />
- </ExchangeAmlFrame>
+ <BrowserHashNavigationProvider>
+ <Routing />
+ </BrowserHashNavigationProvider>
</SWRConfig>
- </HashPathProvider>
- </ExchangeApiProvider>
- </TranslationProvider>
+ </ExchangeApiProvider>
+ </TranslationProvider>
+ </SettingsProvider>
);
}
@@ -85,3 +99,34 @@ function localStorageProvider(): Map<unknown, unknown> {
});
return map;
}
+
+function getInitialBackendBaseURL(
+ backendFromSettings: string | undefined,
+): string {
+ const overrideUrl =
+ typeof localStorage !== "undefined"
+ ? localStorage.getItem("exchange-base-url")
+ : undefined;
+ let result: string;
+
+ if (!overrideUrl) {
+ // normal path
+ if (!backendFromSettings) {
+ console.error(
+ "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'",
+ );
+ result = window.origin;
+ } else {
+ result = backendFromSettings;
+ }
+ } 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/Dashboard.tsx b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
index 78980265d..66eb3df36 100644
--- a/packages/aml-backoffice-ui/src/Dashboard.tsx
+++ b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
@@ -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
@@ -20,19 +20,20 @@ import {
ToastBanner,
notifyError,
notifyException,
+ useNavigationContext,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { ComponentChildren, VNode, h } from "preact";
import { useEffect, useErrorBoundary } from "preact/hooks";
-import { useOfficer } from "./hooks/useOfficer.js";
+import { privatePages } from "./Routing.js";
+import { useSettingsContext } from "./context/settings.js";
+import { OfficerState } from "./hooks/officer.js";
import {
- getAllBooleanSettings,
- getLabelForSetting,
- useSettings,
-} from "./hooks/useSettings.js";
-import { Pages } from "./pages.js";
-import { PageEntry, useChangeLocation } from "./route.js";
-import { uiSettings } from "./settings.js";
+ getAllBooleanPreferences,
+ getLabelForPreferences,
+ usePreferences,
+} from "./hooks/preferences.js";
+import { HomeIcon } from "./pages/Cases.js";
/**
* mapping route to view
@@ -107,7 +108,9 @@ const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
export function ExchangeAmlFrame({
children,
+ officer,
}: {
+ officer?: OfficerState,
children?: ComponentChildren;
}): VNode {
const { i18n } = useTranslationContext();
@@ -129,8 +132,8 @@ export function ExchangeAmlFrame({
}
}, [error]);
- const officer = useOfficer();
- const [settings, updateSettings] = useSettings();
+ const [preferences, updatePreferences] = usePreferences();
+ const settings = useSettingsContext()
return (
<div
@@ -140,9 +143,9 @@ export function ExchangeAmlFrame({
<div class="bg-indigo-600 pb-32">
<Header
title="Exchange"
- iconLinkURL={uiSettings.backendBaseURL ?? "#"}
+ iconLinkURL={settings.backendBaseURL ?? "#"}
onLogout={
- officer.state !== "ready"
+ officer?.state !== "ready"
? undefined
: () => {
officer.lock();
@@ -156,8 +159,8 @@ export function ExchangeAmlFrame({
<i18n.Translate>Preferences</i18n.Translate>
</div>
<ul role="list" class="space-y-1">
- {getAllBooleanSettings().map((set) => {
- const isOn: boolean = !!settings[set];
+ {getAllBooleanPreferences().map((set) => {
+ const isOn: boolean = !!preferences[set];
return (
<li key={set} class="mt-2 pl-2">
<div class="flex items-center justify-between">
@@ -166,7 +169,7 @@ export function ExchangeAmlFrame({
class="text-sm text-black font-medium leading-6 "
id="availability-label"
>
- {getLabelForSetting(set, i18n)}
+ {getLabelForPreferences(set, i18n)}
</span>
</span>
<button
@@ -178,7 +181,7 @@ export function ExchangeAmlFrame({
aria-labelledby="availability-label"
aria-describedby="availability-description"
onClick={() => {
- updateSettings(set, !isOn);
+ updatePreferences(set, !isOn);
}}
>
<span
@@ -203,7 +206,7 @@ export function ExchangeAmlFrame({
</div>
<div class="-mt-32 flex grow ">
- {officer.state !== "ready" ? undefined : <Navigation />}
+ {officer?.state !== "ready" ? undefined : <Navigation />}
<div class="flex mx-auto my-4">
<main class="rounded-lg bg-white px-5 py-6 shadow">{children}</main>
</div>
@@ -219,24 +222,28 @@ export function ExchangeAmlFrame({
}
function Navigation(): VNode {
- const pageList: Array<PageEntry> = [Pages.officer, Pages.cases];
- const location = useChangeLocation();
+ const { i18n } = useTranslationContext();
+ const pageList = [
+ { route: privatePages.account, Icon: HomeIcon, label: i18n.str`Account` },
+ { route: privatePages.cases, Icon: HomeIcon, label: i18n.str`Cases` },
+ ];
+ const { path } = useNavigationContext();
return (
<div class="hidden sm:block min-w-min bg-indigo-600 divide-y rounded-r-lg divide-cyan-800 overflow-y-auto overflow-x-clip">
<nav class="flex flex-1 flex-col mx-4 mt-4 mb-2">
<ul role="list" class="flex flex-1 flex-col gap-y-7">
<li>
<ul role="list" class="-mx-2 space-y-1">
- {pageList.map((p) => {
+ {pageList.map((p, idx) => {
return (
- <li key={p.url}>
+ <li key={idx}>
<a
- href={p.url}
- data-selected={location == p.url}
+ href={p.route.url({})}
+ data-selected={path == p.route.url({})}
class="data-[selected=true]:bg-indigo-700 pr-4 data-[selected=true]:text-white text-indigo-200 hover:text-white hover:bg-indigo-700 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"
>
{p.Icon && <p.Icon />}
- <span class="hidden md:inline">{p.name}</span>
+ <span class="hidden md:inline">{p.label}</span>
</a>
</li>
);
diff --git a/packages/aml-backoffice-ui/src/Routing.tsx b/packages/aml-backoffice-ui/src/Routing.tsx
new file mode 100644
index 000000000..1e32e4f4c
--- /dev/null
+++ b/packages/aml-backoffice-ui/src/Routing.tsx
@@ -0,0 +1,151 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+import {
+ urlPattern,
+ useCurrentLocation,
+ useNavigationContext,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
+
+import { assertUnreachable } from "@gnu-taler/taler-util";
+import { useEffect } from "preact/hooks";
+import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
+import { useOfficer } from "./hooks/officer.js";
+import { Cases } from "./pages/Cases.js";
+import { Officer } from "./pages/Officer.js";
+import { CaseDetails } from "./pages/CaseDetails.js";
+import { CaseUpdate, SelectForm } from "./pages/CaseUpdate.js";
+import { HandleAccountNotReady } from "./pages/HandleAccountNotReady.js";
+
+export function Routing(): VNode {
+ const session = useOfficer();
+
+ if (session.state === "ready") {
+ return (
+ <ExchangeAmlFrame officer={session}>
+ <PrivateRouting />
+ </ExchangeAmlFrame>
+ );
+ }
+ return (
+ <ExchangeAmlFrame>
+ <PublicRounting />
+ </ExchangeAmlFrame>
+ );
+}
+
+const publicPages = {
+ config: urlPattern(/\/config/, () => "#/config"),
+ login: urlPattern(/\/login/, () => "#/login"),
+};
+
+function PublicRounting(): VNode {
+ const { i18n } = useTranslationContext();
+ const location = useCurrentLocation(publicPages);
+ // const { navigateTo } = useNavigationContext();
+ // const { config, lib } = useExchangeApiContext();
+ // const [notification, notify, handleError] = useLocalNotification();
+ const session = useOfficer();
+
+ if (location === undefined) {
+ if (session.state !== "ready") {
+ return <HandleAccountNotReady officer={session}/>;
+ } else {
+ return <div />
+ }
+ }
+
+ switch (location.name) {
+ case "config": {
+ return (
+ <Fragment>
+ <div class="sm:mx-auto sm:w-full sm:max-w-sm">
+ <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to exchange config!`}</h2>
+ </div>
+ </Fragment>
+ );
+ }
+ case "login": {
+ return (
+ <Fragment>
+ <div class="sm:mx-auto sm:w-full sm:max-w-sm">
+ <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to exchange config!`}</h2>
+ </div>
+ </Fragment>
+ );
+ }
+ default:
+ assertUnreachable(location);
+ }
+}
+
+export const privatePages = {
+ account: urlPattern(/\/account/, () => "#/account"),
+ cases: urlPattern(/\/cases/, () => "#/cases"),
+ caseDetails: urlPattern<{ cid: string }>(
+ /\/case\/(?<cid>[a-zA-Z0-9]+)/,
+ ({ cid }) => `#/case/${cid}`,
+ ),
+ caseUpdate: urlPattern<{ cid: string; type: string }>(
+ /\/case\/(?<cid>[a-zA-Z0-9]+)\/new\/(?<type>[a-zA-Z0-9]+)/,
+ ({ cid, type }) => `#/case/${cid}/new/${type}`,
+ ),
+ caseNew: urlPattern<{ cid: string }>(
+ /\/case\/(?<cid>[a-zA-Z0-9]+)\/new/,
+ ({ cid }) => `#/case/${cid}/new`,
+ ),
+};
+
+function PrivateRouting(): VNode {
+ const { navigateTo } = useNavigationContext();
+ const location = useCurrentLocation(privatePages);
+ useEffect(() => {
+ if (location === undefined) {
+ navigateTo(privatePages.account.url({}));
+ }
+ }, [location]);
+
+ if (location === undefined) {
+ return <Fragment />;
+ }
+
+ switch (location.name) {
+ case "account": {
+ return <Officer />;
+ }
+ case "caseDetails": {
+ return <CaseDetails account={location.values.cid} />;
+ }
+ case "caseUpdate": {
+ return (
+ <CaseUpdate
+ account={location.values.cid}
+ type={location.values.type}
+ />
+ );
+ }
+ case "caseNew": {
+ return <SelectForm account={location.values.cid} />;
+ }
+ case "cases": {
+ return <Cases />;
+ }
+ default:
+ assertUnreachable(location);
+ }
+}
diff --git a/packages/aml-backoffice-ui/src/context/config.ts b/packages/aml-backoffice-ui/src/context/config.ts
deleted file mode 100644
index d2bc58578..000000000
--- a/packages/aml-backoffice-ui/src/context/config.ts
+++ /dev/null
@@ -1,100 +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 <http://www.gnu.org/licenses/>
- */
-
-import { TalerExchangeApi, TalerExchangeHttpClient, TalerError } from "@gnu-taler/taler-util";
-import { BrowserFetchHttpLib, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { ComponentChildren, createContext, FunctionComponent, h, VNode } from "preact";
-import { useContext, useEffect, useState } from "preact/hooks";
-import { ErrorLoading } from "@gnu-taler/web-util/browser";
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-export type Type = {
- url: URL,
- config: TalerExchangeApi.ExchangeVersionResponse,
- api: TalerExchangeHttpClient,
-};
-
-const Context = createContext<Type>(undefined!);
-
-export const useExchangeApiContext = (): Type => useContext(Context);
-export const useMaybeExchangeApiContext = (): Type | undefined => useContext(Context);
-
-export function ExchangeApiContextTesting({ config, children }: { config: TalerExchangeApi.ExchangeVersionResponse, children?: ComponentChildren; }): VNode {
- return h(Context.Provider, {
- value: { url: new URL("http://testing"), config, api: null! },
- children
- }
- )
-}
-
-export type ConfigResult = undefined
- | { type: "ok", config: TalerExchangeApi.ExchangeVersionResponse }
- | { type: "incompatible", result: TalerExchangeApi.ExchangeVersionResponse, supported: string }
- | { type: "error", error: TalerError }
-
-export const ExchangeApiProvider = ({
- baseUrl,
- children,
- frameOnError,
-}: {
- baseUrl: string,
- children: ComponentChildren;
- frameOnError: FunctionComponent<{ children: ComponentChildren }>,
-}): VNode => {
- const [checked, setChecked] = useState<ConfigResult>()
- const { i18n } = useTranslationContext();
- const url = new URL(baseUrl)
- const api = new TalerExchangeHttpClient(url.href, new BrowserFetchHttpLib())
- useEffect(() => {
- api.getConfig()
- .then((resp) => {
- if (resp.type === "fail") {
- setChecked({ type: "error", error: TalerError.fromUncheckedDetail(resp.detail) });
- } else if (api.isCompatible(resp.body.version)) {
- setChecked({ type: "ok", config: resp.body });
- } else {
- setChecked({ type: "incompatible", result: resp.body, supported: api.PROTOCOL_VERSION })
- }
- })
- .catch((error: unknown) => {
- if (error instanceof TalerError) {
- setChecked({ type: "error", error });
- }
- });
- }, []);
-
- if (checked === undefined) {
- return h(frameOnError, { children: h("div", {}, "loading...") })
- }
- if (checked.type === "error") {
- return h(frameOnError, { children: h(ErrorLoading, { error: checked.error, showDetail: true }) })
- }
- if (checked.type === "incompatible") {
- return h(frameOnError, { children: h("div", {}, i18n.str`the bank backend is not supported. supported version "${checked.supported}", server version "${checked.result.version}"`) })
- }
- const value: Type = {
- url, config: checked.config, api
- }
- return h(Context.Provider, {
- value,
- children,
- });
-};
-
diff --git a/packages/aml-backoffice-ui/src/context/settings.ts b/packages/aml-backoffice-ui/src/context/settings.ts
new file mode 100644
index 000000000..6c61a7b4a
--- /dev/null
+++ b/packages/aml-backoffice-ui/src/context/settings.ts
@@ -0,0 +1,44 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+import { ComponentChildren, createContext, h, VNode } from "preact";
+import { useContext } from "preact/hooks";
+import { UiSettings } from "../settings.js";
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+export type Type = UiSettings;
+
+const initial: UiSettings = {};
+const Context = createContext<Type>(initial);
+
+export const useSettingsContext = (): Type => useContext(Context);
+
+export const SettingsProvider = ({
+ children,
+ value,
+}: {
+ value: UiSettings;
+ children: ComponentChildren;
+}): VNode => {
+ return h(Context.Provider, {
+ value,
+ children,
+ });
+};
diff --git a/packages/aml-backoffice-ui/src/declaration.d.ts b/packages/aml-backoffice-ui/src/declaration.d.ts
index 663271ec7..7868e41bd 100644
--- a/packages/aml-backoffice-ui/src/declaration.d.ts
+++ b/packages/aml-backoffice-ui/src/declaration.d.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
diff --git a/packages/aml-backoffice-ui/src/forms.ts b/packages/aml-backoffice-ui/src/forms.ts
index e1fb283d6..3ecec2bb0 100644
--- a/packages/aml-backoffice-ui/src/forms.ts
+++ b/packages/aml-backoffice-ui/src/forms.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_11e.ts b/packages/aml-backoffice-ui/src/forms/902_11e.ts
index b1cdda6ba..ee4323f77 100644
--- a/packages/aml-backoffice-ui/src/forms/902_11e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_11e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_12e.ts b/packages/aml-backoffice-ui/src/forms/902_12e.ts
index d5a420177..0c14f6ee7 100644
--- a/packages/aml-backoffice-ui/src/forms/902_12e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_12e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_13e.ts b/packages/aml-backoffice-ui/src/forms/902_13e.ts
index 9e05e061a..a4851002e 100644
--- a/packages/aml-backoffice-ui/src/forms/902_13e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_13e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_15e.ts b/packages/aml-backoffice-ui/src/forms/902_15e.ts
index 72acf8d06..915b7dbf7 100644
--- a/packages/aml-backoffice-ui/src/forms/902_15e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_15e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_1e.ts b/packages/aml-backoffice-ui/src/forms/902_1e.ts
index c6d33b9ca..1e7c54f25 100644
--- a/packages/aml-backoffice-ui/src/forms/902_1e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_1e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_4e.ts b/packages/aml-backoffice-ui/src/forms/902_4e.ts
index 15446bb27..46803333b 100644
--- a/packages/aml-backoffice-ui/src/forms/902_4e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_4e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_5e.ts b/packages/aml-backoffice-ui/src/forms/902_5e.ts
index 40dd4d7ad..efe47b213 100644
--- a/packages/aml-backoffice-ui/src/forms/902_5e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_5e.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
diff --git a/packages/aml-backoffice-ui/src/forms/902_9e.ts b/packages/aml-backoffice-ui/src/forms/902_9e.ts
index 539e086f5..62fca5647 100644
--- a/packages/aml-backoffice-ui/src/forms/902_9e.ts
+++ b/packages/aml-backoffice-ui/src/forms/902_9e.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
diff --git a/packages/aml-backoffice-ui/src/forms/declaration.ts b/packages/aml-backoffice-ui/src/forms/declaration.ts
index d944a7a53..fb7b8f334 100644
--- a/packages/aml-backoffice-ui/src/forms/declaration.ts
+++ b/packages/aml-backoffice-ui/src/forms/declaration.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
diff --git a/packages/aml-backoffice-ui/src/forms/icons.tsx b/packages/aml-backoffice-ui/src/forms/icons.tsx
index 824f75c8f..8bd369c4f 100644
--- a/packages/aml-backoffice-ui/src/forms/icons.tsx
+++ b/packages/aml-backoffice-ui/src/forms/icons.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/forms/index.ts b/packages/aml-backoffice-ui/src/forms/index.ts
index 0a6c1df40..6c5f5d767 100644
--- a/packages/aml-backoffice-ui/src/forms/index.ts
+++ b/packages/aml-backoffice-ui/src/forms/index.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
diff --git a/packages/aml-backoffice-ui/src/forms/simplest.ts b/packages/aml-backoffice-ui/src/forms/simplest.ts
index 77ed4ebbb..bd512546d 100644
--- a/packages/aml-backoffice-ui/src/forms/simplest.ts
+++ b/packages/aml-backoffice-ui/src/forms/simplest.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
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 <http://www.gnu.org/licenses/>
+ */
+
+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<T> = {
+ [k in keyof T]?: T[k] extends string
+ ? UIField
+ : T[k] extends AmountJson
+ ? UIField
+ : FormHandler<T[k]>;
+};
+
+export type FormValues<T> = {
+ [k in keyof T]: T[k] extends string
+ ? string | undefined
+ : T[k] extends AmountJson
+ ? string | undefined
+ : FormValues<T[k]>;
+};
+
+export type RecursivePartial<T> = {
+ [k in keyof T]?: T[k] extends string
+ ? string
+ : T[k] extends AmountJson
+ ? AmountJson
+ : RecursivePartial<T[k]>;
+};
+
+export type FormErrors<T> = {
+ [k in keyof T]?: T[k] extends string
+ ? TranslatedString
+ : T[k] extends AmountJson
+ ? TranslatedString
+ : FormErrors<T[k]>;
+};
+
+export type FormStatus<T> =
+ | {
+ status: "ok";
+ result: T;
+ errors: undefined;
+ }
+ | {
+ status: "fail";
+ result: RecursivePartial<T>;
+ errors: FormErrors<T>;
+ };
+
+function constructFormHandler<T>(
+ form: FormValues<T>,
+ updateForm: (d: FormValues<T>) => void,
+ errors: FormErrors<T> | undefined,
+): FormHandler<T> {
+
+ const keys = Object.keys(form) as Array<keyof T>;
+
+ 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<T>);
+
+ return handler;
+}
+
+/**
+ * FIXME: Consider sending this to web-utils
+ *
+ *
+ * @param defaultValue
+ * @param check
+ * @returns
+ */
+export function useFormState<T>(
+ defaultValue: FormValues<T>,
+ check: (f: FormValues<T>) => FormStatus<T>,
+): [FormHandler<T>, FormStatus<T>] {
+ const [form, updateForm] = useState<FormValues<T>>(defaultValue);
+
+ const status = check(form);
+ const handler = constructFormHandler(form, updateForm, status.errors);
+
+ return [handler, status];
+}
diff --git a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts b/packages/aml-backoffice-ui/src/hooks/officer.ts
index b49c9db26..3ac4c857c 100644
--- a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts
+++ b/packages/aml-backoffice-ui/src/hooks/officer.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
@@ -26,14 +26,11 @@ import {
createNewOfficerAccount,
decodeCrock,
encodeCrock,
- unlockOfficerAccount
+ unlockOfficerAccount,
} from "@gnu-taler/taler-util";
-import {
- buildStorageKey,
- useLocalStorage
-} from "@gnu-taler/web-util/browser";
+import { buildStorageKey, useExchangeApiContext, useLocalStorage } from "@gnu-taler/web-util/browser";
import { useMemo } from "preact/hooks";
-import { useMaybeExchangeApiContext } from "../context/config.js";
+import { usePreferences } from "./preferences.js";
export interface Officer {
account: LockedAccount;
@@ -43,9 +40,9 @@ export interface Officer {
const codecForLockedAccount = codecForString() as Codec<LockedAccount>;
type OfficerAccountString = {
- id: string,
+ id: string;
strKey: string;
-}
+};
export const codecForOfficerAccount = (): Codec<OfficerAccountString> =>
buildCodecForObject<OfficerAccountString>()
@@ -78,46 +75,55 @@ interface OfficerReady {
}
const OFFICER_KEY = buildStorageKey("officer", codecForOfficer());
-const DEV_ACCOUNT_KEY = buildStorageKey("account-dev", codecForOfficerAccount());
+const DEV_ACCOUNT_KEY = buildStorageKey(
+ "account-dev",
+ codecForOfficerAccount(),
+);
export function useOfficer(): OfficerState {
- const exchangeContext = useMaybeExchangeApiContext();
- // dev account, is save when reloaded.
+ 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
+ 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])
+ 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 (!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);
+ 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 })
+ const strKey = encodeCrock(signingKey);
+ accountStorage.update({ id, strKey });
},
};
}
@@ -131,7 +137,10 @@ export function useOfficer(): OfficerState {
tryUnlock: async (pwd: string) => {
const ac = await unlockOfficerAccount(officer.account, pwd);
// accountStorage.update(ac);
- accountStorage.update({ id: ac.id, strKey: encodeCrock(ac.signingKey) })
+ accountStorage.update({
+ id: ac.id,
+ strKey: encodeCrock(ac.signingKey),
+ });
},
};
}
diff --git a/packages/aml-backoffice-ui/src/hooks/useSettings.ts b/packages/aml-backoffice-ui/src/hooks/preferences.ts
index 55cdafb23..12e85d249 100644
--- a/packages/aml-backoffice-ui/src/hooks/useSettings.ts
+++ b/packages/aml-backoffice-ui/src/hooks/preferences.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
@@ -20,52 +20,66 @@ import {
buildCodecForObject,
codecForBoolean
} from "@gnu-taler/taler-util";
-import { buildStorageKey, useLocalStorage, useTranslationContext } from "@gnu-taler/web-util/browser";
+import {
+ buildStorageKey,
+ useLocalStorage,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
-interface Settings {
+interface Preferences {
allowInsecurePassword: boolean;
keepSessionAfterReload: boolean;
}
-export function getAllBooleanSettings(): Array<keyof Settings> {
- return ["allowInsecurePassword", "keepSessionAfterReload"]
-}
-
-export function getLabelForSetting(k: keyof Settings, i18n: ReturnType<typeof useTranslationContext>["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<Settings> =>
- buildCodecForObject<Settings>()
+export const codecForPreferences = (): Codec<Preferences> =>
+ buildCodecForObject<Preferences>()
.property("allowInsecurePassword", (codecForBoolean()))
.property("keepSessionAfterReload", (codecForBoolean()))
- .build("Settings");
+ .build("Preferences");
-const defaultSettings: Settings = {
+const defaultPreferences: Preferences = {
allowInsecurePassword: false,
keepSessionAfterReload: false,
};
-const EXCHANGE_SETTINGS_KEY = buildStorageKey(
- "exchange-settings",
- codecForSettings(),
+const PREFERENCES_KEY = buildStorageKey(
+ "exchange-preferences",
+ codecForPreferences(),
);
-
-export function useSettings(): [
- Readonly<Settings>,
- <T extends keyof Settings>(key: T, value: Settings[T]) => void,
+/**
+ * User preferences.
+ *
+ * @returns tuple of [state, update()]
+ */
+export function usePreferences(): [
+ Readonly<Preferences>,
+ <T extends keyof Preferences>(key: T, value: Preferences[T]) => void,
] {
const { value, update } = useLocalStorage(
- EXCHANGE_SETTINGS_KEY,
- defaultSettings,
+ PREFERENCES_KEY,
+ defaultPreferences,
);
- function updateField<T extends keyof Settings>(k: T, v: Settings[T]) {
+ function updateField<T extends keyof Preferences>(k: T, v: Preferences[T]) {
const newValue = { ...value, [k]: v };
update(newValue);
}
return [value, updateField];
}
+
+export function getAllBooleanPreferences(): Array<keyof Preferences> {
+ return [
+ "allowInsecurePassword",
+ "keepSessionAfterReload",
+ ];
+}
+
+export function getLabelForPreferences(
+ k: keyof Preferences,
+ i18n: ReturnType<typeof useTranslationContext>["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 <http://www.gnu.org/licenses/>
- */
- 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<string>();
- 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<TalerExchangeResultByMethod<"getDecisionsByState">, 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<T> = OperationOk<T> & {
@@ -64,11 +82,15 @@ type PaginatedResult<T> = OperationOk<T> & {
isFirstPage: boolean;
loadNext(): void;
loadFirst(): void;
-}
+};
//TODO: consider sending this to web-util
-export function buildPaginatedResult<R, OffId>(data: R[], offset: OffId | undefined, setOffset: (o: OffId | undefined) => void, getId: (r: R) => OffId): PaginatedResult<R[]> {
-
+export function buildPaginatedResult<R, OffId>(
+ data: R[],
+ offset: OffId | undefined,
+ setOffset: (o: OffId | undefined) => void,
+ getId: (r: R) => OffId,
+): PaginatedResult<R[]> {
const isLastPage = data.length < PAGINATED_LIST_REQUEST;
const isFirstPage = offset === undefined;
@@ -83,7 +105,7 @@ export function buildPaginatedResult<R, OffId>(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/i18n/bank.pot b/packages/aml-backoffice-ui/src/i18n/bank.pot
index 66e98976f..39f9de5ce 100644
--- a/packages/aml-backoffice-ui/src/i18n/bank.pot
+++ b/packages/aml-backoffice-ui/src/i18n/bank.pot
@@ -1,5 +1,5 @@
# 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
diff --git a/packages/aml-backoffice-ui/src/i18n/fr.po b/packages/aml-backoffice-ui/src/i18n/fr.po
index 203d55343..8148f6a0c 100644
--- a/packages/aml-backoffice-ui/src/i18n/fr.po
+++ b/packages/aml-backoffice-ui/src/i18n/fr.po
@@ -1,5 +1,5 @@
# 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
diff --git a/packages/aml-backoffice-ui/src/i18n/poheader b/packages/aml-backoffice-ui/src/i18n/poheader
index a251e9584..d7a371934 100644
--- a/packages/aml-backoffice-ui/src/i18n/poheader
+++ b/packages/aml-backoffice-ui/src/i18n/poheader
@@ -1,5 +1,5 @@
# 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
diff --git a/packages/aml-backoffice-ui/src/i18n/strings-prelude b/packages/aml-backoffice-ui/src/i18n/strings-prelude
index a0aeb8268..3ab0fd1e5 100644
--- a/packages/aml-backoffice-ui/src/i18n/strings-prelude
+++ b/packages/aml-backoffice-ui/src/i18n/strings-prelude
@@ -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
diff --git a/packages/aml-backoffice-ui/src/i18n/strings.ts b/packages/aml-backoffice-ui/src/i18n/strings.ts
index a779bbc49..4f7419eb4 100644
--- a/packages/aml-backoffice-ui/src/i18n/strings.ts
+++ b/packages/aml-backoffice-ui/src/i18n/strings.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
diff --git a/packages/aml-backoffice-ui/src/index.html b/packages/aml-backoffice-ui/src/index.html
index c1de73520..b7f73d0a2 100644
--- a/packages/aml-backoffice-ui/src/index.html
+++ b/packages/aml-backoffice-ui/src/index.html
@@ -1,6 +1,6 @@
<!--
This file is part of GNU Taler
- (C) 2021--2022 Taler Systems S.A.
+ (C) 2021--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
diff --git a/packages/aml-backoffice-ui/src/index.tsx b/packages/aml-backoffice-ui/src/index.tsx
index ad0d394d8..c6f6b4a8f 100644
--- a/packages/aml-backoffice-ui/src/index.tsx
+++ b/packages/aml-backoffice-ui/src/index.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/pages.ts b/packages/aml-backoffice-ui/src/pages.ts
deleted file mode 100644
index 1c8fdde4a..000000000
--- a/packages/aml-backoffice-ui/src/pages.ts
+++ /dev/null
@@ -1,58 +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 <http://www.gnu.org/licenses/>
- */
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { CaseDetails } from "./pages/CaseDetails.js";
-import { Cases, HomeIcon, PeopleIcon } from "./pages/Cases.js";
-import { NewFormEntry } from "./pages/NewFormEntry.js";
-import { Officer } from "./pages/Officer.js";
-import { PageEntry, pageDefinition } from "./route.js";
-// import homeLogo from "./assets/home.svg";
-// import peopleLogo from "./assets/people.svg";
-const cases: PageEntry = {
- url: "#/cases",
- view: Cases,
- name: "Cases" as TranslatedString,
- Icon: HomeIcon,
-};
-
-const officer: PageEntry = {
- url: "#/officer",
- view: Officer,
- name: "Officer" as TranslatedString,
- Icon: PeopleIcon,
-};
-
-const account: PageEntry<{ account: string }> = {
- url: pageDefinition("#/account/:account"),
- view: CaseDetails,
- name: "Account" as TranslatedString,
- // icon: () => undefined,
-};
-
-const newFormEntry: PageEntry<{ account?: string; type?: string }> = {
- url: pageDefinition("#/account/:account/new/:type?"),
- view: NewFormEntry,
- name: "New Form" as TranslatedString,
- // icon: () => undefined,
-};
-
-
-export const Pages = {
- cases,
- officer,
- account,
- newFormEntry,
-};
diff --git a/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.stories.tsx b/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.stories.tsx
index 0b055f682..0c82a4a0e 100644
--- a/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.stories.tsx
+++ b/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.stories.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx b/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx
index 77d4b8167..db034c996 100644
--- a/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx
+++ b/packages/aml-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx
@@ -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
@@ -24,17 +24,17 @@ import {
buildCodecForObject,
codecForNumber,
codecForString,
- codecOptional
+ codecOptional,
} from "@gnu-taler/taler-util";
import {
DefaultForm,
+ useExchangeApiContext,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { h } from "preact";
-import { useExchangeApiContext } from "../context/config.js";
import { BaseForm, FormMetadata, uiForms } from "../forms/declaration.js";
-import { Pages } from "../pages.js";
import { AmlExchangeBackend } from "../utils/types.js";
+import { privatePages } from "../Routing.js";
export function AntiMoneyLaunderingForm({
account,
@@ -68,7 +68,10 @@ export function AntiMoneyLaunderingForm({
form={theForm.impl(initial)}
onUpdate={() => {}}
onSubmit={(formValue) => {
- if (formValue.state === undefined || formValue.threshold === undefined) {
+ if (
+ formValue.state === undefined ||
+ formValue.threshold === undefined
+ ) {
return;
}
const validatedForm = formValue as BaseForm;
@@ -87,7 +90,7 @@ export function AntiMoneyLaunderingForm({
>
<div class="mt-6 flex items-center justify-end gap-x-6">
<a
- href={Pages.account.url({ account })}
+ href={privatePages.caseDetails.url({ cid: account })}
class="text-sm font-semibold leading-6 text-gray-900"
>
<i18n.Translate>Cancel</i18n.Translate>
@@ -133,7 +136,10 @@ export function parseJustification(
s: string,
listOfAllKnownForms: FormMetadata<BaseForm>[],
):
- | OperationOk<{ justification: Justification; metadata: FormMetadata<BaseForm> }>
+ | OperationOk<{
+ justification: Justification;
+ metadata: FormMetadata<BaseForm>;
+ }>
| OperationFail<ParseJustificationFail> {
try {
const justification = JSON.parse(s);
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index a91f3d107..576cdbbb9 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -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
@@ -34,13 +34,13 @@ import { VNode, h } from "preact";
import { useState } from "preact/hooks";
import { BaseForm, FormMetadata, uiForms } from "../forms/declaration.js";
import { useCaseDetails } from "../hooks/useCaseDetails.js";
-import { Pages } from "../pages.js";
import { AmlExchangeBackend } from "../utils/types.js";
import {
Justification,
parseJustification,
} from "./AntiMoneyLaunderingForm.js";
import { ShowConsolidated } from "./ShowConsolidated.js";
+import { privatePages } from "../Routing.js";
export type AmlEvent =
| AmlFormEvent
@@ -201,7 +201,7 @@ export function CaseDetails({ account }: { account: string }) {
return (
<div>
<a
- href={Pages.newFormEntry.url({ account })}
+ href={privatePages.caseNew.url({ cid: account })}
class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
>
<i18n.Translate>New AML form</i18n.Translate>
diff --git a/packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx b/packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx
index 7c10132fa..c4bff1f9f 100644
--- a/packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx
@@ -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
@@ -23,35 +23,31 @@ import {
} from "@gnu-taler/taler-util";
import {
LocalNotificationBanner,
+ useExchangeApiContext,
useLocalNotification,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
-import { useExchangeApiContext } from "../context/config.js";
+import { privatePages } from "../Routing.js";
import { uiForms } from "../forms/declaration.js";
-import { useOfficer } from "../hooks/useOfficer.js";
-import { Pages } from "../pages.js";
+import { useOfficer } from "../hooks/officer.js";
import { AntiMoneyLaunderingForm } from "./AntiMoneyLaunderingForm.js";
import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
-export function NewFormEntry({
+export function CaseUpdate({
account,
type,
}: {
- account?: string;
- type?: string;
+ account: string;
+ type: string;
}): VNode {
const { i18n } = useTranslationContext();
const officer = useOfficer();
- const { api } = useExchangeApiContext();
+ const {
+ lib: { exchange: api },
+ } = useExchangeApiContext();
const [notification, notify, handleError] = useLocalNotification();
- if (!account) {
- return <div>no account</div>;
- }
- if (!type) {
- return <SelectForm account={account} />;
- }
if (officer.state !== "ready") {
return <HandleAccountNotReady officer={officer} />;
}
@@ -78,7 +74,7 @@ export function NewFormEntry({
decision,
);
if (resp.type === "ok") {
- window.location.href = Pages.cases.url;
+ window.location.href = privatePages.cases.url({});
return;
}
switch (resp.case) {
@@ -115,7 +111,7 @@ export function NewFormEntry({
);
}
-function SelectForm({ account }: { account: string }) {
+export function SelectForm({ account }: { account: string }) {
const { i18n } = useTranslationContext();
return (
<div>
@@ -124,7 +120,7 @@ function SelectForm({ account }: { account: string }) {
return (
<a
key={form.id}
- href={Pages.newFormEntry.url({ account, type: form.id })}
+ href={privatePages.caseUpdate.url({ cid: account, type: form.id })}
class="m-4 block rounded-md w-fit border-0 p-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-600"
>
{form.label}
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.stories.tsx b/packages/aml-backoffice-ui/src/pages/Cases.stories.tsx
index 223cbbb84..dcbd366a4 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.stories.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.stories.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx b/packages/aml-backoffice-ui/src/pages/Cases.tsx
index 7ecc85e44..e928b831f 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -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
@@ -28,11 +28,11 @@ import {
import { VNode, h } from "preact";
import { useState } from "preact/hooks";
import { useCases } from "../hooks/useCases.js";
-import { Pages } from "../pages.js";
import { amlStateConverter } from "../utils/converter.js";
import { AmlExchangeBackend } from "../utils/types.js";
import { Officer } from "./Officer.js";
+import { privatePages } from "../Routing.js";
export function CasesUI({
records,
@@ -130,7 +130,7 @@ export function CasesUI({
<td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
<div class="text-gray-900">
<a
- href={Pages.account.url({ account: r.h_payto })}
+ href={privatePages.caseDetails.url({ cid: r.h_payto })}
class="text-indigo-600 hover:text-indigo-900"
>
{r.h_payto.substring(0, 16)}...
diff --git a/packages/aml-backoffice-ui/src/pages/CreateAccount.tsx b/packages/aml-backoffice-ui/src/pages/CreateAccount.tsx
index 568ec81fa..9afd0d212 100644
--- a/packages/aml-backoffice-ui/src/pages/CreateAccount.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CreateAccount.tsx
@@ -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
@@ -20,7 +20,7 @@ import {
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
-import { useSettings } from "../hooks/useSettings.js";
+import { usePreferences } from "../hooks/preferences.js";
export function CreateAccount({
onNewAccount,
@@ -32,8 +32,8 @@ export function CreateAccount({
password: string;
repeat: string;
}>();
- const [settings] = useSettings();
-
+ const [settings] = usePreferences();
+
return (
<div class="flex min-h-full flex-col ">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
diff --git a/packages/aml-backoffice-ui/src/pages/HandleAccountNotReady.tsx b/packages/aml-backoffice-ui/src/pages/HandleAccountNotReady.tsx
index c86906929..b23798172 100644
--- a/packages/aml-backoffice-ui/src/pages/HandleAccountNotReady.tsx
+++ b/packages/aml-backoffice-ui/src/pages/HandleAccountNotReady.tsx
@@ -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
@@ -15,7 +15,7 @@
*/
import { assertUnreachable } from "@gnu-taler/taler-util";
import { VNode, h } from "preact";
-import { OfficerNotReady } from "../hooks/useOfficer.js";
+import { OfficerNotReady } from "../hooks/officer.js";
import { CreateAccount } from "./CreateAccount.js";
import { UnlockAccount } from "./UnlockAccount.js";
diff --git a/packages/aml-backoffice-ui/src/pages/Officer.tsx b/packages/aml-backoffice-ui/src/pages/Officer.tsx
index eaa961b90..ad8ae1ed3 100644
--- a/packages/aml-backoffice-ui/src/pages/Officer.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Officer.tsx
@@ -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
@@ -13,22 +13,27 @@
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/>
*/
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import {
+ useExchangeApiContext,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
import { h } from "preact";
-import { getInitialBackendBaseURL } from "../hooks/useBackend.js";
-import { useOfficer } from "../hooks/useOfficer.js";
-import { uiSettings } from "../settings.js";
+import { useOfficer } from "../hooks/officer.js";
import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
+import { useSettingsContext } from "../context/settings.js";
export function Officer() {
const officer = useOfficer();
- const { i18n } = useTranslationContext()
+ const settings = useSettingsContext();
+ const { lib } = useExchangeApiContext();
+
+ const { i18n } = useTranslationContext();
if (officer.state !== "ready") {
return <HandleAccountNotReady officer={officer} />;
}
- const url = new URL(getInitialBackendBaseURL())
- const signupEmail = uiSettings.signupEmail ?? `aml-signup@${url.hostname}`
+ const url = new URL("./", lib.exchange.baseUrl);
+ const signupEmail = settings.signupEmail ?? `aml-signup@${url.hostname}`;
return (
<div>
@@ -40,7 +45,11 @@ export function Officer() {
</div>
<p>
<a
- href={`mailto:${signupEmail}?subject=${encodeURIComponent("Request AML signup")}&body=${encodeURIComponent(`I want my AML account\n\n\nPubKey: ${officer.account.id}`)}`}
+ href={`mailto:${signupEmail}?subject=${encodeURIComponent(
+ "Request AML signup",
+ )}&body=${encodeURIComponent(
+ `I want my AML account\n\n\nPubKey: ${officer.account.id}`,
+ )}`}
target="_blank"
rel="noreferrer"
class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
diff --git a/packages/aml-backoffice-ui/src/pages/ShowConsolidated.stories.tsx b/packages/aml-backoffice-ui/src/pages/ShowConsolidated.stories.tsx
index fa88277ec..1cb50efd2 100644
--- a/packages/aml-backoffice-ui/src/pages/ShowConsolidated.stories.tsx
+++ b/packages/aml-backoffice-ui/src/pages/ShowConsolidated.stories.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx b/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx
index 15b109bee..c1f7e02cb 100644
--- a/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx
+++ b/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx b/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx
index 8066155ac..de634c9e0 100644
--- a/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx
+++ b/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx
@@ -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
diff --git a/packages/aml-backoffice-ui/src/pages/index.stories.ts b/packages/aml-backoffice-ui/src/pages/index.stories.ts
index 22435178b..b2cbf485e 100644
--- a/packages/aml-backoffice-ui/src/pages/index.stories.ts
+++ b/packages/aml-backoffice-ui/src/pages/index.stories.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
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 <http://www.gnu.org/licenses/>
- */
-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<ContextType>(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<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;
- name: TranslatedString;
- Icon?: () => VNode;
- }
- : T extends unknown
- ? {
- url: string;
- view: (props: {}) => VNode;
- name: TranslatedString;
- Icon?: () => 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>>,
-): 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<PageEntry<any>>,
-): 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<string, string> = {};
- 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<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> = {};
diff --git a/packages/aml-backoffice-ui/src/settings.ts b/packages/aml-backoffice-ui/src/settings.ts
index 600fa0eee..a4a693d7d 100644
--- a/packages/aml-backoffice-ui/src/settings.ts
+++ b/packages/aml-backoffice-ui/src/settings.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
@@ -14,17 +14,77 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+ import {
+ Codec,
+ buildCodecForObject,
+ canonicalizeBaseUrl,
+ codecForString,
+ codecOptional
+} from "@gnu-taler/taler-util";
+
export interface UiSettings {
+ // Where libeufin backend is localted
+ // default: window.origin without "webui/"
backendBaseURL?: string;
+ // Shows a button "create random account" in the registration form
+ // Useful for testing
+ // default: false
signupEmail?: string;
}
/**
- * Global settings for the UI.
+ * Global settings for the bank UI.
*/
-const defaultSettings: UiSettings = {};
+const defaultSettings: UiSettings = {
+ backendBaseURL: buildDefaultBackendBaseURL(),
+ signupEmail: undefined,
+};
+
+const codecForBankUISettings = (): Codec<UiSettings> =>
+ buildCodecForObject<UiSettings>()
+ .property("backendBaseURL", codecOptional(codecForString()))
+ .property("signupEmail", codecOptional(codecForString()))
+ .build("UiSettings");
+
+function removeUndefineField<T extends object>(obj: T): T {
+ const keys = Object.keys(obj) as Array<keyof T>;
+ return keys.reduce((prev, cur) => {
+ if (typeof prev[cur] === "undefined") {
+ delete prev[cur];
+ }
+ return prev;
+ }, obj);
+}
+
+export function fetchSettings(listener: (s: UiSettings) => void): void {
+ fetch("./settings.json")
+ .then((resp) => resp.json())
+ .then((json) => codecForBankUISettings().decode(json))
+ .then((result) =>
+ listener({
+ ...defaultSettings,
+ ...removeUndefineField(result),
+ }),
+ )
+ .catch((e) => {
+ console.log("failed to fetch settings", e);
+ listener(defaultSettings);
+ });
+}
+
+function buildDefaultBackendBaseURL(): string | undefined {
+ if (typeof window !== "undefined") {
+ const currentLocation = new URL(
+ window.location.pathname,
+ window.location.origin,
+ ).href;
+ /**
+ * By default, bank backend serves the html content
+ * from the /webui root.
+ */
+ return canonicalizeBaseUrl(currentLocation.replace("/webui", ""));
+ }
+ throw Error("No default URL");
+}
+
-export const uiSettings: UiSettings =
- "talerExchangeAmlSettings" in globalThis
- ? (globalThis as any).talerExchangeAmlSettings
- : defaultSettings;
diff --git a/packages/aml-backoffice-ui/src/stories.test.ts b/packages/aml-backoffice-ui/src/stories.test.ts
index 235370e16..a4f32cf43 100644
--- a/packages/aml-backoffice-ui/src/stories.test.ts
+++ b/packages/aml-backoffice-ui/src/stories.test.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
@@ -19,15 +19,17 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { TalerExchangeApi, setupI18n } from "@gnu-taler/taler-util";
-import { parseGroupImport } from "@gnu-taler/web-util/browser";
+import {
+ ExchangeApiProviderTesting,
+ ExchangeContextType,
+ parseGroupImport,
+} from "@gnu-taler/web-util/browser";
import * as tests from "@gnu-taler/web-util/testing";
// import * as components from "./components/index.examples.js";
import * as pages from "./pages/index.stories.js";
import { ComponentChildren, VNode, h as create } from "preact";
-import { ExchangeApiContextTesting } from "./context/config.js";
-// import { BackendStateProviderTesting } from "./context/backend.js";
setupI18n("en", { en: {} });
@@ -66,5 +68,16 @@ function DefaultTestingContext({
supported_kyc_requirements: [],
version: "asd",
};
- return create(ExchangeApiContextTesting, { config, children });
+ const value: ExchangeContextType = {
+ cancelRequest: () => null,
+ config,
+ url: new URL("/", "http://locahost"),
+ hints: [],
+ lib: {
+ exchange: undefined!, //FIXME: mock
+ },
+ onActivity: () => null!,
+ };
+
+ return create(ExchangeApiProviderTesting, { value, children });
}
diff --git a/packages/aml-backoffice-ui/src/stories.tsx b/packages/aml-backoffice-ui/src/stories.tsx
index 017a31ffa..a66396696 100644
--- a/packages/aml-backoffice-ui/src/stories.tsx
+++ b/packages/aml-backoffice-ui/src/stories.tsx
@@ -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
@@ -22,10 +22,14 @@ import { strings } from "./i18n/strings.js";
import * as pages from "./pages/index.stories.js";
-import { renderStories } from "@gnu-taler/web-util/browser";
+import {
+ ExchangeApiProviderTesting,
+ ExchangeContextType,
+ renderStories,
+} from "@gnu-taler/web-util/browser";
+import { TalerExchangeApi } from "@gnu-taler/taler-util";
import { ComponentChildren, FunctionComponent, VNode, h } from "preact";
-import { ExchangeApiContextTesting } from "./context/config.js";
import "./scss/main.css";
function main(): void {
@@ -40,24 +44,33 @@ function main(): void {
function getWrapperForGroup(): FunctionComponent {
return function All({ children }: { children?: ComponentChildren }): VNode {
+ const config: TalerExchangeApi.ExchangeVersionResponse = {
+ currency: "ARS",
+ currency_specification: {
+ alt_unit_names: {},
+ name: "ARS",
+ num_fractional_input_digits: 2,
+ num_fractional_normal_digits: 2,
+ num_fractional_trailing_zero_digits: 2,
+ },
+ name: "taler-exchange",
+ supported_kyc_requirements: [],
+ version: "asd",
+ };
+ const value: ExchangeContextType = {
+ cancelRequest: () => null,
+ config,
+ url: new URL("/", "http://locahost"),
+ hints: [],
+ lib: {
+ exchange: undefined!, //FIXME: mock
+ },
+ onActivity: () => null!,
+ };
return (
- <ExchangeApiContextTesting
- config={{
- currency: "ARS",
- currency_specification: {
- alt_unit_names: {},
- name: "ARS",
- num_fractional_input_digits: 2,
- num_fractional_normal_digits: 2,
- num_fractional_trailing_zero_digits: 2,
- },
- name: "taler-exchange",
- supported_kyc_requirements: [],
- version: "asd",
- }}
- >
+ <ExchangeApiProviderTesting value={value}>
{children}
- </ExchangeApiContextTesting>
+ </ExchangeApiProviderTesting>
);
};
}
diff --git a/packages/aml-backoffice-ui/src/utils/QR.tsx b/packages/aml-backoffice-ui/src/utils/QR.tsx
index 1dc1712b7..b382348a3 100644
--- a/packages/aml-backoffice-ui/src/utils/QR.tsx
+++ b/packages/aml-backoffice-ui/src/utils/QR.tsx
@@ -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