gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 01/02: settings and preferences, getting conversion


From: gnunet
Subject: [taler-wallet-core] 01/02: settings and preferences, getting conversion info
Date: Wed, 22 Nov 2023 19:20:43 +0100

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

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

commit 33c0267b37eecf44dc9f04e124eb44d27cba700c
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Nov 22 13:33:44 2023 -0300

    settings and preferences, getting conversion info
---
 packages/demobank-ui/dev.mjs                       |  4 +-
 packages/demobank-ui/src/Routing.tsx               | 10 ++-
 packages/demobank-ui/src/bank-ui-settings.js       | 19 -----
 packages/demobank-ui/src/components/app.tsx        | 52 +++++++------
 .../{dev.mjs => src/context/settings.ts}           | 53 +++++++-------
 packages/demobank-ui/src/hooks/backend.ts          |  1 -
 packages/demobank-ui/src/hooks/circuit.ts          | 63 +++++++---------
 .../src/hooks/{settings.ts => preferences.ts}      | 30 ++++----
 packages/demobank-ui/src/index.html                |  2 -
 .../demobank-ui/src/pages/AccountPage/views.tsx    |  4 +-
 packages/demobank-ui/src/pages/BankFrame.tsx       | 23 +++---
 packages/demobank-ui/src/pages/LoginForm.tsx       | 13 ++--
 .../demobank-ui/src/pages/OperationState/state.ts  |  4 +-
 .../demobank-ui/src/pages/OperationState/views.tsx |  6 +-
 packages/demobank-ui/src/pages/PaymentOptions.tsx  |  4 +-
 .../demobank-ui/src/pages/RegistrationPage.tsx     | 17 +++--
 .../demobank-ui/src/pages/WalletWithdrawForm.tsx   |  6 +-
 .../src/pages/WithdrawalConfirmationQuestion.tsx   |  4 +-
 .../src/pages/WithdrawalOperationPage.tsx          |  4 +-
 .../src/pages/business/CreateCashout.tsx           | 32 ++++----
 packages/demobank-ui/src/pages/rnd.ts              |  2 -
 packages/demobank-ui/src/settings.json             | 12 +++
 packages/demobank-ui/src/settings.ts               | 33 +++++++--
 packages/taler-util/src/http-client/types.ts       | 85 +++++++---------------
 packages/web-util/src/components/Header.tsx        |  7 +-
 25 files changed, 235 insertions(+), 255 deletions(-)

diff --git a/packages/demobank-ui/dev.mjs b/packages/demobank-ui/dev.mjs
index 8b04155f4..c5ea318e7 100755
--- a/packages/demobank-ui/dev.mjs
+++ b/packages/demobank-ui/dev.mjs
@@ -18,13 +18,13 @@
 import { serve } from "@gnu-taler/web-util/node";
 import { initializeDev } from "@gnu-taler/web-util/build";
 
-const devEntryPoints = ["src/stories.tsx", "src/index.tsx", 
"src/bank-ui-settings.js"];
+const devEntryPoints = ["src/stories.tsx", "src/index.tsx"];
 
 const build = initializeDev({
   type: "development",
   source: {
     js: devEntryPoints,
-    assets: [{ base: "src", files: ["src/index.html"] }],
+    assets: [{ base: "src", files: ["src/index.html", "src/settings.json"] }],
   },
   destination: "./dist/dev",
   public: "/app",
diff --git a/packages/demobank-ui/src/Routing.tsx 
b/packages/demobank-ui/src/Routing.tsx
index d797a837d..733d55a0f 100644
--- a/packages/demobank-ui/src/Routing.tsx
+++ b/packages/demobank-ui/src/Routing.tsx
@@ -19,6 +19,7 @@ import { createHashHistory } from "history";
 import { Fragment, VNode, h } from "preact";
 import { Route, Router, route } from "preact-router";
 import { useEffect } from "preact/hooks";
+
 import { useBackendState } from "./hooks/backend.js";
 import { BankFrame } from "./pages/BankFrame.js";
 import { WithdrawalOperationPage } from "./pages/WithdrawalOperationPage.js";
@@ -27,7 +28,6 @@ import { PublicHistoriesPage } from 
"./pages/PublicHistoriesPage.js";
 import { RegistrationPage } from "./pages/RegistrationPage.js";
 import { AdminHome } from "./pages/admin/AdminHome.js";
 import { CreateCashout } from "./pages/business/CreateCashout.js";
-import { bankUiSettings } from "./settings.js";
 import { ShowAccountDetails } from "./pages/account/ShowAccountDetails.js";
 import { UpdateAccountPassword } from 
"./pages/account/UpdateAccountPassword.js";
 import { RemoveAccount } from "./pages/admin/RemoveAccount.js";
@@ -36,10 +36,14 @@ import { CashoutListForAccount } from 
"./pages/account/CashoutListForAccount.js"
 import { ShowCashoutDetails } from "./pages/business/ShowCashoutDetails.js";
 import { WireTransfer } from "./pages/WireTransfer.js";
 import { AccountPage } from "./pages/AccountPage/index.js";
+import { useSettingsContext } from "./context/settings.js";
+import { useBankCoreApiContext } from "./context/config.js";
 
 export function Routing(): VNode {
   const history = createHashHistory();
   const backend = useBackendState();
+  const settings = useSettingsContext();
+  const {config} = useBankCoreApiContext();
   const { i18n } = useTranslationContext();
 
   if (backend.state.status === "loggedOut") {
@@ -50,7 +54,7 @@ export function Routing(): VNode {
           component={() => (
             <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 
${bankUiSettings.bankName}!`}</h2>
+                <h2 class="text-center text-2xl font-bold leading-9 
tracking-tight text-gray-900">{i18n.str`Welcome to ${settings.bankName}!`}</h2>
               </div>
 
               <LoginForm
@@ -76,7 +80,7 @@ export function Routing(): VNode {
             />
           )}
         />
-        {bankUiSettings.allowRegistrations &&
+        {config.allow_registrations &&
           <Route
             path="/register"
             component={() => (
diff --git a/packages/demobank-ui/src/bank-ui-settings.js 
b/packages/demobank-ui/src/bank-ui-settings.js
deleted file mode 100644
index 397fa28c0..000000000
--- a/packages/demobank-ui/src/bank-ui-settings.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Values for development environment
-
-/**
- * Global settings for the bank UI.
- */
-globalThis.talerBankSettings = {
-  backendBaseURL: "http://bank.taler.test:1180/";,
-  allowRegistrations: true,
-  showDemoNav: true,
-  simplePasswordForRandomAccounts: true,
-  allowRandomAccountCreation: true,
-  bankName: "Taler DEVELOPMENT Bank",
-  // Names and links for other demo sites to show in the navbar
-  demoSites: [
-    ["Exchange", "https://Exchnage.taler.test/";],
-    ["Bank", "https://bank-ui.taler.test/";],
-    ["Merchant", "https://merchant.taler.test/";],
-  ],
-};
diff --git a/packages/demobank-ui/src/components/app.tsx 
b/packages/demobank-ui/src/components/app.tsx
index c787fa713..27898caeb 100644
--- a/packages/demobank-ui/src/components/app.tsx
+++ b/packages/demobank-ui/src/components/app.tsx
@@ -19,35 +19,45 @@ import {
   getGlobalLogLevel,
   setGlobalLogLevelFromString
 } from "@gnu-taler/taler-util";
-import { TranslationProvider } from "@gnu-taler/web-util/browser";
+import { Loading, TranslationProvider } from "@gnu-taler/web-util/browser";
 import { Fragment, FunctionalComponent, h } from "preact";
 import { SWRConfig } from "swr";
 import { BackendStateProvider } from "../context/backend.js";
 import { BankCoreApiProvider } from "../context/config.js";
 import { strings } from "../i18n/strings.js";
-import { bankUiSettings } from "../settings.js";
+import { BankUiSettings, fetchSettings } from "../settings.js";
 import { Routing } from "../Routing.js";
 import { BankFrame } from "../pages/BankFrame.js";
+import { useEffect, useState } from "preact/hooks";
+import { SettingsProvider } from "../context/settings.js";
 const WITH_LOCAL_STORAGE_CACHE = false;
 
 const App: FunctionalComponent = () => {
-  const baseUrl = getInitialBackendBaseURL();
+  const [settings, setSettings] = useState<BankUiSettings>()
+  useEffect(() => {
+    fetchSettings(setSettings)
+  }, [])
+  if (!settings) return <Loading />;
+  
+  const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL);
   return (
-    <TranslationProvider source={strings}>
-      <BackendStateProvider>
-        <BankCoreApiProvider baseUrl={baseUrl} frameOnError={BankFrame}>
-          <SWRConfig
-            value={{
-              provider: WITH_LOCAL_STORAGE_CACHE
-                ? localStorageProvider
-                : undefined,
-            }}
-          >
-            <Routing />
-          </SWRConfig>
-        </BankCoreApiProvider>
-      </BackendStateProvider>
-    </TranslationProvider >
+    <SettingsProvider value={settings}>
+      <TranslationProvider source={strings}>
+        <BackendStateProvider>
+          <BankCoreApiProvider baseUrl={baseUrl} frameOnError={BankFrame}>
+            <SWRConfig
+              value={{
+                provider: WITH_LOCAL_STORAGE_CACHE
+                  ? localStorageProvider
+                  : undefined,
+              }}
+            >
+              <Routing />
+            </SWRConfig>
+          </BankCoreApiProvider>
+        </BackendStateProvider>
+      </TranslationProvider >
+    </SettingsProvider>
   );
 };
 
@@ -66,7 +76,7 @@ function localStorageProvider(): Map<unknown, unknown> {
 
 export default App;
 
-function getInitialBackendBaseURL(): string {
+function getInitialBackendBaseURL(backendFromSettings: string | undefined): 
string {
   const overrideUrl =
     typeof localStorage !== "undefined"
       ? localStorage.getItem("bank-base-url")
@@ -75,13 +85,13 @@ function getInitialBackendBaseURL(): string {
 
   if (!overrideUrl) {
     //normal path
-    if (!bankUiSettings.backendBaseURL) {
+    if (!backendFromSettings) {
       console.error(
         "ERROR: backendBaseURL was overridden by a setting file and missing. 
Setting value to 'window.origin'",
       );
       result = window.origin
     } else {
-      result = bankUiSettings.backendBaseURL;
+      result = backendFromSettings;
     }
   } else {
     // testing/development path
diff --git a/packages/demobank-ui/dev.mjs 
b/packages/demobank-ui/src/context/settings.ts
old mode 100755
new mode 100644
similarity index 53%
copy from packages/demobank-ui/dev.mjs
copy to packages/demobank-ui/src/context/settings.ts
index 8b04155f4..a14c14d15
--- a/packages/demobank-ui/dev.mjs
+++ b/packages/demobank-ui/src/context/settings.ts
@@ -1,4 +1,3 @@
-#!/usr/bin/env node
 /*
  This file is part of GNU Taler
  (C) 2022 Taler Systems S.A.
@@ -15,27 +14,31 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { serve } from "@gnu-taler/web-util/node";
-import { initializeDev } from "@gnu-taler/web-util/build";
-
-const devEntryPoints = ["src/stories.tsx", "src/index.tsx", 
"src/bank-ui-settings.js"];
-
-const build = initializeDev({
-  type: "development",
-  source: {
-    js: devEntryPoints,
-    assets: [{ base: "src", files: ["src/index.html"] }],
-  },
-  destination: "./dist/dev",
-  public: "/app",
-  css: "postcss",
-});
-
-await build();
-
-serve({
-  folder: "./dist/dev",
-  port: 8080,
-  source: "./src",
-  onSourceUpdate: build,
-});
+import { ComponentChildren, createContext, h, VNode } from "preact";
+import { useContext } from "preact/hooks";
+import { BankUiSettings } from "../settings.js";
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+export type Type = BankUiSettings;
+
+const initial: BankUiSettings = {};
+const Context = createContext<Type>(initial);
+
+export const useSettingsContext = (): Type => useContext(Context);
+
+export const SettingsProvider = ({
+  children,
+  value,
+}: {
+  value: BankUiSettings,
+  children: ComponentChildren;
+}): VNode => {
+  return h(Context.Provider, {
+    value,
+    children,
+  });
+};
diff --git a/packages/demobank-ui/src/hooks/backend.ts 
b/packages/demobank-ui/src/hooks/backend.ts
index 93d647e73..863b47bf3 100644
--- a/packages/demobank-ui/src/hooks/backend.ts
+++ b/packages/demobank-ui/src/hooks/backend.ts
@@ -29,7 +29,6 @@ import {
   useLocalStorage
 } from "@gnu-taler/web-util/browser";
 import { useSWRConfig } from "swr";
-import { bankUiSettings } from "../settings.js";
 
 /**
  * Has the information to reach and
diff --git a/packages/demobank-ui/src/hooks/circuit.ts 
b/packages/demobank-ui/src/hooks/circuit.ts
index d0d180a53..c0164d60a 100644
--- a/packages/demobank-ui/src/hooks/circuit.ts
+++ b/packages/demobank-ui/src/hooks/circuit.ts
@@ -34,9 +34,7 @@ export type TransferCalculation = {
 };
 type EstimatorFunction = (
   amount: AmountJson,
-  currency: string,
-  sellFee: AmountJson,
-  sellRate: number,
+  fee: AmountJson,
 ) => Promise<TransferCalculation>;
 
 type CashoutEstimators = {
@@ -73,25 +71,19 @@ export function useEstimator(): CashoutEstimators {
   const { state } = useBackendState();
   const { api } = useBankCoreApiContext();
   return {
-    estimateByCredit: async (fiatAmount, regionalCurrency, fee, rate) => {
-      // const resp = await api.getConversionInfoAPI().getCashoutRate({
-      //   credit: amount
-      // });
-      // if (resp.type === "fail") {
-      //   // can't happen
-      //   // not-supported: it should not be able to call this function
-      //   // wrong-calculation: we are using just one parameter
-      //   throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint)
-      // }
-      const credit = fiatAmount;
-      const beforeFee = Amounts.sub(credit, fee).amount;
-
-      // const debit = Amounts.parseOrThrow(resp.body.amount_debit);
-      //FIXME: remove this when endpoint works
-      const debit = Amounts.add(
-        Amounts.zeroOfCurrency(regionalCurrency),
-        beforeFee
-      ).amount;
+    estimateByCredit: async (fiatAmount, fee) => {
+      const resp = await api.getConversionInfoAPI().getCashoutRate({
+        credit: fiatAmount
+      });
+      if (resp.type === "fail") {
+        // can't happen
+        // not-supported: it should not be able to call this function
+        // wrong-calculation: we are using just one parameter
+        throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint)
+      }
+      const credit = Amounts.parseOrThrow(resp.body.amount_credit);
+      const debit = Amounts.parseOrThrow(resp.body.amount_debit);
+      const beforeFee = Amounts.add(credit, fee).amount;
 
       return {
         debit,
@@ -99,19 +91,20 @@ export function useEstimator(): CashoutEstimators {
         credit,
       };
     },
-    estimateByDebit: async (regionalAmount, fiatCurrency, fee, rate) => {
-      // const resp = await api.getConversionInfoAPI().getCashoutRate({ debit: 
amount });
-      // if (resp.type === "fail") {
-      //   // can't happen
-      //   // not-supported: it should not be able to call this function
-      //   // wrong-calculation: we are using just one parameter
-      //   throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint)
-      // }
-      // const credit = Amounts.parseOrThrow(resp.body.amount_credit);
-      const debit = regionalAmount;
-      const _credit = Amounts.parseOrThrow(regionalAmount);
-      const beforeFee = { ..._credit, currency: fiatCurrency };
-      const credit = Amounts.sub(beforeFee, fee).amount;
+    estimateByDebit: async (regionalAmount, fee) => {
+      const resp = await api.getConversionInfoAPI().getCashoutRate({ 
+        debit: regionalAmount 
+      });
+      if (resp.type === "fail") {
+        // can't happen
+        // not-supported: it should not be able to call this function
+        // wrong-calculation: we are using just one parameter
+        throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint)
+      }
+      const credit = Amounts.parseOrThrow(resp.body.amount_credit);
+      const debit = Amounts.parseOrThrow(resp.body.amount_debit);
+      const beforeFee = Amounts.add(credit, fee).amount;
+
       return {
         debit,
         beforeFee,
diff --git a/packages/demobank-ui/src/hooks/settings.ts 
b/packages/demobank-ui/src/hooks/preferences.ts
similarity index 78%
rename from packages/demobank-ui/src/hooks/settings.ts
rename to packages/demobank-ui/src/hooks/preferences.ts
index bd48ca680..a1525ac80 100644
--- a/packages/demobank-ui/src/hooks/settings.ts
+++ b/packages/demobank-ui/src/hooks/preferences.ts
@@ -25,7 +25,7 @@ import {
 } from "@gnu-taler/taler-util";
 import { buildStorageKey, useLocalStorage, useTranslationContext } from 
"@gnu-taler/web-util/browser";
 
-interface Settings {
+interface Preferences {
   currentWithdrawalOperationId: string | undefined;
   showWithdrawalSuccess: boolean;
   showDemoDescription: boolean;
@@ -36,11 +36,11 @@ interface Settings {
 
 }
 
-export function getAllBooleanSettings(): Array<keyof Settings> {
+export function getAllBooleanPreferences(): Array<keyof Preferences> {
   return ["fastWithdrawal", "showDebugInfo", "showDemoDescription", 
"showInstallWallet", "showWithdrawalSuccess"]
 }
 
-export function getLabelForSetting(k: keyof Settings, i18n: ReturnType<typeof 
useTranslationContext>["i18n"]): TranslatedString {
+export function getLabelForPreferences(k: keyof Preferences, i18n: 
ReturnType<typeof useTranslationContext>["i18n"]): TranslatedString {
   switch (k) {
     case "currentWithdrawalOperationId": return i18n.str`Current withdrawal 
operation`
     case "maxWithdrawalAmount": return i18n.str`Max withdrawal amount`
@@ -52,8 +52,8 @@ export function getLabelForSetting(k: keyof Settings, i18n: 
ReturnType<typeof us
   }
 }
 
-export const codecForSettings = (): Codec<Settings> =>
-  buildCodecForObject<Settings>()
+export const codecForPreferences = (): Codec<Preferences> =>
+  buildCodecForObject<Preferences>()
     .property("currentWithdrawalOperationId", codecOptional(codecForString()))
     .property("showWithdrawalSuccess", (codecForBoolean()))
     .property("showDemoDescription", (codecForBoolean()))
@@ -63,7 +63,7 @@ export const codecForSettings = (): Codec<Settings> =>
     .property("maxWithdrawalAmount", codecForNumber())
     .build("Settings");
 
-const defaultSettings: Settings = {
+const defaultPreferences: Preferences = {
   currentWithdrawalOperationId: undefined,
   showWithdrawalSuccess: true,
   showDemoDescription: true,
@@ -73,21 +73,21 @@ const defaultSettings: Settings = {
   showDebugInfo: false,
 };
 
-const BANK_SETTINGS_KEY = buildStorageKey(
-  "bank-settings",
-  codecForSettings(),
+const BANK_PREFERENCES_KEY = buildStorageKey(
+  "bank-preferences",
+  codecForPreferences(),
 );
 
-export function useSettings(): [
-  Readonly<Settings>,
-  <T extends keyof Settings>(key: T, value: Settings[T]) => void,
+export function usePreferences(): [
+  Readonly<Preferences>,
+  <T extends keyof Preferences>(key: T, value: Preferences[T]) => void,
 ] {
   const { value, update } = useLocalStorage(
-    BANK_SETTINGS_KEY,
-    defaultSettings,
+    BANK_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);
   }
diff --git a/packages/demobank-ui/src/index.html 
b/packages/demobank-ui/src/index.html
index f702f30ea..3cc7f7fd2 100644
--- a/packages/demobank-ui/src/index.html
+++ b/packages/demobank-ui/src/index.html
@@ -29,8 +29,6 @@
     
href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn
 [...]
   <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
   <title>Bank</title>
-  <!-- Optional customization script.  -->
-  <script src="bank-ui-settings.js"></script>
   <!-- Entry point for the bank SPA. -->
   <script type="module" src="index.js"></script>
   <link rel="stylesheet" href="index.css" />
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx 
b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index 0f5236192..cfee684fa 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -18,7 +18,7 @@ import { useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { Attention } from "@gnu-taler/web-util/browser";
 import { Transactions } from "../../components/Transactions/index.js";
-import { useSettings } from "../../hooks/settings.js";
+import { usePreferences } from "../../hooks/preferences.js";
 import { PaymentOptions } from "../PaymentOptions.js";
 import { State } from "./index.js";
 
@@ -32,7 +32,7 @@ const IS_PUBLIC_ACCOUNT_ENABLED = false
 
 function ShowDemoInfo(): VNode {
   const { i18n } = useTranslationContext();
-  const [settings, updateSettings] = useSettings();
+  const [settings, updateSettings] = usePreferences();
   if (!settings.showDemoDescription) return <Fragment />
   return <Attention title={i18n.str`This is a demo bank`} onClose={() => {
     updateSettings("showDemoDescription", false);
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx 
b/packages/demobank-ui/src/pages/BankFrame.tsx
index f0baae3a3..5fef04b66 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -20,9 +20,9 @@ import { ComponentChildren, Fragment, VNode, h } from 
"preact";
 import { useEffect, useErrorBoundary } from "preact/hooks";
 import { useAccountDetails } from "../hooks/access.js";
 import { useBackendState } from "../hooks/backend.js";
-import { getAllBooleanSettings, getLabelForSetting, useSettings } from 
"../hooks/settings.js";
-import { bankUiSettings } from "../settings.js";
+import { getAllBooleanPreferences, getLabelForPreferences, usePreferences } 
from "../hooks/preferences.js";
 import { RenderAmount } from "./PaytoWireTransferForm.js";
+import { useSettingsContext } from "../context/settings.js";
 
 const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : 
undefined;
 const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
@@ -37,7 +37,8 @@ export function BankFrame({
 }): VNode {
   const { i18n } = useTranslationContext();
   const backend = useBackendState();
-  const [settings, updateSettings] = useSettings();
+  const settings = useSettingsContext();
+  const [preferences, updatePreferences] = usePreferences();
 
   const [error, resetError] = useErrorBoundary();
 
@@ -59,12 +60,12 @@ export function BankFrame({
     <div class="bg-indigo-600 pb-32">
       <Header
         title="Bank"
-        iconLinkURL={bankUiSettings.iconLinkURL ?? "#"}
+        iconLinkURL={settings.iconLinkURL ?? "#"}
         onLogout={backend.state.status !== "loggedIn" ? undefined : () => {
           backend.logOut()
-          updateSettings("currentWithdrawalOperationId", undefined);
+          updatePreferences("currentWithdrawalOperationId", undefined);
         }}
-        sites={bankUiSettings.demoSites ?? []}
+        sites={settings.demoSites ?? new Array<Array<string>>(new 
Array<string>())}
         supportedLangs={["en", "es", "de"]}
       >
         <li>
@@ -72,18 +73,18 @@ export function BankFrame({
             <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 class="mt-2 pl-2">
                 <div class="flex items-center justify-between">
                   <span class="flex flex-grow flex-col">
                     <span class="text-sm text-black font-medium leading-6 " 
id="availability-label">
-                      {getLabelForSetting(set, i18n)}
+                      {getLabelForPreferences(set, i18n)}
                     </span>
                   </span>
                   <button type="button" data-enabled={isOn} 
class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 
w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent 
transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 
focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" 
aria-labelledby="availability-label" aria-describedby="availability-description"
 
-                    onClick={() => { updateSettings(set, !isOn); }}>
+                    onClick={() => { updatePreferences(set, !isOn); }}>
                     <span aria-hidden="true" data-enabled={isOn} 
class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none 
inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition 
duration-200 ease-in-out"></span>
                   </button>
                 </div>
@@ -130,7 +131,7 @@ export function BankFrame({
 }
 
 function MaybeShowDebugInfo({ info }: { info: any }): VNode {
-  const [settings] = useSettings()
+  const [settings] = usePreferences()
   if (settings.showDebugInfo) {
     return <pre class="whitespace-break-spaces ">
       {info}
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx 
b/packages/demobank-ui/src/pages/LoginForm.tsx
index 018416390..02ec75dbf 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -15,18 +15,14 @@
  */
 
 import { TranslatedString } from "@gnu-taler/taler-util";
-import { Notification, useLocalNotification, useTranslationContext } from 
"@gnu-taler/web-util/browser";
+import { LocalNotificationBanner, ShowInputErrorLabel, useLocalNotification, 
useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useEffect, useRef, useState } from "preact/hooks";
-import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser";
 import { useBankCoreApiContext } from "../context/config.js";
 import { useBackendState } from "../hooks/backend.js";
-import { bankUiSettings } from "../settings.js";
-import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js";
-import { assertUnreachable } from "./WithdrawalOperationPage.js";
+import { undefinedIfEmpty } from "../utils.js";
 import { doAutoFocus } from "./PaytoWireTransferForm.js";
-import { Attention } from "@gnu-taler/web-util/browser";
-import { LocalNotificationBanner } from "@gnu-taler/web-util/browser";
+import { assertUnreachable } from "./WithdrawalOperationPage.js";
 
 
 /**
@@ -40,6 +36,7 @@ export function LoginForm({ reason, onRegister }: { reason?: 
"not-found" | "forb
   const { i18n } = useTranslationContext();
   const { api } = useBankCoreApiContext();
   const [notification, notify, handleError] = useLocalNotification()
+  const {config} = useBankCoreApiContext();
 
   /** 
    * Register form may be shown in the initialization step.
@@ -208,7 +205,7 @@ export function LoginForm({ reason, onRegister }: { 
reason?: "not-found" | "forb
           </div>}
         </form>
 
-        {bankUiSettings.allowRegistrations && onRegister &&
+        {config.allow_registrations && onRegister &&
           <p class="mt-10 text-center text-sm text-gray-500 border-t">
             <button type="submit"
               class="flex mt-4 rounded-md bg-blue-600 px-3 py-1.5 text-sm 
font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 
focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 
focus-visible:outline-blue-600"
diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts 
b/packages/demobank-ui/src/pages/OperationState/state.ts
index 2d33ff78b..30f7419f0 100644
--- a/packages/demobank-ui/src/pages/OperationState/state.ts
+++ b/packages/demobank-ui/src/pages/OperationState/state.ts
@@ -21,12 +21,12 @@ import { mutate } from "swr";
 import { useBankCoreApiContext } from "../../context/config.js";
 import { useWithdrawalDetails } from "../../hooks/access.js";
 import { useBackendState } from "../../hooks/backend.js";
-import { useSettings } from "../../hooks/settings.js";
+import { usePreferences } from "../../hooks/preferences.js";
 import { assertUnreachable } from "../WithdrawalOperationPage.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState({ currency, onClose }: Props): 
utils.RecursiveState<State> {
-  const [settings, updateSettings] = useSettings()
+  const [settings, updateSettings] = usePreferences()
   const { state: credentials } = useBackendState()
   const creds = credentials.status !== "loggedIn" ? undefined : credentials
   const { api } = useBankCoreApiContext()
diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx 
b/packages/demobank-ui/src/pages/OperationState/views.tsx
index e7db566ea..a06147039 100644
--- a/packages/demobank-ui/src/pages/OperationState/views.tsx
+++ b/packages/demobank-ui/src/pages/OperationState/views.tsx
@@ -20,7 +20,7 @@ import { Fragment, VNode, h } from "preact";
 import { useEffect, useMemo, useState } from "preact/hooks";
 import { QR } from "../../components/QR.js";
 import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser";
-import { useSettings } from "../../hooks/settings.js";
+import { usePreferences } from "../../hooks/preferences.js";
 import { undefinedIfEmpty } from "../../utils.js";
 import { State } from "./index.js";
 import { LocalNotificationBanner } from "@gnu-taler/web-util/browser";
@@ -46,7 +46,7 @@ export function InvalidReserveView({ reserve, onClose }: 
State.InvalidReserve) {
 
 export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: 
doConfirm, busy }: State.NeedConfirmation) {
   const { i18n } = useTranslationContext()
-  const [settings] = useSettings()
+  const [settings] = usePreferences()
   const [notification, notify, errorHandler] = useLocalNotification()
 
   const captchaNumbers = useMemo(() => {
@@ -309,7 +309,7 @@ export function AbortedView({ error, onClose }: 
State.Aborted) {
 
 export function ConfirmedView({ error, onClose }: State.Confirmed) {
   const { i18n } = useTranslationContext();
-  const [settings, updateSettings] = useSettings()
+  const [settings, updateSettings] = usePreferences()
   return (
     <Fragment>
 
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx 
b/packages/demobank-ui/src/pages/PaymentOptions.tsx
index 2e756b86d..76d20867e 100644
--- a/packages/demobank-ui/src/pages/PaymentOptions.tsx
+++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx
@@ -20,7 +20,7 @@ import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { PaytoWireTransferForm, doAutoFocus } from 
"./PaytoWireTransferForm.js";
 import { WalletWithdrawForm } from "./WalletWithdrawForm.js";
-import { useSettings } from "../hooks/settings.js";
+import { usePreferences } from "../hooks/preferences.js";
 
 /**
  * Let the user choose a payment option,
@@ -28,7 +28,7 @@ import { useSettings } from "../hooks/settings.js";
  */
 export function PaymentOptions({ limit, goToConfirmOperation }: { limit: 
AmountJson, goToConfirmOperation: (id: string) => void }): VNode {
   const { i18n } = useTranslationContext();
-  const [settings] = useSettings();
+  const [settings] = usePreferences();
 
   const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | 
undefined>();
 
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx 
b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index fdaa28bbb..9c3b21097 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -15,18 +15,18 @@
  */
 import { AccessToken, Logger, TranslatedString } from "@gnu-taler/taler-util";
 import {
+  LocalNotificationBanner,
+  ShowInputErrorLabel,
   useLocalNotification,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
-import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser";
 import { useBankCoreApiContext } from "../context/config.js";
 import { useBackendState } from "../hooks/backend.js";
-import { bankUiSettings } from "../settings.js";
-import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js";
+import { undefinedIfEmpty } from "../utils.js";
 import { getRandomPassword, getRandomUsername } from "./rnd.js";
-import { LocalNotificationBanner } from "@gnu-taler/web-util/browser";
+import { useSettingsContext } from "../context/settings.js";
 
 const logger = new Logger("RegistrationPage");
 
@@ -38,7 +38,8 @@ export function RegistrationPage({
   onCancel: () => void;
 }): VNode {
   const { i18n } = useTranslationContext();
-  if (!bankUiSettings.allowRegistrations) {
+  const {config} = useBankCoreApiContext();
+  if (!config.allow_registrations) {
     return (
       <p>{i18n.str`Currently, the bank is not accepting new 
registrations!`}</p>
     );
@@ -62,6 +63,7 @@ function RegistrationForm({ onComplete, onCancel }: { 
onComplete: () => void, on
   const [email, setEmail] = useState<string | undefined>();
   const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
   const [notification, notify, handleError] = useLocalNotification()
+  const settings = useSettingsContext();
 
   const { api } = useBankCoreApiContext()
   // const { register } = useTestingAPI();
@@ -177,7 +179,8 @@ function RegistrationForm({ onComplete, onCancel }: { 
onComplete: () => void, on
 
   async function doRandomRegistration(tries: number = 3) {
     const user = getRandomUsername();
-    const pass = getRandomPassword();
+     
+    const pass = settings.simplePasswordForRandomAccounts ? "123" : 
getRandomPassword();
     const username = `_${user.first}-${user.second}_`
     await doRegistrationAndLogin(name, username, pass)
     onComplete();
@@ -389,7 +392,7 @@ function RegistrationForm({ onComplete, onCancel }: { 
onComplete: () => void, on
 
           </form>
 
-          {bankUiSettings.allowRandomAccountCreation &&
+          {settings.allowRandomAccountCreation &&
             <p class="mt-10 text-center text-sm text-gray-500 border-t">
               <button type="submit"
                 class="flex mt-4 w-full justify-center rounded-md bg-green-600 
px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm 
hover:bg-green-500 focus-visible:outline focus-visible:outline-2 
focus-visible:outline-offset-2 focus-visible:outline-green-600"
diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx 
b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
index a9a661c25..5eef95f1e 100644
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
@@ -32,7 +32,7 @@ import { useState } from "preact/hooks";
 import { Attention } from "@gnu-taler/web-util/browser";
 import { useBankCoreApiContext } from "../context/config.js";
 import { useBackendState } from "../hooks/backend.js";
-import { useSettings } from "../hooks/settings.js";
+import { usePreferences } from "../hooks/preferences.js";
 import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js";
 import { OperationState } from "./OperationState/index.js";
 import { InputAmount, doAutoFocus } from "./PaytoWireTransferForm.js";
@@ -50,7 +50,7 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, 
onCancel, focus }: {
   onCancel: () => void;
 }): VNode {
   const { i18n } = useTranslationContext();
-  const [settings, updateSettings] = useSettings()
+  const [settings, updateSettings] = usePreferences()
 
   const { state: credentials } = useBackendState();
   const creds = credentials.status !== "loggedIn" ? undefined : credentials
@@ -240,7 +240,7 @@ export function WalletWithdrawForm({
   onCancel: () => void;
 }): VNode {
   const { i18n } = useTranslationContext();
-  const [settings, updateSettings] = useSettings()
+  const [settings, updateSettings] = usePreferences()
 
   return (<div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 
bg-gray-100 my-4 px-4 pb-4 rounded-lg">
     <div class="px-4 sm:px-0">
diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx 
b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
index 7fec76d2f..be8ff8b58 100644
--- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
@@ -33,7 +33,7 @@ import { useMemo, useState } from "preact/hooks";
 import { mutate } from "swr";
 import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser";
 import { useBankCoreApiContext } from "../context/config.js";
-import { useSettings } from "../hooks/settings.js";
+import { usePreferences } from "../hooks/preferences.js";
 import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js";
 import { RenderAmount } from "./PaytoWireTransferForm.js";
 import { assertUnreachable } from "./WithdrawalOperationPage.js";
@@ -60,7 +60,7 @@ export function WithdrawalConfirmationQuestion({
   withdrawUri,
 }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const [settings, updateSettings] = useSettings()
+  const [settings, updateSettings] = usePreferences()
 
   const captchaNumbers = useMemo(() => {
     return {
diff --git a/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx 
b/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
index 5ed57a0f7..7060b7a98 100644
--- a/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
@@ -25,7 +25,7 @@ import {
 import { Fragment, VNode, h } from "preact";
 import { Attention } from "@gnu-taler/web-util/browser";
 import { useBankCoreApiContext } from "../context/config.js";
-import { useSettings } from "../hooks/settings.js";
+import { usePreferences } from "../hooks/preferences.js";
 import { WithdrawalQRCode } from "./WithdrawalQRCode.js";
 
 const logger = new Logger("AccountPage");
@@ -44,7 +44,7 @@ export function WithdrawalOperationPage({
   });
   const parsedUri = parseWithdrawUri(uri);
   const { i18n } = useTranslationContext();
-  const [settings, updateSettings] = useSettings();
+  const [settings, updateSettings] = usePreferences();
 
   if (!parsedUri) {
     return <Attention type="danger" title={i18n.str`The Withdrawal URI is not 
valid`}>
diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx 
b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
index 1838dbda3..c5f4ebc4e 100644
--- a/packages/demobank-ui/src/pages/business/CreateCashout.tsx
+++ b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
@@ -77,7 +77,7 @@ export function CreateCashout({
     estimateByCredit: calculateFromCredit,
     estimateByDebit: calculateFromDebit,
   } = useEstimator();
-  const { api, config } = useBankCoreApiContext()
+  const { config } = useBankCoreApiContext()
   const [form, setForm] = useState<Partial<FormType>>({ isDebit: true, amount: 
"2" });
   const [notification, notify, handleError] = useLocalNotification()
   const info = useConversionInfo();
@@ -108,35 +108,29 @@ export function CreateCashout({
     return <ErrorLoading error={info} />
   }
 
+  const conversionInfo = info.body.conversion_info
+  if (!conversionInfo) {
+    return <div>conversion enabled but server replied without 
conversion_info</div>
+  }
+
   const account = {
     balance: Amounts.parseOrThrow(resultAccount.body.balance.amount),
     balanceIsDebit: resultAccount.body.balance.credit_debit_indicator == 
"debit",
     debitThreshold: Amounts.parseOrThrow(resultAccount.body.debit_threshold)
   }
 
-  const { fiat_currency, regional_currency, cashout_ratio, cashout_fee } = 
info.body
+  const {fiat_currency, regional_currency} = info.body
   const regionalZero = Amounts.zeroOfCurrency(regional_currency);
   const fiatZero = Amounts.zeroOfCurrency(fiat_currency);
   const limit = account.balanceIsDebit
     ? Amounts.sub(account.debitThreshold, account.balance).amount
     : Amounts.add(account.balance, account.debitThreshold).amount;
 
-  const zeroCalc = { debit: regionalZero, credit: fiatZero, beforeFee: 
regionalZero };
+  const zeroCalc = { debit: regionalZero, credit: fiatZero, beforeFee: 
fiatZero };
   const [calc, setCalc] = useState(zeroCalc);
-
-  const sellRate = Number.parseFloat(cashout_ratio);
-  const sellFee = !cashout_fee
-    ? fiatZero
-    : Amounts.parseOrThrow(cashout_fee);
-
-  if (sellRate === undefined || sellRate < 0) return <div>error rate d
-    <pre>
-      {JSON.stringify(info.body, undefined, 2)}
-    </pre>
-  </div>;
-
-  const safeSellRate = sellRate
-
+  console.log(calc)
+  const sellFee = Amounts.parseOrThrow(conversionInfo.cashout_fee);
+  const sellRate = conversionInfo.cashout_ratio
   /**
    * can be in regional currency or fiat currency
    * depending on the isDebit flag
@@ -150,8 +144,8 @@ export function CreateCashout({
       await handleError(async () => {
         if (Amounts.isNonZero(inputAmount)) {
           const resp = await (form.isDebit ?
-            calculateFromDebit(inputAmount, fiat_currency, sellFee, 
safeSellRate) :
-            calculateFromCredit(inputAmount, regional_currency, sellFee, 
safeSellRate));
+            calculateFromDebit(inputAmount, sellFee) :
+            calculateFromCredit(inputAmount, sellFee));
           setCalc(resp)
         }
       })
diff --git a/packages/demobank-ui/src/pages/rnd.ts 
b/packages/demobank-ui/src/pages/rnd.ts
index 32c3a934f..46111425e 100644
--- a/packages/demobank-ui/src/pages/rnd.ts
+++ b/packages/demobank-ui/src/pages/rnd.ts
@@ -1,5 +1,4 @@
 import { createEddsaKeyPair, encodeCrock, getRandomBytes } from 
"@gnu-taler/taler-util"
-import { bankUiSettings } from "../settings.js"
 
 
 const noun = [
@@ -2890,6 +2889,5 @@ export function getRandomUsername(): { first: string, 
second: string } {
 }
 
 export function getRandomPassword(): string {
-  if (bankUiSettings.simplePasswordForRandomAccounts) return "123"
   return encodeCrock(getRandomBytes(16))
 }
\ No newline at end of file
diff --git a/packages/demobank-ui/src/settings.json 
b/packages/demobank-ui/src/settings.json
new file mode 100644
index 000000000..8d5b149b5
--- /dev/null
+++ b/packages/demobank-ui/src/settings.json
@@ -0,0 +1,12 @@
+{
+  "backendBaseURL": "http://bank.taler.test:1180/";,
+  "showDemoNav": true,
+  "simplePasswordForRandomAccounts": true,
+  "allowRandomAccountCreation": true,
+  "bankName": "Taler DEVELOPMENT Bank",
+  "demoSites": [
+    ["Exchange", "https://Exchnage.taler.test/";],
+    ["Bank", "https://bank-ui.taler.test/";],
+    ["Merchant", "https://merchant.taler.test/";]
+  ]
+}
diff --git a/packages/demobank-ui/src/settings.ts 
b/packages/demobank-ui/src/settings.ts
index f17d1d511..a9c63857b 100644
--- a/packages/demobank-ui/src/settings.ts
+++ b/packages/demobank-ui/src/settings.ts
@@ -14,15 +14,16 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { Codec, buildCodecForObject, codecForBoolean, codecForList, 
codecForString, codecOptional } from "@gnu-taler/taler-util";
+
 export interface BankUiSettings {
   backendBaseURL?: string;
-  allowRegistrations?: boolean;
   iconLinkURL?: string;
   showDemoNav?: boolean;
   simplePasswordForRandomAccounts?: boolean;
   allowRandomAccountCreation?: boolean;
   bankName?: string;
-  demoSites?: [string, string][];
+  demoSites?: Array<Array<string>>;
 }
 
 /**
@@ -31,7 +32,6 @@ export interface BankUiSettings {
 const defaultSettings: BankUiSettings = {
   backendBaseURL: "https://bank.demo.taler.net/demobanks/default/";,
   iconLinkURL: "https://demo.taler.net/";,
-  allowRegistrations: true,
   bankName: "Taler Bank",
   showDemoNav: true,
   simplePasswordForRandomAccounts: true,
@@ -45,7 +45,26 @@ const defaultSettings: BankUiSettings = {
   ],
 };
 
-export const bankUiSettings: BankUiSettings =
-  "talerBankSettings" in globalThis
-    ? (globalThis as any).talerBankSettings
-    : defaultSettings;
+const codecForBankUISettings = (): Codec<BankUiSettings> =>
+  buildCodecForObject<BankUiSettings>()
+    .property("allowRandomAccountCreation", codecOptional(codecForBoolean()))
+    .property("backendBaseURL", codecOptional(codecForString()))
+    .property("bankName", codecOptional(codecForString()))
+    .property("demoSites", 
codecOptional(codecForList(codecForList(codecForString()))))
+    .property("iconLinkURL", codecOptional(codecForString()))
+    .property("showDemoNav", codecOptional(codecForBoolean()))
+    .property("simplePasswordForRandomAccounts", 
codecOptional(codecForBoolean()))
+    .build("BankUiSettings");
+
+export function fetchSettings(listener: (s: BankUiSettings) => void): void {
+  fetch("./settings.json")
+    .then(resp => resp.json())
+    .then(json => codecForBankUISettings().decode(json))
+    .then(listener)
+    .catch(e => {
+      console.log("failed to fetch settings", e)
+      listener(defaultSettings)
+    })
+}
+
+
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 3ef0ff76c..0ecc08b33 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -754,29 +754,21 @@ export const codecForConversionInfo =
     buildCodecForObject<TalerBankConversionApi.ConversionInfo>()
       .property("cashin_fee", codecForAmountString())
       .property("cashin_min_amount", codecForAmountString())
-      .property("cashin_ratio", codecForString())
-      // .property("cashin_ratio", codecForDecimalNumber())
-      .property(
-        "cashin_rounding_mode",
-        codecForEither(
-          codecForConstString("zero"),
-          codecForConstString("up"),
-          codecForConstString("nearest"),
-        ),
-      )
+      .property("cashin_ratio", codecForDecimalNumber())
+      .property("cashin_rounding_mode", codecForEither(
+        codecForConstString("zero"),
+        codecForConstString("up"),
+        codecForConstString("nearest")
+      ))
       .property("cashin_tiny_amount", codecForAmountString())
       .property("cashout_fee", codecForAmountString())
       .property("cashout_min_amount", codecForAmountString())
-      .property("cashout_ratio", codecForString())
-      // .property("cashout_ratio", codecForDecimalNumber())
-      .property(
-        "cashout_rounding_mode",
-        codecForEither(
-          codecForConstString("zero"),
-          codecForConstString("up"),
-          codecForConstString("nearest"),
-        ),
-      )
+      .property("cashout_ratio", codecForDecimalNumber())
+      .property("cashout_rounding_mode", codecForEither(
+        codecForConstString("zero"),
+        codecForConstString("up"),
+        codecForConstString("nearest")
+      ))
       .property("cashout_tiny_amount", codecForAmountString())
       .build("ConversionBankConfig.ConversionInfo");
 
@@ -792,34 +784,10 @@ export const codecForConversionBankConfig =
       )
       .property("fiat_currency", codecForString())
       .property("fiat_currency_specification", 
codecForCurrencySpecificiation())
-      // .property("conversion_info", codecOptional(codecForConversionInfo()))
-      ////////////////////////// remove this
-      .property("cashin_fee", codecForAmountString())
-      .property("cashin_min_amount", codecForAmountString())
-      .property("cashin_ratio", codecForString())
-      .property(
-        "cashin_rounding_mode",
-        codecForEither(
-          codecForConstString("zero"),
-          codecForConstString("up"),
-          codecForConstString("nearest"),
-        ),
-      )
-      .property("cashin_tiny_amount", codecForAmountString())
-      .property("cashout_fee", codecForAmountString())
-      .property("cashout_min_amount", codecForAmountString())
-      .property("cashout_ratio", codecForString())
-      .property(
-        "cashout_rounding_mode",
-        codecForEither(
-          codecForConstString("zero"),
-          codecForConstString("up"),
-          codecForConstString("nearest"),
-        ),
-      )
-      .property("cashout_tiny_amount", codecForAmountString())
-      //////////////////////////
-      .build("ConversionBankConfig.IntegrationConfig");
+
+      .property("conversion_info", codecOptional(codecForConversionInfo()))
+      .build("ConversionBankConfig.IntegrationConfig")
+
 // export const codecFor =
 //   (): Codec<TalerWireGatewayApi.PublicAccountsResponse> =>
 //     buildCodecForObject<TalerWireGatewayApi.PublicAccountsResponse>()
@@ -833,7 +801,7 @@ type EddsaSignature = string;
 type BlindedRsaSignature = string;
 type Base32 = string;
 
-type DecimalNumber = number;
+type DecimalNumber = string;
 type RsaSignature = string;
 // The type of a coin's blinded envelope depends on the cipher that is used
 // for signing with a denomination key.
@@ -859,11 +827,10 @@ interface CSCoinEnvelope {
 // a 256-bit nonce, converted to Crockford Base32.
 type DenominationBlindingKeyP = string;
 
-const codecForURL = codecForString;
-const codecForLibtoolVersion = codecForString;
-const codecForCurrencyName = codecForString;
-const codecForEddsaSignature = codecForString;
-const codecForDecimalNumber = codecForNumber;
+const codecForURL = codecForString
+const codecForLibtoolVersion = codecForString
+const codecForCurrencyName = codecForString
+const codecForDecimalNumber = codecForString
 
 enum TanChannel {
   SMS = "sms",
@@ -1065,12 +1032,10 @@ export namespace TalerRevenueApi {
 export namespace TalerBankConversionApi {
   export interface ConversionInfo {
     // Exchange rate to buy regional currency from fiat
-    // cashin_ratio: DecimalNumber;
-    cashin_ratio: string;
+    cashin_ratio: DecimalNumber;
 
     // Exchange rate to sell regional currency for fiat
-    // cashout_ratio: DecimalNumber;
-    cashout_ratio: string;
+    cashout_ratio: DecimalNumber;
 
     // Fee to subtract after applying the cashin ratio.
     cashin_fee: AmountString;
@@ -1097,7 +1062,7 @@ export namespace TalerBankConversionApi {
     cashout_rounding_mode: "zero" | "up" | "nearest";
   }
 
-  export interface IntegrationConfig extends ConversionInfo {
+  export interface IntegrationConfig {
     // libtool-style representation of the Bank protocol version, see
     // 
https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
     // The format is "current:revision:age".
@@ -1120,7 +1085,7 @@ export namespace TalerBankConversionApi {
 
     // Extra conversion rate information.
     // Only present if server opts in to report the static conversion rate.
-    // conversion_info?: ConversionInfo
+    conversion_info?: ConversionInfo
   }
 
   export interface CashinConversionResponse {
diff --git a/packages/web-util/src/components/Header.tsx 
b/packages/web-util/src/components/Header.tsx
index bde0688dc..0ffc57417 100644
--- a/packages/web-util/src/components/Header.tsx
+++ b/packages/web-util/src/components/Header.tsx
@@ -3,7 +3,8 @@ import { LangSelector, useTranslationContext } from 
"../index.browser.js";
 import { ComponentChildren, Fragment, VNode, h } from "preact";
 import logo from "../assets/logo-2021.svg";
 
-export function Header({ title, iconLinkURL, sites, supportedLangs, onLogout, 
children }: { title: string, iconLinkURL: string, children?: ComponentChildren, 
onLogout: (() => void) | undefined, sites: [string, string][], supportedLangs: 
string[] }): VNode {
+export function Header({ title, iconLinkURL, sites, supportedLangs, onLogout, 
children }: 
+  { title: string, iconLinkURL: string, children?: ComponentChildren, 
onLogout: (() => void) | undefined, sites: Array<Array<string>>, 
supportedLangs: string[] }): VNode {
   const { i18n } = useTranslationContext();
   const [open, setOpen] = useState(false)
   return <Fragment>
@@ -28,7 +29,9 @@ export function Header({ title, iconLinkURL, sites, 
supportedLangs, onLogout, ch
           {sites.length !== 0 &&
             <div class="flex flex-1 space-x-4">
               {/* <!-- Current: "bg-indigo-700 text-white", Default: 
"text-white hover:bg-indigo-500 hover:bg-opacity-75" --> */}
-              {sites.map(([name, url]) => {
+              {sites.map((site) => {
+                if (site.length !== 2) return;
+                const [name, url] = site
                 return <a href={url} class="text-white hover:bg-indigo-500 
hover:bg-opacity-75 rounded-md py-2 px-3 text-sm font-medium">{name}</a>
               })}
             </div>

-- 
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]