gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated (c8aea621a -> a1c5917e6)


From: gnunet
Subject: [taler-wallet-core] branch master updated (c8aea621a -> a1c5917e6)
Date: Fri, 26 Apr 2024 19:31:54 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a change to branch master
in repository wallet-core.

    from c8aea621a build system: missing command
     new f5cea56a6 cache evict for exchange
     new dbe5a5e5e exchange api for web
     new ce251b9bd show error like bank
     new 6837a9dc6 some comments
     new a1c5917e6 update code to match others

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/aml-backoffice-ui/copyleft-header.js      |   2 +-
 packages/aml-backoffice-ui/src/App.tsx             |  97 ++++++---
 .../src/{Dashboard.tsx => ExchangeAmlFrame.tsx}    |  57 ++---
 packages/aml-backoffice-ui/src/Routing.tsx         | 151 +++++++++++++
 packages/aml-backoffice-ui/src/context/config.ts   | 100 ---------
 .../src/context/settings.ts                        |   8 +-
 packages/aml-backoffice-ui/src/declaration.d.ts    |   2 +-
 packages/aml-backoffice-ui/src/forms.ts            |   2 +-
 packages/aml-backoffice-ui/src/forms/902_11e.ts    |   2 +-
 packages/aml-backoffice-ui/src/forms/902_12e.ts    |   2 +-
 packages/aml-backoffice-ui/src/forms/902_13e.ts    |   2 +-
 packages/aml-backoffice-ui/src/forms/902_15e.ts    |   2 +-
 packages/aml-backoffice-ui/src/forms/902_1e.ts     |   2 +-
 packages/aml-backoffice-ui/src/forms/902_4e.ts     |   2 +-
 packages/aml-backoffice-ui/src/forms/902_5e.ts     |   2 +-
 packages/aml-backoffice-ui/src/forms/902_9e.ts     |   2 +-
 .../aml-backoffice-ui/src/forms/declaration.ts     |   2 +-
 packages/aml-backoffice-ui/src/forms/icons.tsx     |   2 +-
 packages/aml-backoffice-ui/src/forms/index.ts      |   2 +-
 packages/aml-backoffice-ui/src/forms/simplest.ts   |   2 +-
 .../src/hooks/form.ts                              |   9 +
 .../src/hooks/{useOfficer.ts => officer.ts}        |  67 +++---
 .../src/hooks/{useSettings.ts => preferences.ts}   |  70 +++---
 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/i18n/bank.pot       |   2 +-
 packages/aml-backoffice-ui/src/i18n/fr.po          |   2 +-
 packages/aml-backoffice-ui/src/i18n/poheader       |   2 +-
 .../aml-backoffice-ui/src/i18n/strings-prelude     |   2 +-
 packages/aml-backoffice-ui/src/i18n/strings.ts     |   2 +-
 packages/aml-backoffice-ui/src/index.html          |   2 +-
 packages/aml-backoffice-ui/src/index.tsx           |   2 +-
 packages/aml-backoffice-ui/src/pages.ts            |  58 -----
 .../src/pages/AntiMoneyLaunderingForm.stories.tsx  |   2 +-
 .../src/pages/AntiMoneyLaunderingForm.tsx          |  20 +-
 .../aml-backoffice-ui/src/pages/CaseDetails.tsx    |   6 +-
 .../src/pages/{NewFormEntry.tsx => CaseUpdate.tsx} |  30 ++-
 .../aml-backoffice-ui/src/pages/Cases.stories.tsx  |   2 +-
 packages/aml-backoffice-ui/src/pages/Cases.tsx     |   6 +-
 .../aml-backoffice-ui/src/pages/CreateAccount.tsx  |   8 +-
 .../src/pages/HandleAccountNotReady.tsx            |   4 +-
 packages/aml-backoffice-ui/src/pages/Officer.tsx   |  27 ++-
 .../src/pages/ShowConsolidated.stories.tsx         |   2 +-
 .../src/pages/ShowConsolidated.tsx                 |   2 +-
 .../aml-backoffice-ui/src/pages/UnlockAccount.tsx  |   2 +-
 .../aml-backoffice-ui/src/pages/index.stories.ts   |   2 +-
 packages/aml-backoffice-ui/src/route.ts            | 239 ---------------------
 packages/aml-backoffice-ui/src/settings.ts         |  74 ++++++-
 packages/aml-backoffice-ui/src/stories.test.ts     |  23 +-
 packages/aml-backoffice-ui/src/stories.tsx         |  51 +++--
 packages/aml-backoffice-ui/src/utils/QR.tsx        |   2 +-
 packages/bank-ui/src/app.tsx                       |   4 +-
 packages/bank-ui/src/context/settings.ts           |   8 +-
 packages/bank-ui/src/hooks/form.ts                 |   9 +
 packages/bank-ui/src/pages/RegistrationPage.tsx    |   7 +-
 packages/bank-ui/src/settings.ts                   |  14 +-
 .../merchant-backoffice-ui/src/context/session.ts  |   9 +
 packages/taler-util/src/http-client/exchange.ts    |  10 +-
 packages/web-util/src/context/activity.ts          |   6 +-
 .../context/{challenger-api.ts => exchange-api.ts} |  72 ++++---
 packages/web-util/src/context/index.ts             |   1 +
 packages/web-util/src/forms/DefaultForm.tsx        |   2 +-
 63 files changed, 677 insertions(+), 734 deletions(-)
 rename packages/aml-backoffice-ui/src/{Dashboard.tsx => ExchangeAmlFrame.tsx} 
(87%)
 create mode 100644 packages/aml-backoffice-ui/src/Routing.tsx
 delete mode 100644 packages/aml-backoffice-ui/src/context/config.ts
 copy packages/{bank-ui => aml-backoffice-ui}/src/context/settings.ts (88%)
 copy packages/{bank-ui => aml-backoffice-ui}/src/hooks/form.ts (96%)
 rename packages/aml-backoffice-ui/src/hooks/{useOfficer.ts => officer.ts} (74%)
 rename packages/aml-backoffice-ui/src/hooks/{useSettings.ts => preferences.ts} 
(56%)
 delete mode 100644 packages/aml-backoffice-ui/src/hooks/useBackend.ts
 delete mode 100644 packages/aml-backoffice-ui/src/pages.ts
 rename packages/aml-backoffice-ui/src/pages/{NewFormEntry.tsx => 
CaseUpdate.tsx} (87%)
 delete mode 100644 packages/aml-backoffice-ui/src/route.ts
 copy packages/web-util/src/context/{challenger-api.ts => exchange-api.ts} (75%)

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
similarity index 87%
rename from packages/aml-backoffice-ui/src/Dashboard.tsx
rename to 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/bank-ui/src/context/settings.ts 
b/packages/aml-backoffice-ui/src/context/settings.ts
similarity index 88%
copy from packages/bank-ui/src/context/settings.ts
copy to packages/aml-backoffice-ui/src/context/settings.ts
index 053fcbd12..6c61a7b4a 100644
--- a/packages/bank-ui/src/context/settings.ts
+++ b/packages/aml-backoffice-ui/src/context/settings.ts
@@ -16,16 +16,16 @@
 
 import { ComponentChildren, createContext, h, VNode } from "preact";
 import { useContext } from "preact/hooks";
-import { BankUiSettings } from "../settings.js";
+import { UiSettings } from "../settings.js";
 
 /**
  *
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-export type Type = BankUiSettings;
+export type Type = UiSettings;
 
-const initial: BankUiSettings = {};
+const initial: UiSettings = {};
 const Context = createContext<Type>(initial);
 
 export const useSettingsContext = (): Type => useContext(Context);
@@ -34,7 +34,7 @@ export const SettingsProvider = ({
   children,
   value,
 }: {
-  value: BankUiSettings;
+  value: UiSettings;
   children: ComponentChildren;
 }): VNode => {
   return h(Context.Provider, {
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/bank-ui/src/hooks/form.ts 
b/packages/aml-backoffice-ui/src/hooks/form.ts
similarity index 96%
copy from packages/bank-ui/src/hooks/form.ts
copy to packages/aml-backoffice-ui/src/hooks/form.ts
index afa4912eb..fae11c05c 100644
--- a/packages/bank-ui/src/hooks/form.ts
+++ b/packages/aml-backoffice-ui/src/hooks/form.ts
@@ -72,6 +72,7 @@ function constructFormHandler<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) => {
@@ -102,6 +103,14 @@ function constructFormHandler<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>,
diff --git a/packages/aml-backoffice-ui/src/hooks/useOfficer.ts 
b/packages/aml-backoffice-ui/src/hooks/officer.ts
similarity index 74%
rename from packages/aml-backoffice-ui/src/hooks/useOfficer.ts
rename to 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
similarity index 56%
rename from packages/aml-backoffice-ui/src/hooks/useSettings.ts
rename to 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
similarity index 87%
rename from packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx
rename to 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
diff --git a/packages/bank-ui/src/app.tsx b/packages/bank-ui/src/app.tsx
index 29dabddd6..1ea8c69ca 100644
--- a/packages/bank-ui/src/app.tsx
+++ b/packages/bank-ui/src/app.tsx
@@ -37,7 +37,7 @@ import { Routing } from "./Routing.js";
 import { SettingsProvider } from "./context/settings.js";
 import { strings } from "./i18n/strings.js";
 import { BankFrame } from "./pages/BankFrame.js";
-import { BankUiSettings, fetchSettings } from "./settings.js";
+import { UiSettings, fetchSettings } from "./settings.js";
 import {
   revalidateAccountDetails,
   revalidatePublicAccounts,
@@ -51,7 +51,7 @@ import {
 const WITH_LOCAL_STORAGE_CACHE = false;
 
 export function App() {
-  const [settings, setSettings] = useState<BankUiSettings>();
+  const [settings, setSettings] = useState<UiSettings>();
   useEffect(() => {
     fetchSettings(setSettings);
   }, []);
diff --git a/packages/bank-ui/src/context/settings.ts 
b/packages/bank-ui/src/context/settings.ts
index 053fcbd12..6c61a7b4a 100644
--- a/packages/bank-ui/src/context/settings.ts
+++ b/packages/bank-ui/src/context/settings.ts
@@ -16,16 +16,16 @@
 
 import { ComponentChildren, createContext, h, VNode } from "preact";
 import { useContext } from "preact/hooks";
-import { BankUiSettings } from "../settings.js";
+import { UiSettings } from "../settings.js";
 
 /**
  *
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-export type Type = BankUiSettings;
+export type Type = UiSettings;
 
-const initial: BankUiSettings = {};
+const initial: UiSettings = {};
 const Context = createContext<Type>(initial);
 
 export const useSettingsContext = (): Type => useContext(Context);
@@ -34,7 +34,7 @@ export const SettingsProvider = ({
   children,
   value,
 }: {
-  value: BankUiSettings;
+  value: UiSettings;
   children: ComponentChildren;
 }): VNode => {
   return h(Context.Provider, {
diff --git a/packages/bank-ui/src/hooks/form.ts 
b/packages/bank-ui/src/hooks/form.ts
index afa4912eb..fae11c05c 100644
--- a/packages/bank-ui/src/hooks/form.ts
+++ b/packages/bank-ui/src/hooks/form.ts
@@ -72,6 +72,7 @@ function constructFormHandler<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) => {
@@ -102,6 +103,14 @@ function constructFormHandler<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>,
diff --git a/packages/bank-ui/src/pages/RegistrationPage.tsx 
b/packages/bank-ui/src/pages/RegistrationPage.tsx
index 18f926e00..5dd19a63f 100644
--- a/packages/bank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/bank-ui/src/pages/RegistrationPage.tsx
@@ -14,21 +14,20 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 import {
-  AccessToken,
   HttpStatusCode,
-  TalerErrorCode,
+  TalerErrorCode
 } from "@gnu-taler/taler-util";
 import {
   LocalNotificationBanner,
+  RouteDefinition,
   ShowInputErrorLabel,
+  useBankCoreApiContext,
   useLocalNotification,
   useTranslationContext,
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "@gnu-taler/web-util/browser";
 import { useSettingsContext } from "../context/settings.js";
-import { RouteDefinition } from "@gnu-taler/web-util/browser";
 import { undefinedIfEmpty } from "../utils.js";
 import { getRandomPassword, getRandomUsername } from "./rnd.js";
 
diff --git a/packages/bank-ui/src/settings.ts b/packages/bank-ui/src/settings.ts
index 968fe6248..c085c7cd8 100644
--- a/packages/bank-ui/src/settings.ts
+++ b/packages/bank-ui/src/settings.ts
@@ -24,7 +24,7 @@ import {
   codecOptional,
 } from "@gnu-taler/taler-util";
 
-export interface BankUiSettings {
+export interface UiSettings {
   // Where libeufin backend is localted
   // default: window.origin without "webui/"
   backendBaseURL?: string;
@@ -50,7 +50,7 @@ export interface BankUiSettings {
 /**
  * Global settings for the bank UI.
  */
-const defaultSettings: BankUiSettings = {
+const defaultSettings: UiSettings = {
   backendBaseURL: buildDefaultBackendBaseURL(),
   iconLinkURL: undefined,
   simplePasswordForRandomAccounts: false,
@@ -58,8 +58,8 @@ const defaultSettings: BankUiSettings = {
   topNavSites: {},
 };
 
-const codecForBankUISettings = (): Codec<BankUiSettings> =>
-  buildCodecForObject<BankUiSettings>()
+const codecForUISettings = (): Codec<UiSettings> =>
+  buildCodecForObject<UiSettings>()
     .property("backendBaseURL", codecOptional(codecForString()))
     .property("allowRandomAccountCreation", codecOptional(codecForBoolean()))
     .property(
@@ -68,7 +68,7 @@ const codecForBankUISettings = (): Codec<BankUiSettings> =>
     )
     .property("iconLinkURL", codecOptional(codecForString()))
     .property("topNavSites", codecOptional(codecForMap(codecForString())))
-    .build("BankUiSettings");
+    .build("UiSettings");
 
 function removeUndefineField<T extends object>(obj: T): T {
   const keys = Object.keys(obj) as Array<keyof T>;
@@ -80,10 +80,10 @@ function removeUndefineField<T extends object>(obj: T): T {
   }, obj);
 }
 
-export function fetchSettings(listener: (s: BankUiSettings) => void): void {
+export function fetchSettings(listener: (s: UiSettings) => void): void {
   fetch("./settings.json")
     .then((resp) => resp.json())
-    .then((json) => codecForBankUISettings().decode(json))
+    .then((json) => codecForUISettings().decode(json))
     .then((result) =>
       listener({
         ...defaultSettings,
diff --git a/packages/merchant-backoffice-ui/src/context/session.ts 
b/packages/merchant-backoffice-ui/src/context/session.ts
index dbd188ccd..fa5e14ab3 100644
--- a/packages/merchant-backoffice-ui/src/context/session.ts
+++ b/packages/merchant-backoffice-ui/src/context/session.ts
@@ -139,6 +139,15 @@ const Context = 
createContext<SessionStateHandler>(undefined!);
 
 export const useSessionContext = (): SessionStateHandler => 
useContext(Context);
 
+/**
+ * Creates the session in loggedIn state.
+ * Infer the instance name based on the URL.
+ * Create the instance of the merchant api http rest.
+ * Returns API that handle impersonation.
+ * 
+ * @param param0 
+ * @returns 
+ */
 export const SessionContextProvider = ({
   children,
   // value,
diff --git a/packages/taler-util/src/http-client/exchange.ts 
b/packages/taler-util/src/http-client/exchange.ts
index ea7f44cf9..0ff1a8874 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -33,7 +33,7 @@ import {
   codecForExchangeConfig,
   codecForExchangeKeys,
 } from "./types.js";
-import { addPaginationParams } from "./utils.js";
+import { CacheEvictor, addPaginationParams, nullEvictor } from "./utils.js";
 
 export type TalerExchangeResultByMethod<
   prop extends keyof TalerExchangeHttpClient,
@@ -42,17 +42,25 @@ export type TalerExchangeErrorsByMethod<
   prop extends keyof TalerExchangeHttpClient,
 > = FailCasesByMethod<TalerExchangeHttpClient, prop>;
 
+export enum TalerExchangeCacheEviction {
+  CREATE_DESCISION,
+}
+
+
 /**
  */
 export class TalerExchangeHttpClient {
   httpLib: HttpRequestLibrary;
   public readonly PROTOCOL_VERSION = "18:0:1";
+  cacheEvictor: CacheEvictor<TalerExchangeCacheEviction>;
 
   constructor(
     readonly baseUrl: string,
     httpClient?: HttpRequestLibrary,
+    cacheEvictor?: CacheEvictor<TalerExchangeCacheEviction>,
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
+    this.cacheEvictor = cacheEvictor ?? nullEvictor;
   }
 
   isCompatible(version: string): boolean {
diff --git a/packages/web-util/src/context/activity.ts 
b/packages/web-util/src/context/activity.ts
index fd366cbe5..d12d1efb6 100644
--- a/packages/web-util/src/context/activity.ts
+++ b/packages/web-util/src/context/activity.ts
@@ -14,7 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { ChallengerHttpClient, ObservabilityEvent, 
TalerAuthenticationHttpClient, TalerBankConversionHttpClient, 
TalerCoreBankHttpClient, TalerMerchantInstanceHttpClient, 
TalerMerchantManagementHttpClient } from "@gnu-taler/taler-util";
+import { ChallengerHttpClient, ObservabilityEvent, 
TalerAuthenticationHttpClient, TalerBankConversionHttpClient, 
TalerCoreBankHttpClient, TalerExchangeHttpClient, 
TalerMerchantInstanceHttpClient, TalerMerchantManagementHttpClient } from 
"@gnu-taler/taler-util";
 
 type Listener<Event> = (e: Event) => void;
 type Unsuscriber = () => void;
@@ -60,6 +60,10 @@ export interface MerchantLib {
   subInstanceApi: (instanceId: string) => MerchantLib;
 }
 
+export interface ExchangeLib {
+  exchange: TalerExchangeHttpClient;
+}
+
 export interface BankLib {
   bank: TalerCoreBankHttpClient;
   conversion: TalerBankConversionHttpClient;
diff --git a/packages/web-util/src/context/challenger-api.ts 
b/packages/web-util/src/context/exchange-api.ts
similarity index 75%
copy from packages/web-util/src/context/challenger-api.ts
copy to packages/web-util/src/context/exchange-api.ts
index 8748f5f69..39f889ba9 100644
--- a/packages/web-util/src/context/challenger-api.ts
+++ b/packages/web-util/src/context/exchange-api.ts
@@ -16,13 +16,13 @@
 
 import {
   CacheEvictor,
-  ChallengerApi,
-  ChallengerCacheEviction,
-  ChallengerHttpClient,
   LibtoolVersion,
   ObservabilityEvent,
   ObservableHttpClientLibrary,
-  TalerError
+  TalerError,
+  TalerExchangeApi,
+  TalerExchangeCacheEviction,
+  TalerExchangeHttpClient
 } from "@gnu-taler/taler-util";
 import {
   ComponentChildren,
@@ -32,68 +32,71 @@ import {
   h,
 } from "preact";
 import { useContext, useEffect, useState } from "preact/hooks";
-import { BrowserFetchHttpLib, ErrorLoading } from "../index.browser.js";
+import { BrowserFetchHttpLib, ErrorLoading, useTranslationContext } from 
"../index.browser.js";
 import {
   APIClient,
   ActiviyTracker,
-  ChallengerLib,
-  Subscriber
+  ExchangeLib,
+  Subscriber,
 } from "./activity.js";
-import { useTranslationContext } from "./translation.js";
 
 /**
  *
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-export type ChallengerContextType = {
+export type ExchangeContextType = {
   url: URL;
-  config: ChallengerApi.ChallengerTermsOfServiceResponse;
-  lib: ChallengerLib;
+  config: TalerExchangeApi.ExchangeVersionResponse;
+  lib: ExchangeLib;
   hints: VersionHint[];
   onActivity: Subscriber<ObservabilityEvent>;
   cancelRequest: (eventId: string) => void;
 };
 
+// FIXME: below
 // @ts-expect-error default value to undefined, should it be another thing?
-const ChallengerContext = createContext<ChallengerContextType>(undefined);
+const ExchangeContext = createContext<ExchangeContextType>(undefined);
 
-export const useChallengerApiContext = (): ChallengerContextType =>
-  useContext(ChallengerContext);
+export const useExchangeApiContext = (): ExchangeContextType =>
+  useContext(ExchangeContext);
 
 enum VersionHint {
   NONE,
 }
 
 type Evictors = {
-  challenger?: CacheEvictor<ChallengerCacheEviction>;
-}
+  exchange?: CacheEvictor<TalerExchangeCacheEviction>;
+};
 
 type ConfigResult<T> =
   | undefined
   | { type: "ok"; config: T; hints: VersionHint[] }
+  | ConfigResultFail<T>;
+
+type ConfigResultFail<T> =
   | { type: "incompatible"; result: T; supported: string }
   | { type: "error"; error: TalerError };
 
 const CONFIG_FAIL_TRY_AGAIN_MS = 5000;
 
-export const ChallengerApiProvider = ({
+export const ExchangeApiProvider = ({
   baseUrl,
   children,
-  frameOnError,
   evictors = {},
+  frameOnError,
 }: {
   baseUrl: URL;
-  children: ComponentChildren;
   evictors?: Evictors;
+  children: ComponentChildren;
   frameOnError: FunctionComponent<{ children: ComponentChildren }>;
 }): VNode => {
   const [checked, setChecked] =
-    useState<ConfigResult<ChallengerApi.ChallengerTermsOfServiceResponse>>();
-  const { i18n } = useTranslationContext();
+    useState<ConfigResult<TalerExchangeApi.ExchangeVersionResponse>>();
+    const { i18n } = useTranslationContext();
 
   const { getRemoteConfig, VERSION, lib, cancelRequest, onActivity } =
-    buildChallengerApiClient(baseUrl, evictors);
+    buildExchangeApiClient(baseUrl, evictors);
 
   useEffect(() => {
     let keepRetrying = true;
@@ -149,7 +152,7 @@ export const ChallengerApiProvider = ({
     });
   }
 
-  const value: ChallengerContextType = {
+  const value: ExchangeContextType = {
     url: baseUrl,
     config: checked.config,
     onActivity: onActivity,
@@ -157,31 +160,32 @@ export const ChallengerApiProvider = ({
     cancelRequest,
     hints: checked.hints,
   };
-  return h(ChallengerContext.Provider, {
+  return h(ExchangeContext.Provider, {
     value,
     children,
   });
 };
 
-function buildChallengerApiClient(
+function buildExchangeApiClient(
   url: URL,
   evictors: Evictors,
-): APIClient<ChallengerLib, ChallengerApi.ChallengerTermsOfServiceResponse> {
+): APIClient<ExchangeLib, TalerExchangeApi.ExchangeVersionResponse> {
   const httpFetch = new BrowserFetchHttpLib({
     enableThrottling: true,
     requireTls: false,
   });
   const tracker = new ActiviyTracker<ObservabilityEvent>();
+
   const httpLib = new ObservableHttpClientLibrary(httpFetch, {
     observe(ev) {
       tracker.notify(ev);
     },
   });
 
-  const challenger = new ChallengerHttpClient(url.href, httpLib, 
evictors.challenger);
+  const ex = new TalerExchangeHttpClient(url.href, httpLib, evictors.exchange);
 
-  async function getRemoteConfig(): 
Promise<ChallengerApi.ChallengerTermsOfServiceResponse> {
-    const resp = await challenger.getConfig();
+  async function getRemoteConfig(): 
Promise<TalerExchangeApi.ExchangeVersionResponse> {
+    const resp = await ex.getConfig();
     if (resp.type === "fail") {
       throw TalerError.fromUncheckedDetail(resp.detail);
     }
@@ -190,23 +194,23 @@ function buildChallengerApiClient(
 
   return {
     getRemoteConfig,
-    VERSION: challenger.PROTOCOL_VERSION,
+    VERSION: ex.PROTOCOL_VERSION,
     lib: {
-      challenger,
+      exchange: ex,
     },
     onActivity: tracker.subscribe,
     cancelRequest: httpLib.cancelRequest,
   };
 }
 
-export const ChallengerApiProviderTesting = ({
+export const ExchangeApiProviderTesting = ({
   children,
   value,
 }: {
-  value: ChallengerContextType;
+  value: ExchangeContextType;
   children: ComponentChildren;
 }): VNode => {
-  return h(ChallengerContext.Provider, {
+  return h(ExchangeContext.Provider, {
     value,
     children,
   });
diff --git a/packages/web-util/src/context/index.ts 
b/packages/web-util/src/context/index.ts
index 8e7f096da..7e30ecd09 100644
--- a/packages/web-util/src/context/index.ts
+++ b/packages/web-util/src/context/index.ts
@@ -7,5 +7,6 @@ export {
 export * from "./bank-api.js";
 export * from "./challenger-api.js";
 export * from "./merchant-api.js";
+export * from "./exchange-api.js";
 export * from "./navigation.js";
 export * from "./wallet-integration.js";
diff --git a/packages/web-util/src/forms/DefaultForm.tsx 
b/packages/web-util/src/forms/DefaultForm.tsx
index 1155401f5..118699487 100644
--- a/packages/web-util/src/forms/DefaultForm.tsx
+++ b/packages/web-util/src/forms/DefaultForm.tsx
@@ -52,7 +52,7 @@ export function DefaultForm<T extends object>({
         {form.design.map((section, i) => {
           if (!section) return <Fragment />;
           return (
-            <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3">
+            <div key={i} class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 
md:grid-cols-3">
               <div class="px-4 sm:px-0">
                 <h2 class="text-base font-semibold leading-7 text-gray-900">
                   {section.title}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]