From 062939d9cc016a186a282f7a48492c3e01cd740c Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Thu, 21 Sep 2023 10:31:10 -0300
Subject: admin refactor

---
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  | 112 +++++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 packages/demobank-ui/src/pages/admin/RemoveAccount.tsx

(limited to 'packages/demobank-ui/src/pages/admin/RemoveAccount.tsx')

diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
new file mode 100644
index 000000000..2900db9d2
--- /dev/null
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -0,0 +1,112 @@
+import { ErrorType, HttpResponsePaginated, RequestError, notify, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { VNode,h,Fragment } from "preact";
+import { useAccountDetails } from "../../hooks/access.js";
+import { useAdminAccountAPI } from "../../hooks/circuit.js";
+import { Amounts, HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
+import { buildRequestErrorMessage } from "../../utils.js";
+
+export function RemoveAccount({
+    account,
+    onClear,
+    onUpdateSuccess,
+    onLoadNotOk,
+  }: {
+    onLoadNotOk: <T>(
+      error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
+    ) => VNode;
+    onClear: () => void;
+    onUpdateSuccess: () => void;
+    account: string;
+  }): VNode {
+    const { i18n } = useTranslationContext();
+    const result = useAccountDetails(account);
+    const { deleteAccount } = useAdminAccountAPI();
+  
+    if (!result.ok) {
+      if (result.loading || result.type === ErrorType.TIMEOUT) {
+        return onLoadNotOk(result);
+      }
+      if (result.status === HttpStatusCode.NotFound) {
+        return <div>account not found</div>;
+      }
+      return onLoadNotOk(result);
+    }
+  
+    const balance = Amounts.parse(result.data.balance.amount);
+    if (!balance) {
+      return <div>there was an error reading the balance</div>;
+    }
+    const isBalanceEmpty = Amounts.isZero(balance);
+    return (
+      <div>
+        <div>
+          <h1 class="nav welcome-text">
+            <i18n.Translate>Remove account: {account}</i18n.Translate>
+          </h1>
+        </div>
+        {/* {FXME: SHOW WARNING} */}
+        {/* {!isBalanceEmpty && (
+          <ErrorBannerFloat
+            error={{
+              title: i18n.str`Can't delete the account`,
+              description: i18n.str`Balance is not empty`,
+            }}
+            onClear={() => saveError(undefined)}
+          />
+        )} */}
+  
+        <p>
+          <div style={{ display: "flex", justifyContent: "space-between" }}>
+            <div>
+              <input
+                class="pure-button"
+                type="submit"
+                value={i18n.str`Cancel`}
+                onClick={async (e) => {
+                  e.preventDefault();
+                  onClear();
+                }}
+              />
+            </div>
+            <div>
+              <input
+                id="select-exchange"
+                class="pure-button pure-button-primary content"
+                disabled={!isBalanceEmpty}
+                type="submit"
+                value={i18n.str`Confirm`}
+                onClick={async (e) => {
+                  e.preventDefault();
+                  try {
+                    const r = await deleteAccount(account);
+                    onUpdateSuccess();
+                  } catch (error) {
+                    if (error instanceof RequestError) {
+                      notify(
+                        buildRequestErrorMessage(i18n, error.cause, {
+                          onClientError: (status) =>
+                            status === HttpStatusCode.Forbidden
+                              ? i18n.str`The administrator specified a institutional username`
+                              : status === HttpStatusCode.NotFound
+                                ? i18n.str`The username was not found`
+                                : status === HttpStatusCode.PreconditionFailed
+                                  ? i18n.str`Balance was not zero`
+                                  : undefined,
+                        }),
+                      );
+                    } else {
+                      notifyError(i18n.str`Operation failed, please report`,
+                        (error instanceof Error
+                            ? error.message
+                            : JSON.stringify(error)) as TranslatedString);
+                    }
+                  }
+                }}
+              />
+            </div>
+          </div>
+        </p>
+      </div>
+    );
+  }
+  
\ No newline at end of file
-- 
cgit v1.2.3


From 0b7bbed99d155ba030a1328e357ab6751bdbb835 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Thu, 21 Sep 2023 13:10:16 -0300
Subject: more ui: business and admin

---
 packages/demobank-ui/src/components/Routing.tsx    |  17 +-
 .../src/components/ShowInputErrorLabel.tsx         |   4 +-
 .../demobank-ui/src/pages/AccountPage/index.ts     |   5 +-
 .../demobank-ui/src/pages/AccountPage/state.ts     |   7 +-
 .../demobank-ui/src/pages/AccountPage/views.tsx    |  29 +-
 packages/demobank-ui/src/pages/BankFrame.tsx       |  32 +-
 packages/demobank-ui/src/pages/HomePage.tsx        |   6 +-
 packages/demobank-ui/src/pages/PaymentOptions.tsx  | 131 +++---
 .../src/pages/PaytoWireTransferForm.tsx            |   6 +-
 .../demobank-ui/src/pages/RegistrationPage.tsx     |   2 +-
 .../demobank-ui/src/pages/ShowAccountDetails.tsx   | 278 ++++++------
 .../src/pages/UpdateAccountPassword.tsx            | 278 +++++++-----
 packages/demobank-ui/src/pages/admin/Account.tsx   |  72 ++-
 .../demobank-ui/src/pages/admin/AccountForm.tsx    | 494 +++++++++++++--------
 .../demobank-ui/src/pages/admin/AccountList.tsx    | 182 +++++---
 .../src/pages/admin/CreateNewAccount.tsx           | 174 ++++----
 packages/demobank-ui/src/pages/admin/Home.tsx      |  51 +--
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  | 302 +++++++++----
 packages/demobank-ui/src/pages/business/Home.tsx   |   2 +-
 19 files changed, 1181 insertions(+), 891 deletions(-)

(limited to 'packages/demobank-ui/src/pages/admin/RemoveAccount.tsx')

diff --git a/packages/demobank-ui/src/components/Routing.tsx b/packages/demobank-ui/src/components/Routing.tsx
index ef11af76e..b8e39948b 100644
--- a/packages/demobank-ui/src/components/Routing.tsx
+++ b/packages/demobank-ui/src/components/Routing.tsx
@@ -33,12 +33,7 @@ export function Routing(): VNode {
   const backend = useBackendContext();
 
   if (backend.state.status === "loggedOut") {
-    return <BankFrame
-      account={undefined}
-      goToBusinessAccount={() => {
-        route("/business");
-      }}
-    >
+    return <BankFrame >
       <Router history={history}>
         <Route
           path="/login"
@@ -67,12 +62,7 @@ export function Routing(): VNode {
   const { isUserAdministrator, username } = backend.state
 
   return (
-    <BankFrame
-      account={backend.state.username}
-      goToBusinessAccount={() => {
-        route("/business");
-      }}
-    >
+    <BankFrame account={backend.state.username}>
       <Router history={history}>
         <Route
           path="/test"
@@ -121,6 +111,9 @@ export function Routing(): VNode {
                 onPendingOperationFound={(wopid) => {
                   route(`/operation/${wopid}`);
                 }}
+                goToBusinessAccount={() => {
+                  route("/business");
+                }}
                 onRegister={() => {
                   route("/register");
                 }}
diff --git a/packages/demobank-ui/src/components/ShowInputErrorLabel.tsx b/packages/demobank-ui/src/components/ShowInputErrorLabel.tsx
index dacffe20a..c5840cad9 100644
--- a/packages/demobank-ui/src/components/ShowInputErrorLabel.tsx
+++ b/packages/demobank-ui/src/components/ShowInputErrorLabel.tsx
@@ -24,6 +24,6 @@ export function ShowInputErrorLabel({
   isDirty: boolean;
 }): VNode {
   if (message && isDirty)
-    return <div style={{ marginTop: 8, color: "red" }}>{message}</div>;
-  return <Fragment />;
+    return <div class="text-base" style={{ color: "red" }}>{message}</div>;
+  return <div class="text-base" style={{ }}> </div>;
 }
diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts
index ed6945f84..128a6d30f 100644
--- a/packages/demobank-ui/src/pages/AccountPage/index.ts
+++ b/packages/demobank-ui/src/pages/AccountPage/index.ts
@@ -28,6 +28,7 @@ export interface Props {
   onLoadNotOk: <T>(
     error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
   ) => VNode;
+  goToBusinessAccount: () => void;
 }
 
 export type State = State.Loading | State.LoadingError | State.Ready | State.InvalidIban | State.UserNotFound;
@@ -51,10 +52,8 @@ export namespace State {
     status: "ready";
     error: undefined;
     account: string, 
-    payto: PaytoUriIBAN | PaytoUriTalerBank, 
-    balance: AmountJson, 
-    balanceIsDebit: boolean, 
     limit: AmountJson,
+    goToBusinessAccount: () => void;
   }
 
   export interface InvalidIban {
diff --git a/packages/demobank-ui/src/pages/AccountPage/state.ts b/packages/demobank-ui/src/pages/AccountPage/state.ts
index 2249b743e..a57e19901 100644
--- a/packages/demobank-ui/src/pages/AccountPage/state.ts
+++ b/packages/demobank-ui/src/pages/AccountPage/state.ts
@@ -20,7 +20,7 @@ import { useBackendContext } from "../../context/backend.js";
 import { useAccountDetails } from "../../hooks/access.js";
 import { Props, State } from "./index.js";
 
-export function useComponentState({ account, onLoadNotOk }: Props): State {
+export function useComponentState({ account, goToBusinessAccount }: Props): State {
   const result = useAccountDetails(account);
   const backend = useBackendContext();
   const { i18n } = useTranslationContext();
@@ -60,7 +60,6 @@ export function useComponentState({ account, onLoadNotOk }: Props): State {
   const payto = parsePaytoUri(data.paytoUri);
 
   if (!payto || !payto.isKnown || (payto.targetType !== "iban" && payto.targetType !== "x-taler-bank")) {
-    console.log(payto)
     return {
       status: "invalid-iban",
       error: result
@@ -75,11 +74,9 @@ export function useComponentState({ account, onLoadNotOk }: Props): State {
 
   return {
     status: "ready",
+    goToBusinessAccount,
     error: undefined,
     account,
-    balance,
-    balanceIsDebit,
     limit,
-    payto
   };
 }
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index f2cbbba6c..abd14848f 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -22,6 +22,7 @@ import { PaymentOptions } from "../PaymentOptions.js";
 import { State } from "./index.js";
 import { CopyButton } from "../../components/CopyButton.js";
 import { bankUiSettings } from "../../settings.js";
+import { useBusinessAccountDetails } from "../../hooks/circuit.js";
 
 export function InvalidIbanView({ error }: State.InvalidIban) {
   return (
@@ -77,11 +78,35 @@ function ImportantMessage(): VNode {
 
 }
 
-export function ReadyView({ account, balance, balanceIsDebit, limit, payto }: State.Ready): VNode<{}> {
-  const { i18n } = useTranslationContext();
+export function ReadyView({ account, limit, goToBusinessAccount }: State.Ready): VNode<{}> {
   return <Fragment>
+    <MaybeBusinessButton account={account} onClick={goToBusinessAccount} />
     <PaymentOptions limit={limit} />
     <Transactions account={account} />
   </Fragment>;
 }
 
+function MaybeBusinessButton({
+  account,
+  onClick,
+}: {
+  account: string;
+  onClick: () => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const result = useBusinessAccountDetails(account);
+  if (!result.ok) return <Fragment />;
+  return (
+    <div class="w-full flex justify-end">
+      <button
+        class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+        onClick={(e) => {
+          e.preventDefault()
+          onClick()
+        }}
+      >
+        <i18n.Translate>Business Profile</i18n.Translate>
+      </button>
+    </div>
+  );
+}
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index 80a8224d4..4b23686d6 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -39,36 +39,12 @@ const versionText = VERSION
 
 const logger = new Logger("BankFrame");
 
-function MaybeBusinessButton({
-  account,
-  onClick,
-}: {
-  account: string;
-  onClick: () => void;
-}): VNode {
-  const { i18n } = useTranslationContext();
-  const result = useBusinessAccountDetails(account);
-  if (!result.ok) return <Fragment />;
-  return (
-    <a
-      href="#"
-      class="pure-button pure-button-primary"
-      onClick={(e) => {
-        e.preventDefault();
-        onClick();
-      }}
-    >{i18n.str`Business Profile`}</a>
-  );
-}
-
 export function BankFrame({
   children,
-  goToBusinessAccount,
   account,
 }: {
-  account: string | undefined,
+  account?: string,
   children: ComponentChildren;
-  goToBusinessAccount?: () => void;
 }): VNode {
   const { i18n } = useTranslationContext();
   const backend = useBackendContext();
@@ -489,5 +465,9 @@ function AccountBalance({ account }: { account: string }): VNode {
   const result = useAccountDetails(account);
   if (!result.ok) return <div />
 
-  return <div>{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""} {Amounts.currencyOf(result.data.balance.amount)} {Amounts.stringifyValue(result.data.balance.amount)}</div>
+  return <div>
+    {Amounts.currencyOf(result.data.balance.amount)}
+    &nbsp;{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""}
+    {Amounts.stringifyValue(result.data.balance.amount)}
+    </div>
 }
diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx
index a911f347c..40cc147a6 100644
--- a/packages/demobank-ui/src/pages/HomePage.tsx
+++ b/packages/demobank-ui/src/pages/HomePage.tsx
@@ -31,14 +31,11 @@ import {
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { Loading } from "../components/Loading.js";
-import { useBackendContext } from "../context/backend.js";
 import { getInitialBackendBaseURL } from "../hooks/backend.js";
 import { useSettings } from "../hooks/settings.js";
 import { AccountPage } from "./AccountPage/index.js";
-import { AdminHome } from "./admin/Home.js";
 import { LoginForm } from "./LoginForm.js";
 import { WithdrawalQRCode } from "./WithdrawalQRCode.js";
-import { error } from "console";
 
 const logger = new Logger("AccountPage");
 
@@ -56,10 +53,12 @@ export function HomePage({
   onRegister,
   account,
   onPendingOperationFound,
+  goToBusinessAccount,
 }: {
   account: string,
   onPendingOperationFound: (id: string) => void;
   onRegister: () => void;
+  goToBusinessAccount: () => void;
 }): VNode {
   const [settings] = useSettings();
   const { i18n } = useTranslationContext();
@@ -72,6 +71,7 @@ export function HomePage({
   return (
     <AccountPage
       account={account}
+      goToBusinessAccount={goToBusinessAccount}
       onLoadNotOk={handleNotOkResult(i18n, onRegister)}
     />
   );
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx
index c82c1b28d..5cb09a5d4 100644
--- a/packages/demobank-ui/src/pages/PaymentOptions.tsx
+++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx
@@ -33,76 +33,79 @@ export function PaymentOptions({ limit }: { limit: AmountJson }): VNode {
   const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>();
   // const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>(undefined);
 
-  return (<fieldset>
-    <legend class="px-4 text-base font-semibold leading-6 text-gray-900">
-      <i18n.Translate>Send money to</i18n.Translate>
-    </legend>
+  return (
+    <fieldset>
+      <legend class="px-4 text-base font-semibold leading-6 text-gray-900">
+        <i18n.Translate>Send money to</i18n.Translate>
+      </legend>
 
-    <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4">
-      {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */}
-      <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "charge-wallet" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
-        <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onClick={() => {
-          setTab("charge-wallet")
-        }} />
-        <span class="flex flex-1">
-          <span class="flex flex-col">
-            <span id="project-type-0-label" class="block text-sm font-medium text-gray-900">
-              <i18n.Translate>a <b>Taler</b> wallet</i18n.Translate>
-            </span>
-            <span id="project-type-0-description-0" class="mt-1 flex items-center text-sm text-gray-500">
-              <i18n.Translate>Withdraw digital money into your mobile wallet or browser extension</i18n.Translate>
+      <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4">
+        {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */}
+        <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "charge-wallet" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
+          <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onClick={() => {
+            setTab("charge-wallet")
+          }} />
+          <span class="flex flex-1">
+            <span class="flex flex-col">
+              <span id="project-type-0-label" class="block text-sm font-medium text-gray-900">
+                <i18n.Translate>a <b>Taler</b> wallet</i18n.Translate>
+              </span>
+              <span id="project-type-0-description-0" class="mt-1 flex items-center text-sm text-gray-500">
+                <i18n.Translate>Withdraw digital money into your mobile wallet or browser extension</i18n.Translate>
+              </span>
             </span>
           </span>
-        </span>
-        <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "charge-wallet" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-          <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
-        </svg>
-      </label>
+          <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "charge-wallet" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
+          </svg>
+        </label>
 
 
-      <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "wire-transfer" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
-        <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onClick={() => {
-          setTab("wire-transfer")
-        }} />
-        <span class="flex flex-1">
-          <span class="flex flex-col">
-            <span id="project-type-1-label" class="block text-sm font-medium text-gray-900">
-              <i18n.Translate>another bank account</i18n.Translate>
-            </span>
-            <span id="project-type-1-description-0" class="mt-1 flex items-center text-sm text-gray-500">
-              <i18n.Translate>Make a wire transfer to an account which you know the address.</i18n.Translate>
+        <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "wire-transfer" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
+          <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onClick={() => {
+            setTab("wire-transfer")
+          }} />
+          <span class="flex flex-1">
+            <span class="flex flex-col">
+              <span id="project-type-1-label" class="block text-sm font-medium text-gray-900">
+                <i18n.Translate>another bank account</i18n.Translate>
+              </span>
+              <span id="project-type-1-description-0" class="mt-1 flex items-center text-sm text-gray-500">
+                <i18n.Translate>Make a wire transfer to an account which you know the address.</i18n.Translate>
+              </span>
             </span>
           </span>
-        </span>
-        <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "wire-transfer" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-          <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
-        </svg>
-      </label>
-    </div>
-    {tab === "charge-wallet" && (
-      <WalletWithdrawForm
-        focus
-        limit={limit}
-        onSuccess={(id) => {
-          updateSettings("currentWithdrawalOperationId", id);
-        }}
-        onCancel={() => {
-          setTab(undefined)
-        }}
-      />
-    )}
-    {tab === "wire-transfer" && (
-      <PaytoWireTransferForm
-        focus
-        limit={limit}
-        onSuccess={() => {
-          notifyInfo(i18n.str`Wire transfer created!`);
-        }}
-        onCancel={() => {
-          setTab(undefined)
-        }}
-      />
-    )}
+          <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "wire-transfer" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
+          </svg>
+        </label>
+      </div>
+      {tab === "charge-wallet" && (
+        <WalletWithdrawForm
+          focus
+          limit={limit}
+          onSuccess={(id) => {
+            updateSettings("currentWithdrawalOperationId", id);
+          }}
+          onCancel={() => {
+            setTab(undefined)
+          }}
+        />
+      )}
+      {tab === "wire-transfer" && (
+        <PaytoWireTransferForm
+          focus
+          title={i18n.str`Transfer details`}
+          limit={limit}
+          onSuccess={() => {
+            notifyInfo(i18n.str`Wire transfer created!`);
+          }}
+          onCancel={() => {
+            setTab(undefined)
+          }}
+        />
+      )}
 
-  </fieldset>)
+    </fieldset>
+  )
 }
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
index cdaf363e3..af6f7caee 100644
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -44,10 +44,12 @@ const logger = new Logger("PaytoWireTransferForm");
 
 export function PaytoWireTransferForm({
   focus,
+  title,
   onSuccess,
   onCancel,
   limit,
 }: {
+  title: TranslatedString,
   focus?: boolean;
   onSuccess: () => void;
   onCancel: (() => void) | undefined;
@@ -158,7 +160,9 @@ export function PaytoWireTransferForm({
 
   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">
-      <h2 class="text-base font-semibold leading-7 text-gray-900"><i18n.Translate>Transfer details</i18n.Translate></h2>
+      <h2 class="text-base font-semibold leading-7 text-gray-900">
+        {title}
+      </h2>
       <div>
         <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-1 sm:gap-x-4">
           <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (!isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index b912b9060..f972e0380 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -45,7 +45,7 @@ export function RegistrationPage({
   return <RegistrationForm onComplete={onComplete} />;
 }
 
-export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9]*$/;
+export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9-]*$/;
 
 /**
  * Collect and submit registration data.
diff --git a/packages/demobank-ui/src/pages/ShowAccountDetails.tsx b/packages/demobank-ui/src/pages/ShowAccountDetails.tsx
index 91b50b84c..6acf0361e 100644
--- a/packages/demobank-ui/src/pages/ShowAccountDetails.tsx
+++ b/packages/demobank-ui/src/pages/ShowAccountDetails.tsx
@@ -1,5 +1,5 @@
 import { ErrorType, HttpResponsePaginated, RequestError, notify, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { VNode,h } from "preact";
+import { VNode, h } from "preact";
 import { useAdminAccountAPI, useBusinessAccountDetails } from "../hooks/circuit.js";
 import { useState } from "preact/hooks";
 import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
@@ -7,137 +7,161 @@ import { buildRequestErrorMessage } from "../utils.js";
 import { AccountForm } from "./admin/AccountForm.js";
 
 export function ShowAccountDetails({
-    account,
-    onClear,
-    onUpdateSuccess,
-    onLoadNotOk,
-    onChangePassword,
-  }: {
-    onLoadNotOk: <T>(
-      error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
-    ) => VNode;
-    onClear?: () => void;
-    onChangePassword: () => void;
-    onUpdateSuccess: () => void;
-    account: string;
-  }): VNode {
-    const { i18n } = useTranslationContext();
-    const result = useBusinessAccountDetails(account);
-    const { updateAccount } = useAdminAccountAPI();
-    const [update, setUpdate] = useState(false);
-    const [submitAccount, setSubmitAccount] = useState<
-      SandboxBackend.Circuit.CircuitAccountData | undefined
-    >();
-  
-    if (!result.ok) {
-      if (result.loading || result.type === ErrorType.TIMEOUT) {
-        return onLoadNotOk(result);
-      }
-      if (result.status === HttpStatusCode.NotFound) {
-        return <div>account not found</div>;
-      }
+  account,
+  onClear,
+  onUpdateSuccess,
+  onLoadNotOk,
+  onChangePassword,
+}: {
+  onLoadNotOk: <T>(
+    error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
+  ) => VNode;
+  onClear?: () => void;
+  onChangePassword: () => void;
+  onUpdateSuccess: () => void;
+  account: string;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const result = useBusinessAccountDetails(account);
+  const { updateAccount } = useAdminAccountAPI();
+  const [update, setUpdate] = useState(false);
+  const [submitAccount, setSubmitAccount] = useState<
+    SandboxBackend.Circuit.CircuitAccountData | undefined
+  >();
+
+  if (!result.ok) {
+    if (result.loading || result.type === ErrorType.TIMEOUT) {
       return onLoadNotOk(result);
     }
-  
-    return (
-      <div>
-        <div>
-          <h1 class="nav welcome-text">
-            <i18n.Translate>Business account details</i18n.Translate>
-          </h1>
+    if (result.status === HttpStatusCode.NotFound) {
+      return <div>account not found</div>;
+    }
+    return onLoadNotOk(result);
+  }
+
+  async function doUpdate() {
+    if (!update) {
+      setUpdate(true);
+    } else {
+      if (!submitAccount) return;
+      try {
+        await updateAccount(account, {
+          cashout_address: submitAccount.cashout_address,
+          contact_data: submitAccount.contact_data,
+        });
+        onUpdateSuccess();
+      } catch (error) {
+        if (error instanceof RequestError) {
+          notify(
+            buildRequestErrorMessage(i18n, error.cause, {
+              onClientError: (status) =>
+                status === HttpStatusCode.Forbidden
+                  ? i18n.str`The rights to change the account are not sufficient`
+                  : status === HttpStatusCode.NotFound
+                    ? i18n.str`The username was not found`
+                    : undefined,
+            }),
+          );
+        } else {
+          notifyError(
+            i18n.str`Operation failed, please report`,
+            (error instanceof Error
+              ? error.message
+              : JSON.stringify(error)) as TranslatedString
+          )
+        }
+      }
+    }
+  }
+
+  return (
+    <div>
+      <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">
+          <h2 class="text-base font-semibold leading-7 text-gray-900">
+            {update ?
+              <i18n.Translate>Update account</i18n.Translate>
+              :
+              <i18n.Translate>Account details</i18n.Translate>
+            }
+          </h2>
+          <div class="mt-4">
+        <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">
+              <i18n.Translate>change the account details</i18n.Translate>
+            </span>
+          </span>
+          <button type="button" data-enabled={!update} class="bg-indigo-600 data-[enabled=true]:bg-gray-200 relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer rounded-full ring-2 border-gray-600 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={() => {
+              setUpdate(!update)
+            }}>
+            <span aria-hidden="true" data-enabled={!update} class="translate-x-5 data-[enabled=true]: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>
-        <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}>
-          <AccountForm
-            template={result.data}
-            purpose={update ? "update" : "show"}
-            onChange={(a) => setSubmitAccount(a)}
-          />
-  
-          <p class="buttons-account">
-            <div
-              style={{
-                display: "flex",
-                justifyContent: "space-between",
-                flexFlow: "wrap-reverse",
-              }}
-            >
+      </div>
+
+        </div>
+        <AccountForm
+          template={result.data}
+          purpose={update ? "update" : "show"}
+          onChange={(a) => setSubmitAccount(a)}
+        >
+
+        </AccountForm>
+
+        <p class="buttons-account">
+          <div
+            style={{
+              display: "flex",
+              justifyContent: "space-between",
+              flexFlow: "wrap-reverse",
+            }}
+          >
+            <div>
+              {onClear ? (
+                <input
+                  class="pure-button"
+                  type="submit"
+                  value={i18n.str`Close`}
+                  onClick={async (e) => {
+                    e.preventDefault();
+                    onClear();
+                  }}
+                />
+              ) : undefined}
+            </div>
+            <div style={{ display: "flex" }}>
               <div>
-                {onClear ? (
-                  <input
-                    class="pure-button"
-                    type="submit"
-                    value={i18n.str`Close`}
-                    onClick={async (e) => {
-                      e.preventDefault();
-                      onClear();
-                    }}
-                  />
-                ) : undefined}
+                <input
+                  id="select-exchange"
+                  class="pure-button pure-button-primary content"
+                  disabled={update && !submitAccount}
+                  type="submit"
+                  value={i18n.str`Change password`}
+                  onClick={async (e) => {
+                    e.preventDefault();
+                    onChangePassword();
+                  }}
+                />
               </div>
-              <div style={{ display: "flex" }}>
-                <div>
-                  <input
-                    id="select-exchange"
-                    class="pure-button pure-button-primary content"
-                    disabled={update && !submitAccount}
-                    type="submit"
-                    value={i18n.str`Change password`}
-                    onClick={async (e) => {
-                      e.preventDefault();
-                      onChangePassword();
-                    }}
-                  />
-                </div>
-                <div>
-                  <input
-                    id="select-exchange"
-                    class="pure-button pure-button-primary content"
-                    disabled={update && !submitAccount}
-                    type="submit"
-                    value={update ? i18n.str`Confirm` : i18n.str`Update`}
-                    onClick={async (e) => {
-                      e.preventDefault();
-  
-                      if (!update) {
-                        setUpdate(true);
-                      } else {
-                        if (!submitAccount) return;
-                        try {
-                          await updateAccount(account, {
-                            cashout_address: submitAccount.cashout_address,
-                            contact_data: submitAccount.contact_data,
-                          });
-                          onUpdateSuccess();
-                        } catch (error) {
-                          if (error instanceof RequestError) {
-                            notify(
-                              buildRequestErrorMessage(i18n, error.cause, {
-                                onClientError: (status) =>
-                                  status === HttpStatusCode.Forbidden
-                                    ? i18n.str`The rights to change the account are not sufficient`
-                                    : status === HttpStatusCode.NotFound
-                                      ? i18n.str`The username was not found`
-                                      : undefined,
-                              }),
-                            );
-                          } else {
-                            notifyError(
-                              i18n.str`Operation failed, please report`,
-                              (error instanceof Error
-                                ? error.message
-                                : JSON.stringify(error)) as TranslatedString
-                            )
-                          }
-                        }
-                      }
-                    }}
-                  />
-                </div>
+              <div>
+                <input
+                  id="select-exchange"
+                  class="pure-button pure-button-primary content"
+                  disabled={update && !submitAccount}
+                  type="submit"
+                  value={update ? i18n.str`Confirm` : i18n.str`Update`}
+                  onClick={async (e) => {
+                    e.preventDefault();
+                    doUpdate()
+                  }}
+                />
               </div>
             </div>
-          </p>
-        </div>
+          </div>
+        </p>
       </div>
-    );
-  }
-  
\ No newline at end of file
+    </div>
+  );
+}
diff --git a/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx
index 084a5b643..d19c411f3 100644
--- a/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx
+++ b/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx
@@ -1,131 +1,181 @@
+import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
 import { ErrorType, HttpResponsePaginated, RequestError, notify, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
+import { useEffect, useRef, useState } from "preact/hooks";
+import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
 import { useAdminAccountAPI, useBusinessAccountDetails } from "../hooks/circuit.js";
-import { useState } from "preact/hooks";
-import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
-import { VNode,h ,Fragment} from "preact";
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
-import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
 
 export function UpdateAccountPassword({
-    account,
-    onClear,
-    onUpdateSuccess,
-    onLoadNotOk,
-  }: {
-    onLoadNotOk: <T>(
-      error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
-    ) => VNode;
-    onClear: () => void;
-    onUpdateSuccess: () => void;
-    account: string;
-  }): VNode {
-    const { i18n } = useTranslationContext();
-    const result = useBusinessAccountDetails(account);
-    const { changePassword } = useAdminAccountAPI();
-    const [password, setPassword] = useState<string | undefined>();
-    const [repeat, setRepeat] = useState<string | undefined>();
-  
-    if (!result.ok) {
-      if (result.loading || result.type === ErrorType.TIMEOUT) {
-        return onLoadNotOk(result);
-      }
-      if (result.status === HttpStatusCode.NotFound) {
-        return <div>account not found</div>;
-      }
+  account,
+  onCancel,
+  onUpdateSuccess,
+  onLoadNotOk,
+  focus,
+}: {
+  onLoadNotOk: <T>(
+    error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
+  ) => VNode;
+  onCancel: () => void;
+  focus?: boolean,
+  onUpdateSuccess: () => void;
+  account: string;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const result = useBusinessAccountDetails(account);
+  const { changePassword } = useAdminAccountAPI();
+  const [password, setPassword] = useState<string | undefined>();
+  const [repeat, setRepeat] = useState<string | undefined>();
+
+  const ref = useRef<HTMLInputElement>(null);
+  useEffect(() => {
+    if (focus) ref.current?.focus();
+  }, [focus]);
+
+  if (!result.ok) {
+    if (result.loading || result.type === ErrorType.TIMEOUT) {
       return onLoadNotOk(result);
     }
-  
-    const errors = undefinedIfEmpty({
-      password: !password ? i18n.str`required` : undefined,
-      repeat: !repeat
-        ? i18n.str`required`
-        : password !== repeat
-          ? i18n.str`password doesn't match`
-          : undefined,
-    });
-  
-    return (
-      <div>
-        <div>
-          <h1 class="nav welcome-text">
-            <i18n.Translate>Update password for {account}</i18n.Translate>
-          </h1>
-        </div>
-  
-        <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}>
-          <form class="pure-form">
-            <fieldset>
-              <label>{i18n.str`Password`}</label>
-              <input
-                type="password"
-                value={password ?? ""}
-                onChange={(e) => {
-                  setPassword(e.currentTarget.value);
-                }}
-              />
-              <ShowInputErrorLabel
-                message={errors?.password}
-                isDirty={password !== undefined}
-              />
-            </fieldset>
-            <fieldset>
-              <label>{i18n.str`Repeat password`}</label>
-              <input
-                type="password"
-                value={repeat ?? ""}
-                onChange={(e) => {
-                  setRepeat(e.currentTarget.value);
-                }}
-              />
-              <ShowInputErrorLabel
-                message={errors?.repeat}
-                isDirty={repeat !== undefined}
-              />
-            </fieldset>
-          </form>
-          <p>
-            <div style={{ display: "flex", justifyContent: "space-between" }}>
-              <div>
+    if (result.status === HttpStatusCode.NotFound) {
+      return <div>account not found</div>;
+    }
+    return onLoadNotOk(result);
+  }
+
+  const errors = undefinedIfEmpty({
+    password: !password ? i18n.str`required` : undefined,
+    repeat: !repeat
+      ? i18n.str`required`
+      : password !== repeat
+        ? i18n.str`password doesn't match`
+        : undefined,
+  });
+
+  async function doChangePassword() {
+    if (!!errors || !password) return;
+    try {
+      const r = await changePassword(account, {
+        new_password: password,
+      });
+      onUpdateSuccess();
+    } catch (error) {
+      if (error instanceof RequestError) {
+        notify(buildRequestErrorMessage(i18n, error.cause));
+      } else {
+        notifyError(i18n.str`Operation failed, please report`, (error instanceof Error
+          ? error.message
+          : JSON.stringify(error)) as TranslatedString)
+      }
+    }
+  }
+
+  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">
+        <h2 class="text-base font-semibold leading-7 text-gray-900">
+          <i18n.Translate>Update password for account "{account}"</i18n.Translate>
+        </h2>
+      </div>
+      <form
+        class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
+        autoCapitalize="none"
+        autoCorrect="off"
+        onSubmit={e => {
+          e.preventDefault()
+        }}
+      >
+        <div class="px-4 py-6 sm:p-8">
+          <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
+
+            <div class="sm:col-span-5">
+              <label
+                class="block text-sm font-medium leading-6 text-gray-900"
+                for="password"
+              >
+                {i18n.str`New password`}
+              </label>
+              <div class="mt-2">
                 <input
-                  class="pure-button"
-                  type="submit"
-                  value={i18n.str`Close`}
-                  onClick={async (e) => {
-                    e.preventDefault();
-                    onClear();
+                  ref={ref}
+                  type="password"
+                  class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                  name="password"
+                  id="password"
+                  data-error={!!errors?.password && password !== undefined}
+                  value={password ?? ""}
+                  onChange={(e) => {
+                    setPassword(e.currentTarget.value)
                   }}
+                  // placeholder=""
+                  autocomplete="off"
+                />
+                <ShowInputErrorLabel
+                  message={errors?.password}
+                  isDirty={password !== undefined}
                 />
               </div>
-              <div>
+              {/* <p class="mt-2 text-sm text-gray-500" >
+              <i18n.Translate>user </i18n.Translate>
+            </p> */}
+            </div>
+
+            <div class="sm:col-span-5">
+              <label
+                class="block text-sm font-medium leading-6 text-gray-900"
+                for="repeat"
+              >
+                {i18n.str`Type it again`}
+              </label>
+              <div class="mt-2">
                 <input
-                  id="select-exchange"
-                  class="pure-button pure-button-primary content"
-                  disabled={!!errors}
-                  type="submit"
-                  value={i18n.str`Confirm`}
-                  onClick={async (e) => {
-                    e.preventDefault();
-                    if (!!errors || !password) return;
-                    try {
-                      const r = await changePassword(account, {
-                        new_password: password,
-                      });
-                      onUpdateSuccess();
-                    } catch (error) {
-                      if (error instanceof RequestError) {
-                        notify(buildRequestErrorMessage(i18n, error.cause));
-                      } else {
-                        notifyError(i18n.str`Operation failed, please report`, (error instanceof Error
-                          ? error.message
-                          : JSON.stringify(error)) as TranslatedString)
-                      }
-                    }
+                  type="password"
+                  class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                  name="repeat"
+                  id="repeat"
+                  data-error={!!errors?.repeat && repeat !== undefined}
+                  value={repeat ?? ""}
+                  onChange={(e) => {
+                    setRepeat(e.currentTarget.value)
                   }}
+                  // placeholder=""
+                  autocomplete="off"
+                />
+                <ShowInputErrorLabel
+                  message={errors?.repeat}
+                  isDirty={repeat !== undefined}
                 />
               </div>
+              <p class="mt-2 text-sm text-gray-500" >
+                <i18n.Translate>repeat the same password</i18n.Translate>
+              </p>
             </div>
-          </p>
+
+
+
+          </div>
         </div>
-      </div>
-    );
-  }
\ No newline at end of file
+        <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
+          {onCancel ?
+            <button type="button" class="text-sm font-semibold leading-6 text-gray-900"
+              onClick={onCancel}
+            >
+              <i18n.Translate>Cancel</i18n.Translate>
+            </button>
+            : <div />
+          }
+          <button type="submit"
+            class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+            disabled={!!errors}
+            onClick={(e) => {
+              e.preventDefault()
+              doChangePassword()
+            }}
+          >
+            <i18n.Translate>Change</i18n.Translate>
+          </button>
+        </div>
+      </form>
+    </div>
+
+  );
+}
\ No newline at end of file
diff --git a/packages/demobank-ui/src/pages/admin/Account.tsx b/packages/demobank-ui/src/pages/admin/Account.tsx
index 8ab3e1323..90ddd611d 100644
--- a/packages/demobank-ui/src/pages/admin/Account.tsx
+++ b/packages/demobank-ui/src/pages/admin/Account.tsx
@@ -7,50 +7,30 @@ import { notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, h, VNode } from "preact";
 
 export function AdminAccount({ onRegister }: { onRegister: () => void }): VNode {
-    const { i18n } = useTranslationContext();
-    const r = useBackendContext();
-    const account = r.state.status === "loggedIn" ? r.state.username : "admin";
-    const result = useAccountDetails(account);
-  
-    if (!result.ok) {
-      return handleNotOkResult(i18n, onRegister)(result);
-    }
-    const { data } = result;
-    const balance = Amounts.parseOrThrow(data.balance.amount);
-    const debitThreshold = Amounts.parseOrThrow(result.data.debitThreshold);
-    const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
-    const limit = balanceIsDebit
-      ? Amounts.sub(debitThreshold, balance).amount
-      : Amounts.add(balance, debitThreshold).amount;
-    if (!balance) return <Fragment />;
-    return (
-      <Fragment>
-        <section id="assets">
-          <div class="asset-summary">
-            <h2>{i18n.str`Bank account balance`}</h2>
-            {!balance ? (
-              <div class="large-amount" style={{ color: "gray" }}>
-                Waiting server response...
-              </div>
-            ) : (
-              <div class="large-amount amount">
-                {balanceIsDebit ? <b>-</b> : null}
-                <span class="value">{`${Amounts.stringifyValue(balance)}`}</span>
-                &nbsp;
-                <span class="currency">{`${balance.currency}`}</span>
-              </div>
-            )}
-          </div>
-        </section>
-        <PaytoWireTransferForm
-          focus
-          limit={limit}
-          onSuccess={() => {
-            notifyInfo(i18n.str`Wire transfer created!`);
-          }}
-          onCancel={undefined}
-        />
-      </Fragment>
-    );
+  const { i18n } = useTranslationContext();
+  const r = useBackendContext();
+  const account = r.state.status === "loggedIn" ? r.state.username : "admin";
+  const result = useAccountDetails(account);
+
+  if (!result.ok) {
+    return handleNotOkResult(i18n, onRegister)(result);
   }
-  
\ No newline at end of file
+  const { data } = result;
+  const balance = Amounts.parseOrThrow(data.balance.amount);
+  const debitThreshold = Amounts.parseOrThrow(result.data.debitThreshold);
+  const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+  const limit = balanceIsDebit
+    ? Amounts.sub(debitThreshold, balance).amount
+    : Amounts.add(balance, debitThreshold).amount;
+  if (!balance) return <Fragment />;
+  return (
+    <PaytoWireTransferForm
+      title={i18n.str`Make a wire transfer`}
+      limit={limit}
+      onSuccess={() => {
+        notifyInfo(i18n.str`Wire transfer created!`);
+      }}
+      onCancel={undefined}
+    />
+  );
+}
diff --git a/packages/demobank-ui/src/pages/admin/AccountForm.tsx b/packages/demobank-ui/src/pages/admin/AccountForm.tsx
index 9ca0323a1..02df824a2 100644
--- a/packages/demobank-ui/src/pages/admin/AccountForm.tsx
+++ b/packages/demobank-ui/src/pages/admin/AccountForm.tsx
@@ -1,9 +1,9 @@
-import { VNode,h  } from "preact";
+import { ComponentChildren, VNode, h } from "preact";
 import { ShowInputErrorLabel } from "../../components/ShowInputErrorLabel.js";
 import { PartialButDefined, RecursivePartial, WithIntermediate, undefinedIfEmpty, validateIBAN } from "../../utils.js";
-import { useState } from "preact/hooks";
+import { useEffect, useRef, useState } from "preact/hooks";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { parsePaytoUri } from "@gnu-taler/taler-util";
+import { buildPayto, parsePaytoUri } from "@gnu-taler/taler-util";
 
 const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/;
 const EMAIL_REGEX =
@@ -19,201 +19,301 @@ const REGEX_JUST_NUMBERS_REGEX = /^\+[0-9 ]*$/;
  * @returns
  */
 export function AccountForm({
-    template,
-    purpose,
-    onChange,
-  }: {
-    template: SandboxBackend.Circuit.CircuitAccountData | undefined;
-    onChange: (a: SandboxBackend.Circuit.CircuitAccountData | undefined) => void;
-    purpose: "create" | "update" | "show";
-  }): VNode {
-    const initial = initializeFromTemplate(template);
-    const [form, setForm] = useState(initial);
-    const [errors, setErrors] = useState<
-      RecursivePartial<typeof initial> | undefined
-    >(undefined);
-    const { i18n } = useTranslationContext();
-  
-    function updateForm(newForm: typeof initial): void {
-      const parsed = !newForm.cashout_address
-        ? undefined
-        : parsePaytoUri(newForm.cashout_address);
-  
-      const errors = undefinedIfEmpty<RecursivePartial<typeof initial>>({
-        cashout_address: !newForm.cashout_address
+  template,
+  purpose,
+  onChange,
+  focus,
+  children,
+}: {
+  focus?: boolean,
+  children: ComponentChildren,
+  template: SandboxBackend.Circuit.CircuitAccountData | undefined;
+  onChange: (a: SandboxBackend.Circuit.CircuitAccountData | undefined) => void;
+  purpose: "create" | "update" | "show";
+}): VNode {
+  const initial = initializeFromTemplate(template);
+  const [form, setForm] = useState(initial);
+  const [errors, setErrors] = useState<
+    RecursivePartial<typeof initial> | undefined
+  >(undefined);
+  const { i18n } = useTranslationContext();
+  const ref = useRef<HTMLInputElement>(null);
+  useEffect(() => {
+    if (focus) ref.current?.focus();
+  }, [focus]);
+
+  function updateForm(newForm: typeof initial): void {
+
+    const parsed = !newForm.cashout_address
+      ? undefined
+      : buildPayto("iban", newForm.cashout_address, undefined);;
+
+    const errors = undefinedIfEmpty<RecursivePartial<typeof initial>>({
+      cashout_address: !newForm.cashout_address
+        ? i18n.str`required`
+        : !parsed
+          ? i18n.str`does not follow the pattern`
+          : !parsed.isKnown || parsed.targetType !== "iban"
+            ? i18n.str`only "IBAN" target are supported`
+            : !IBAN_REGEX.test(parsed.iban)
+              ? i18n.str`IBAN should have just uppercased letters and numbers`
+              : validateIBAN(parsed.iban, i18n),
+      contact_data: undefinedIfEmpty({
+        email: !newForm.contact_data?.email
           ? i18n.str`required`
-          : !parsed
-            ? i18n.str`does not follow the pattern`
-            : !parsed.isKnown || parsed.targetType !== "iban"
-              ? i18n.str`only "IBAN" target are supported`
-              : !IBAN_REGEX.test(parsed.iban)
-                ? i18n.str`IBAN should have just uppercased letters and numbers`
-                : validateIBAN(parsed.iban, i18n),
-        contact_data: undefinedIfEmpty({
-          email: !newForm.contact_data?.email
-            ? i18n.str`required`
-            : !EMAIL_REGEX.test(newForm.contact_data.email)
-              ? i18n.str`it should be an email`
+          : !EMAIL_REGEX.test(newForm.contact_data.email)
+            ? i18n.str`it should be an email`
+            : undefined,
+        phone: !newForm.contact_data?.phone
+          ? i18n.str`required`
+          : !newForm.contact_data.phone.startsWith("+")
+            ? i18n.str`should start with +`
+            : !REGEX_JUST_NUMBERS_REGEX.test(newForm.contact_data.phone)
+              ? i18n.str`phone number can't have other than numbers`
               : undefined,
-          phone: !newForm.contact_data?.phone
-            ? i18n.str`required`
-            : !newForm.contact_data.phone.startsWith("+")
-              ? i18n.str`should start with +`
-              : !REGEX_JUST_NUMBERS_REGEX.test(newForm.contact_data.phone)
-                ? i18n.str`phone number can't have other than numbers`
-                : undefined,
-        }),
-        iban: !newForm.iban
-          ? undefined //optional field
-          : !IBAN_REGEX.test(newForm.iban)
-            ? i18n.str`IBAN should have just uppercased letters and numbers`
-            : validateIBAN(newForm.iban, i18n),
-        name: !newForm.name ? i18n.str`required` : undefined,
-        username: !newForm.username ? i18n.str`required` : undefined,
-      });
-      setErrors(errors);
-      setForm(newForm);
-      onChange(errors === undefined ? (newForm as any) : undefined);
-    }
-  
-    return (
-      <form class="pure-form">
-        <fieldset>
-          <label for="username">
-            {i18n.str`Username`}
-            {purpose === "create" && <b style={{ color: "red" }}>*</b>}
-          </label>
-          <input
-            name="username"
-            type="text"
-            disabled={purpose !== "create"}
-            value={form.username}
-            onChange={(e) => {
-              form.username = e.currentTarget.value;
-              updateForm(structuredClone(form));
-            }}
-          />{" "}
-          <ShowInputErrorLabel
-            message={errors?.username}
-            isDirty={form.username !== undefined}
-          />
-        </fieldset>
-        <fieldset>
-          <label>
-            {i18n.str`Name`}
-            {purpose === "create" && <b style={{ color: "red" }}>*</b>}
-          </label>
-          <input
-            disabled={purpose !== "create"}
-            value={form.name ?? ""}
-            onChange={(e) => {
-              form.name = e.currentTarget.value;
-              updateForm(structuredClone(form));
-            }}
-          />
-          <ShowInputErrorLabel
-            message={errors?.name}
-            isDirty={form.name !== undefined}
-          />
-        </fieldset>
-        {purpose !== "create" && (
-          <fieldset>
-            <label>{i18n.str`Internal IBAN`}</label>
-            <input
-              disabled={true}
-              value={form.iban ?? ""}
-              onChange={(e) => {
-                form.iban = e.currentTarget.value;
-                updateForm(structuredClone(form));
-              }}
-            />
-            <ShowInputErrorLabel
-              message={errors?.iban}
-              isDirty={form.iban !== undefined}
-            />
-          </fieldset>
-        )}
-        <fieldset>
-          <label>
-            {i18n.str`Email`}
-            {purpose !== "show" && <b style={{ color: "red" }}>*</b>}
-          </label>
-          <input
-            disabled={purpose === "show"}
-            value={form.contact_data.email ?? ""}
-            onChange={(e) => {
-              form.contact_data.email = e.currentTarget.value;
-              updateForm(structuredClone(form));
-            }}
-          />
-          <ShowInputErrorLabel
-            message={errors?.contact_data?.email}
-            isDirty={form.contact_data.email !== undefined}
-          />
-        </fieldset>
-        <fieldset>
-          <label>
-            {i18n.str`Phone`}
-            {purpose !== "show" && <b style={{ color: "red" }}>*</b>}
-          </label>
-          <input
-            disabled={purpose === "show"}
-            value={form.contact_data.phone ?? ""}
-            onChange={(e) => {
-              form.contact_data.phone = e.currentTarget.value;
-              updateForm(structuredClone(form));
-            }}
-          />
-          <ShowInputErrorLabel
-            message={errors?.contact_data?.phone}
-            isDirty={form.contact_data?.phone !== undefined}
-          />
-        </fieldset>
-        <fieldset>
-          <label>
-            {i18n.str`Cashout address`}
-            {purpose !== "show" && <b style={{ color: "red" }}>*</b>}
-          </label>
-          <input
-            disabled={purpose === "show"}
-            value={(form.cashout_address ?? "").substring("payto://iban/".length)}
-            onChange={(e) => {
-              form.cashout_address = "payto://iban/" + e.currentTarget.value;
-              updateForm(structuredClone(form));
-            }}
-          />
-          <ShowInputErrorLabel
-            message={errors?.cashout_address}
-            isDirty={form.cashout_address !== undefined}
-          />
-        </fieldset>
-      </form>
-    );
+      }),
+      // iban: !newForm.iban
+      //   ? undefined //optional field
+      //   : !IBAN_REGEX.test(newForm.iban)
+      //     ? i18n.str`IBAN should have just uppercased letters and numbers`
+      //     : validateIBAN(newForm.iban, i18n),
+      name: !newForm.name ? i18n.str`required` : undefined,
+      username: !newForm.username ? i18n.str`required` : undefined,
+    });
+    setErrors(errors);
+    setForm(newForm);
+    onChange(errors === undefined ? (newForm as any) : undefined);
   }
-  
-  function initializeFromTemplate(
-    account: SandboxBackend.Circuit.CircuitAccountData | undefined,
-  ): WithIntermediate<SandboxBackend.Circuit.CircuitAccountData> {
-    const emptyAccount = {
-      cashout_address: undefined,
-      iban: undefined,
-      name: undefined,
-      username: undefined,
-      contact_data: undefined,
-    };
-    const emptyContact = {
-      email: undefined,
-      phone: undefined,
-    };
-  
-    const initial: PartialButDefined<SandboxBackend.Circuit.CircuitAccountData> =
-      structuredClone(account) ?? emptyAccount;
-    if (typeof initial.contact_data === "undefined") {
-      initial.contact_data = emptyContact;
-    }
-    initial.contact_data.email;
-    return initial as any;
+
+  return (
+    <form
+      class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
+      autoCapitalize="none"
+      autoCorrect="off"
+      onSubmit={e => {
+        e.preventDefault()
+      }}
+    >
+      <div class="px-4 py-6 sm:p-8">
+        <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
+
+
+          <div class="sm:col-span-5">
+            <label
+              class="block text-sm font-medium leading-6 text-gray-900"
+              for="username"
+            >
+              {i18n.str`Username`}
+              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
+            </label>
+            <div class="mt-2">
+              <input
+                ref={ref}
+                type="text"
+                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                name="username"
+                id="username"
+                data-error={!!errors?.username && form.username !== undefined}
+                disabled={purpose !== "create"}
+                value={form.username ?? ""}
+                onChange={(e) => {
+                  form.username = e.currentTarget.value;
+                  updateForm(structuredClone(form));
+                }}
+                // placeholder=""
+                autocomplete="off"
+              />
+              <ShowInputErrorLabel
+                message={errors?.username}
+                isDirty={form.username !== undefined}
+              />
+            </div>
+            <p class="mt-2 text-sm text-gray-500" >
+              <i18n.Translate>account identification in the bank</i18n.Translate>
+            </p>
+          </div>
+
+          <div class="sm:col-span-5">
+            <label
+              class="block text-sm font-medium leading-6 text-gray-900"
+              for="name"
+            >
+              {i18n.str`Name`}
+              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
+            </label>
+            <div class="mt-2">
+              <input
+                type="text"
+                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                name="name"
+                data-error={!!errors?.name && form.name !== undefined}
+                id="name"
+                disabled={purpose !== "create"}
+                value={form.name ?? ""}
+                onChange={(e) => {
+                  form.name = e.currentTarget.value;
+                  updateForm(structuredClone(form));
+                }}
+                // placeholder=""
+                autocomplete="off"
+              />
+              <ShowInputErrorLabel
+                message={errors?.name}
+                isDirty={form.name !== undefined}
+              />
+            </div>
+            <p class="mt-2 text-sm text-gray-500" >
+              <i18n.Translate>name of the person owner the account</i18n.Translate>
+            </p>
+          </div>
+
+
+          {purpose !== "create" && (<div class="sm:col-span-5">
+            <label
+              class="block text-sm font-medium leading-6 text-gray-900"
+              for="internal-iban"
+            >
+              {i18n.str`Internal IBAN`}
+            </label>
+            <div class="mt-2">
+              <input
+                type="text"
+                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                name="internal-iban"
+                id="internal-iban"
+                disabled={true}
+                value={form.iban ?? ""}
+              />
+            </div>
+            <p class="mt-2 text-sm text-gray-500" >
+              <i18n.Translate>international bank account number</i18n.Translate>
+            </p>
+          </div>)}
+
+          <div class="sm:col-span-5">
+            <label
+              class="block text-sm font-medium leading-6 text-gray-900"
+              for="email"
+            >
+              {i18n.str`Email`}
+              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
+            </label>
+            <div class="mt-2">
+              <input
+                type="email"
+                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                name="email"
+                id="email"
+                data-error={!!errors?.contact_data?.email && form.contact_data.email !== undefined}
+                disabled={purpose !== "create"}
+                value={form.contact_data.email ?? ""}
+                onChange={(e) => {
+                  form.contact_data.email = e.currentTarget.value;
+                  updateForm(structuredClone(form));
+                }}
+                autocomplete="off"
+              />
+              <ShowInputErrorLabel
+                message={errors?.contact_data?.email}
+                isDirty={form.contact_data.email !== undefined}
+              />
+            </div>
+          </div>
+
+          <div class="sm:col-span-5">
+            <label
+              class="block text-sm font-medium leading-6 text-gray-900"
+              for="phone"
+            >
+              {i18n.str`Phone`}
+              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
+            </label>
+            <div class="mt-2">
+              <input
+                type="text"
+                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                name="phone"
+                id="phone"
+                disabled={purpose !== "create"}
+                value={form.contact_data.phone ?? ""}
+                data-error={!!errors?.contact_data?.phone && form.contact_data.phone !== undefined}
+                onChange={(e) => {
+                  form.contact_data.phone = e.currentTarget.value;
+                  updateForm(structuredClone(form));
+                }}
+                // placeholder=""
+                autocomplete="off"
+              />
+              <ShowInputErrorLabel
+                message={errors?.contact_data?.phone}
+                isDirty={form.contact_data.phone !== undefined}
+              />
+            </div>
+          </div>
+
+
+          <div class="sm:col-span-5">
+            <label
+              class="block text-sm font-medium leading-6 text-gray-900"
+              for="cashout"
+            >
+              {i18n.str`Cashout IBAN`}
+              {purpose !== "show" && <b style={{ color: "red" }}> *</b>}
+            </label>
+            <div class="mt-2">
+              <input
+                type="text"
+                data-error={!!errors?.cashout_address && form.cashout_address !== undefined}
+                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                name="cashout"
+                id="cashout"
+                disabled={purpose === "show"}
+                value={form.cashout_address ?? ""}
+                onChange={(e) => {
+                  form.cashout_address = e.currentTarget.value;
+                  updateForm(structuredClone(form));
+                }}
+                autocomplete="off"
+              />
+              <ShowInputErrorLabel
+                message={errors?.cashout_address}
+                isDirty={form.cashout_address !== undefined}
+              />
+            </div>
+            <p class="mt-2 text-sm text-gray-500" >
+              <i18n.Translate>account number where the money is going to be sent when doing cashouts</i18n.Translate>
+            </p>
+          </div>
+
+        </div>
+      </div>
+      {children}
+    </form>
+  );
+}
+
+function initializeFromTemplate(
+  account: SandboxBackend.Circuit.CircuitAccountData | undefined,
+): WithIntermediate<SandboxBackend.Circuit.CircuitAccountData> {
+  const emptyAccount = {
+    cashout_address: undefined,
+    iban: undefined,
+    name: undefined,
+    username: undefined,
+    contact_data: undefined,
+  };
+  const emptyContact = {
+    email: undefined,
+    phone: undefined,
+  };
+
+  const initial: PartialButDefined<SandboxBackend.Circuit.CircuitAccountData> =
+    structuredClone(account) ?? emptyAccount;
+  if (typeof initial.contact_data === "undefined") {
+    initial.contact_data = emptyContact;
   }
-  
-  
-  
\ No newline at end of file
+  initial.contact_data.email;
+  return initial as any;
+}
+
+
diff --git a/packages/demobank-ui/src/pages/admin/AccountList.tsx b/packages/demobank-ui/src/pages/admin/AccountList.tsx
index 56b15818b..56d9c45f9 100644
--- a/packages/demobank-ui/src/pages/admin/AccountList.tsx
+++ b/packages/demobank-ui/src/pages/admin/AccountList.tsx
@@ -9,10 +9,10 @@ interface Props {
     onAction: (type: AccountAction, account: string) => void;
     account: string | undefined;
     onRegister: () => void;
-
+    onCreateAccount: () => void;
 }
 
-export function AccountList({ account, onAction, onRegister }: Props): VNode {
+export function AccountList({ account, onAction, onCreateAccount, onRegister }: Props): VNode {
     const result = useBusinessAccounts({ account });
     const { i18n } = useTranslationContext();
 
@@ -22,48 +22,60 @@ export function AccountList({ account, onAction, onRegister }: Props): VNode {
     }
 
     const { customers } = result.data;
-    return <section
-        id="main"
-        style={{ width: 600, marginLeft: "auto", marginRight: "auto" }}
-    >
-        {!customers.length ? (
-            <div></div>
-        ) : (
-            <article>
-                <h2>{i18n.str`Accounts:`}</h2>
-                <div class="results">
-                    <table class="pure-table pure-table-striped">
-                        <thead>
-                            <tr>
-                                <th>{i18n.str`Username`}</th>
-                                <th>{i18n.str`Name`}</th>
-                                <th>{i18n.str`Balance`}</th>
-                                <th>{i18n.str`Actions`}</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                            {customers.map((item, idx) => {
-                                const balance = !item.balance
-                                    ? undefined
-                                    : Amounts.parse(item.balance.amount);
-                                const balanceIsDebit =
-                                    item.balance &&
-                                    item.balance.credit_debit_indicator == "debit";
-                                return (
-                                    <tr key={idx}>
-                                        <td>
-                                            <a
-                                                href="#"
-                                                onClick={(e) => {
-                                                    e.preventDefault();
-                                                    onAction("show-details", item.username)
-                                                }}
-                                            >
-                                                {item.username}
-                                            </a>
+    return <div class="px-4 sm:px-6 lg:px-8">
+        <div class="sm:flex sm:items-center">
+            <div class="sm:flex-auto">
+                <h1 class="text-base font-semibold leading-6 text-gray-900">
+                    <i18n.Translate>Accounts</i18n.Translate>
+                </h1>
+                <p class="mt-2 text-sm text-gray-700">
+                    <i18n.Translate>A list of all business account in the bank.</i18n.Translate>
+                </p>
+            </div>
+            <div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
+                <button type="button" class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+                    onClick={(e) => {
+                        e.preventDefault()
+                        onCreateAccount()
+                    }}>
+                    <i18n.Translate>Create account</i18n.Translate>
+                </button>
+            </div>
+        </div>
+        <div class="mt-8 flow-root">
+            <div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
+                <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
+                    {!customers.length ? (
+                        <div></div>
+                    ) : (
+                        <table class="min-w-full divide-y divide-gray-300">
+                            <thead>
+                                <tr>
+                                    <th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0">{i18n.str`Username`}</th>
+                                    <th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">{i18n.str`Name`}</th>
+                                    <th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">{i18n.str`Balance`}</th>
+                                    <th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-0">
+                                        <span class="sr-only">{i18n.str`Actions`}</span>
+                                    </th>
+                                </tr>
+                            </thead>
+                            <tbody class="divide-y divide-gray-200">
+                                {customers.map((item, idx) => {
+                                    const balance = !item.balance
+                                        ? undefined
+                                        : Amounts.parse(item.balance.amount);
+                                    const balanceIsDebit =
+                                        item.balance &&
+                                        item.balance.credit_debit_indicator == "debit";
+
+                                    return <tr key={idx}>
+                                        <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-0">
+                                            {item.username}
                                         </td>
-                                        <td>{item.name}</td>
-                                        <td>
+                                        <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
+                                            {item.name}
+                                        </td>
+                                        <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
                                             {!balance ? (
                                                 i18n.str`unknown`
                                             ) : (
@@ -77,9 +89,8 @@ export function AccountList({ account, onAction, onRegister }: Props): VNode {
                                                 </span>
                                             )}
                                         </td>
-                                        <td>
-                                            <a
-                                                href="#"
+                                        <td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
+                                            <a href="#" class="text-indigo-600 hover:text-indigo-900"
                                                 onClick={(e) => {
                                                     e.preventDefault();
                                                     onAction("update-password", item.username)
@@ -87,34 +98,71 @@ export function AccountList({ account, onAction, onRegister }: Props): VNode {
                                             >
                                                 change password
                                             </a>
-                                            &nbsp;
-                                            <a
-                                                href="#"
-                                                onClick={(e) => {
-                                                    e.preventDefault();
-                                                    onAction("show-cashout", item.username)
-                                                }}
+                                            <br/>
+                                            <a href="#" class="text-indigo-600 hover:text-indigo-900" onClick={(e) => {
+                                                e.preventDefault();
+                                                onAction("show-cashout", item.username)
+                                            }}
                                             >
                                                 cashouts
                                             </a>
-                                            &nbsp;
-                                            <a
-                                                href="#"
-                                                onClick={(e) => {
-                                                    e.preventDefault();
-                                                    onAction("remove-account", item.username)
-                                                }}
+                                            <br/>
+                                            <a href="#" class="text-indigo-600 hover:text-indigo-900" onClick={(e) => {
+                                                e.preventDefault();
+                                                onAction("remove-account", item.username)
+                                            }}
                                             >
                                                 remove
                                             </a>
                                         </td>
                                     </tr>
-                                );
-                            })}
-                        </tbody>
-                    </table>
+                                })}
+
+                                {/* <!-- More people... --> */}
+                            </tbody>
+                        </table>
+                    )}
                 </div>
-            </article>
-        )}
-    </section>
+            </div>
+        </div>
+    </div>
+
+    //     return <section
+    //         id="main"
+    //         style={{ width: 600, marginLeft: "auto", marginRight: "auto" }}
+    //     >
+    //             <article>
+    //                 <h2>{i18n.str`Accounts:`}</h2>
+    //                 <div class="results">
+    //                     <table class="pure-table pure-table-striped">
+    //                         <tbody>
+    //                                 return (
+    //                                     <tr key={idx}>
+    //                                         <td>
+    //                                             <a
+    //                                                 href="#"
+    //                                                 onClick={(e) => {
+    //                                                     e.preventDefault();
+    //                                                     onAction("show-details", item.username)
+    //                                                 }}
+    //                                             >
+    // {item.username}
+    //                                             </a>
+    //                                         </td>
+    //                                         <td>{item.name}</td>
+    //                                         <td>
+    //                                             
+    //                                         </td>
+    //                                         <td>
+
+    //                                         </td>
+    //                                     </tr>
+    //                                 );
+    //                             })}
+    //                         </tbody>
+    //                     </table>
+    //                 </div>
+    //             </article>
+    //         )}
+    //     </section>
 }
\ No newline at end of file
diff --git a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
index 90835d52b..2146fc6f0 100644
--- a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
@@ -8,100 +8,94 @@ import { getRandomPassword } from "../rnd.js";
 import { AccountForm } from "./AccountForm.js";
 
 export function CreateNewAccount({
-    onClose,
-    onCreateSuccess,
+  onCancel,
+  onCreateSuccess,
 }: {
-    onClose: () => void;
-    onCreateSuccess: (password: string) => void;
+  onCancel: () => void;
+  onCreateSuccess: (password: string) => void;
 }): VNode {
-    const { i18n } = useTranslationContext();
-    const { createAccount } = useAdminAccountAPI();
-    const [submitAccount, setSubmitAccount] = useState<
-        SandboxBackend.Circuit.CircuitAccountData | undefined
-    >();
-    return (
-        <div>
-            <div>
-                <h1 class="nav welcome-text">
-                    <i18n.Translate>New account</i18n.Translate>
-                </h1>
-            </div>
+  const { i18n } = useTranslationContext();
+  const { createAccount } = useAdminAccountAPI();
+  const [submitAccount, setSubmitAccount] = useState<
+    SandboxBackend.Circuit.CircuitAccountData | undefined
+  >();
 
-            <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}>
-                <AccountForm
-                    template={undefined}
-                    purpose="create"
-                    onChange={(a) => {
-                        setSubmitAccount(a);
-                    }}
-                />
+  async function doCreate() {
+    if (!submitAccount) return;
+    try {
+      const account: SandboxBackend.Circuit.CircuitAccountRequest =
+      {
+        cashout_address: submitAccount.cashout_address,
+        contact_data: submitAccount.contact_data,
+        internal_iban: submitAccount.iban,
+        name: submitAccount.name,
+        username: submitAccount.username,
+        password: getRandomPassword(),
+      };
 
-                <p>
-                    <div style={{ display: "flex", justifyContent: "space-between" }}>
-                        <div>
-                            <input
-                                class="pure-button"
-                                type="submit"
-                                value={i18n.str`Close`}
-                                onClick={async (e) => {
-                                    e.preventDefault();
-                                    onClose();
-                                }}
-                            />
-                        </div>
-                        <div>
-                            <input
-                                id="select-exchange"
-                                class="pure-button pure-button-primary content"
-                                disabled={!submitAccount}
-                                type="submit"
-                                value={i18n.str`Confirm`}
-                                onClick={async (e) => {
-                                    e.preventDefault();
+      await createAccount(account);
+      onCreateSuccess(account.password);
+    } catch (error) {
+      if (error instanceof RequestError) {
+        notify(
+          buildRequestErrorMessage(i18n, error.cause, {
+            onClientError: (status) =>
+              status === HttpStatusCode.Forbidden
+                ? i18n.str`The rights to perform the operation are not sufficient`
+                : status === HttpStatusCode.BadRequest
+                  ? i18n.str`Server replied that input data was invalid`
+                  : status === HttpStatusCode.Conflict
+                    ? i18n.str`At least one registration detail was not available`
+                    : undefined,
+          }),
+        );
+      } else {
+        notifyError(
+          i18n.str`Operation failed, please report`,
+          (error instanceof Error
+            ? error.message
+            : JSON.stringify(error)) as TranslatedString
+        )
+      }
+    }
+  }
 
-                                    if (!submitAccount) return;
-                                    try {
-                                        const account: SandboxBackend.Circuit.CircuitAccountRequest =
-                                        {
-                                            cashout_address: submitAccount.cashout_address,
-                                            contact_data: submitAccount.contact_data,
-                                            internal_iban: submitAccount.iban,
-                                            name: submitAccount.name,
-                                            username: submitAccount.username,
-                                            password: getRandomPassword(),
-                                        };
-
-                                        await createAccount(account);
-                                        onCreateSuccess(account.password);
-                                    } catch (error) {
-                                        if (error instanceof RequestError) {
-                                            notify(
-                                                buildRequestErrorMessage(i18n, error.cause, {
-                                                    onClientError: (status) =>
-                                                        status === HttpStatusCode.Forbidden
-                                                            ? i18n.str`The rights to perform the operation are not sufficient`
-                                                            : status === HttpStatusCode.BadRequest
-                                                                ? i18n.str`Input data was invalid`
-                                                                : status === HttpStatusCode.Conflict
-                                                                    ? i18n.str`At least one registration detail was not available`
-                                                                    : undefined,
-                                                }),
-                                            );
-                                        } else {
-                                            notifyError(
-                                                i18n.str`Operation failed, please report`,
-                                                (error instanceof Error
-                                                    ? error.message
-                                                    : JSON.stringify(error)) as TranslatedString
-                                            )
-                                        }
-                                    }
-                                }}
-                            />
-                        </div>
-                    </div>
-                </p>
-            </div>
+  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">
+        <h2 class="text-base font-semibold leading-7 text-gray-900">
+          <i18n.Translate>New business account</i18n.Translate>
+        </h2>
+      </div>
+      <AccountForm
+        template={undefined}
+        purpose="create"
+        onChange={(a) => {
+          setSubmitAccount(a);
+        }}
+      >
+        <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
+          {onCancel ?
+            <button type="button" class="text-sm font-semibold leading-6 text-gray-900"
+              onClick={onCancel}
+            >
+              <i18n.Translate>Cancel</i18n.Translate>
+            </button>
+            : <div />
+          }
+          <button type="submit"
+            class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+            disabled={!submitAccount}
+            onClick={(e) => {
+              e.preventDefault()
+              doCreate()
+            }}
+          >
+            <i18n.Translate>Create</i18n.Translate>
+          </button>
         </div>
-    );
+
+      </AccountForm>
+    </div>
+  );
 }
diff --git a/packages/demobank-ui/src/pages/admin/Home.tsx b/packages/demobank-ui/src/pages/admin/Home.tsx
index e1ec6cfe0..f7d4e426e 100644
--- a/packages/demobank-ui/src/pages/admin/Home.tsx
+++ b/packages/demobank-ui/src/pages/admin/Home.tsx
@@ -17,17 +17,20 @@ import { RemoveAccount } from "./RemoveAccount.js";
 interface Props {
   onRegister: () => void;
 }
-export type AccountAction = "show-details" | 
-  "show-cashout" | 
-  "update-password" | 
-  "remove-account" | 
+export type AccountAction = "show-details" |
+  "show-cashout" |
+  "update-password" |
+  "remove-account" |
   "show-cashouts-details";
 
 export function AdminHome({ onRegister }: Props): VNode {
   const [action, setAction] = useState<{
     type: AccountAction,
     account: string
-  }>()
+  } | undefined>({
+    type:"remove-account",
+    account:"gnunet-at-sandbox"
+  })
 
   const [createAccount, setCreateAccount] = useState(false);
 
@@ -78,7 +81,7 @@ export function AdminHome({ onRegister }: Props): VNode {
           notifyInfo(i18n.str`Password changed`);
           setAction(undefined);
         }}
-        onClear={() => {
+        onCancel={() => {
           setAction(undefined);
         }}
       />
@@ -89,7 +92,7 @@ export function AdminHome({ onRegister }: Props): VNode {
           notifyInfo(i18n.str`Account removed`);
           setAction(undefined);
         }}
-        onClear={() => {
+        onCancel={() => {
           setAction(undefined);
         }}
       />
@@ -116,7 +119,7 @@ export function AdminHome({ onRegister }: Props): VNode {
   if (createAccount) {
     return (
       <CreateNewAccount
-        onClose={() => setCreateAccount(false)}
+        onCancel={() => setCreateAccount(false)}
         onCreateSuccess={(password) => {
           notifyInfo(
             i18n.str`Account created with password "${password}". The user must change the password on the next login.`,
@@ -129,34 +132,18 @@ export function AdminHome({ onRegister }: Props): VNode {
 
   return (
     <Fragment>
-      <div>
-        <h1 class="nav welcome-text">
-          <i18n.Translate>Admin panel</i18n.Translate>
-        </h1>
-      </div>
 
-      <p>
-        <div style={{ display: "flex", justifyContent: "space-between" }}>
-          <div></div>
-          <div>
-            <input
-              class="pure-button pure-button-primary content"
-              type="submit"
-              value={i18n.str`Create account`}
-              onClick={async (e) => {
-                e.preventDefault();
-
-                setCreateAccount(true);
-              }}
-            />
-          </div>
-        </div>
-      </p>
+      <AccountList
+        onCreateAccount={() => {
+          setCreateAccount(true);
+        }}
+        account={undefined}
+        onAction={(type, account) => setAction({ account, type })}
+        onRegister={onRegister}
+      />
 
       <AdminAccount onRegister={onRegister} />
 
-      <AccountList account={undefined} onAction={(type,account) => setAction({account, type})} onRegister={onRegister}/>
-
     </Fragment>
   );
 }
\ No newline at end of file
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index 2900db9d2..050f1fb8a 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -1,112 +1,218 @@
 import { ErrorType, HttpResponsePaginated, RequestError, notify, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { VNode,h,Fragment } from "preact";
+import { VNode, h, Fragment } from "preact";
 import { useAccountDetails } from "../../hooks/access.js";
 import { useAdminAccountAPI } from "../../hooks/circuit.js";
 import { Amounts, HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
-import { buildRequestErrorMessage } from "../../utils.js";
+import { buildRequestErrorMessage, undefinedIfEmpty } from "../../utils.js";
+import { useEffect, useRef, useState } from "preact/hooks";
+import { ShowInputErrorLabel } from "../../components/ShowInputErrorLabel.js";
 
 export function RemoveAccount({
-    account,
-    onClear,
-    onUpdateSuccess,
-    onLoadNotOk,
-  }: {
-    onLoadNotOk: <T>(
-      error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
-    ) => VNode;
-    onClear: () => void;
-    onUpdateSuccess: () => void;
-    account: string;
-  }): VNode {
-    const { i18n } = useTranslationContext();
-    const result = useAccountDetails(account);
-    const { deleteAccount } = useAdminAccountAPI();
-  
-    if (!result.ok) {
-      if (result.loading || result.type === ErrorType.TIMEOUT) {
-        return onLoadNotOk(result);
-      }
-      if (result.status === HttpStatusCode.NotFound) {
-        return <div>account not found</div>;
-      }
+  account,
+  onCancel,
+  onUpdateSuccess,
+  onLoadNotOk,
+  focus,
+}: {
+  onLoadNotOk: <T>(
+    error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
+  ) => VNode;
+  focus?: boolean;
+  onCancel: () => void;
+  onUpdateSuccess: () => void;
+  account: string;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const result = useAccountDetails(account);
+  const [accountName, setAccountName] = useState<string | undefined>()
+  const { deleteAccount } = useAdminAccountAPI();
+
+  if (!result.ok) {
+    if (result.loading || result.type === ErrorType.TIMEOUT) {
       return onLoadNotOk(result);
     }
-  
-    const balance = Amounts.parse(result.data.balance.amount);
-    if (!balance) {
-      return <div>there was an error reading the balance</div>;
+    if (result.status === HttpStatusCode.NotFound) {
+      return <div>account not found</div>;
     }
-    const isBalanceEmpty = Amounts.isZero(balance);
-    return (
-      <div>
-        <div>
-          <h1 class="nav welcome-text">
-            <i18n.Translate>Remove account: {account}</i18n.Translate>
-          </h1>
+    return onLoadNotOk(result);
+  }
+  const ref = useRef<HTMLInputElement>(null);
+  useEffect(() => {
+    if (focus) ref.current?.focus();
+  }, [focus]);
+
+  const balance = Amounts.parse(result.data.balance.amount);
+  if (!balance) {
+    return <div>there was an error reading the balance</div>;
+  }
+  const isBalanceEmpty = Amounts.isZero(balance);
+  if (!isBalanceEmpty) {
+    return <div>
+      <div class="rounded-md bg-yellow-50 p-4">
+        <div class="flex">
+          <div class="flex-shrink-0">
+            <svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
+            </svg>
+          </div>
+          <div class="ml-3">
+            <h3 class="text-sm font-medium text-yellow-800">
+              <i18n.Translate>Can't delete the account</i18n.Translate>
+            </h3>
+            <div class="mt-2 text-sm text-yellow-700">
+              <p>
+                <i18n.Translate>The account can be delete while still holding some balance. First make sure that the owner make a complete cashout.</i18n.Translate>
+              </p>
+            </div>
+          </div>
+
         </div>
-        {/* {FXME: SHOW WARNING} */}
-        {/* {!isBalanceEmpty && (
-          <ErrorBannerFloat
-            error={{
-              title: i18n.str`Can't delete the account`,
-              description: i18n.str`Balance is not empty`,
-            }}
-            onClear={() => saveError(undefined)}
-          />
-        )} */}
-  
-        <p>
-          <div style={{ display: "flex", justifyContent: "space-between" }}>
-            <div>
-              <input
-                class="pure-button"
-                type="submit"
-                value={i18n.str`Cancel`}
-                onClick={async (e) => {
-                  e.preventDefault();
-                  onClear();
-                }}
-              />
+      </div>
+      <div class="mt-2 flex justify-end">
+        <button type="button" class="rounded-md ring-1 ring-gray-400 bg-white px-3 py-2 text-sm font-semibold shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
+          onClick={() => {
+            onCancel()
+          }}>
+          <i18n.Translate>Go back</i18n.Translate>
+        </button>
+      </div>
+    </div>
+  }
+
+  async function doRemove() {
+    try {
+      const r = await deleteAccount(account);
+      onUpdateSuccess();
+    } catch (error) {
+      if (error instanceof RequestError) {
+        notify(
+          buildRequestErrorMessage(i18n, error.cause, {
+            onClientError: (status) =>
+              status === HttpStatusCode.Forbidden
+                ? i18n.str`The administrator specified a institutional username`
+                : status === HttpStatusCode.NotFound
+                  ? i18n.str`The username was not found`
+                  : status === HttpStatusCode.PreconditionFailed
+                    ? i18n.str`Balance was not zero`
+                    : undefined,
+          }),
+        );
+      } else {
+        notifyError(i18n.str`Operation failed, please report`,
+          (error instanceof Error
+            ? error.message
+            : JSON.stringify(error)) as TranslatedString);
+      }
+    }
+  }
+
+  const errors = undefinedIfEmpty({
+    accountName: !accountName
+      ? i18n.str`required`
+      : account !== accountName
+        ? i18n.str`name doesn't match`
+        : undefined,
+  });
+
+
+  return (
+    <div>
+      <div class="rounded-md bg-yellow-50 p-4">
+        <div class="flex">
+          <div class="flex-shrink-0">
+            <svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
+            </svg>
+          </div>
+          <div class="ml-3">
+            <h3 class="text-sm font-bold text-yellow-800">
+              <i18n.Translate>You are going to remove the account</i18n.Translate>
+            </h3>
+            <div class="mt-2 text-sm text-yellow-700">
+              <p>
+                <i18n.Translate>This step can't be undone.</i18n.Translate>
+              </p>
             </div>
-            <div>
-              <input
-                id="select-exchange"
-                class="pure-button pure-button-primary content"
-                disabled={!isBalanceEmpty}
-                type="submit"
-                value={i18n.str`Confirm`}
-                onClick={async (e) => {
-                  e.preventDefault();
-                  try {
-                    const r = await deleteAccount(account);
-                    onUpdateSuccess();
-                  } catch (error) {
-                    if (error instanceof RequestError) {
-                      notify(
-                        buildRequestErrorMessage(i18n, error.cause, {
-                          onClientError: (status) =>
-                            status === HttpStatusCode.Forbidden
-                              ? i18n.str`The administrator specified a institutional username`
-                              : status === HttpStatusCode.NotFound
-                                ? i18n.str`The username was not found`
-                                : status === HttpStatusCode.PreconditionFailed
-                                  ? i18n.str`Balance was not zero`
-                                  : undefined,
-                        }),
-                      );
-                    } else {
-                      notifyError(i18n.str`Operation failed, please report`,
-                        (error instanceof Error
-                            ? error.message
-                            : JSON.stringify(error)) as TranslatedString);
-                    }
-                  }
-                }}
-              />
+          </div>
+
+        </div>
+      </div>
+
+      <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">
+          <h2 class="text-base font-semibold leading-7 text-gray-900">
+            <i18n.Translate>Deleting account "{account}"</i18n.Translate>
+          </h2>
+        </div>
+        <form
+          class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
+          autoCapitalize="none"
+          autoCorrect="off"
+          onSubmit={e => {
+            e.preventDefault()
+          }}
+        >
+          <div class="px-4 py-6 sm:p-8">
+            <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
+
+              <div class="sm:col-span-5">
+                <label
+                  class="block text-sm font-medium leading-6 text-gray-900"
+                  for="password"
+                >
+                  {i18n.str`Verification`}
+                </label>
+                <div class="mt-2">
+                  <input
+                    ref={ref}
+                    type="text"
+                    class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                    name="password"
+                    id="password"
+                    data-error={!!errors?.accountName && accountName !== undefined}
+                    value={accountName ?? ""}
+                    onChange={(e) => {
+                      setAccountName(e.currentTarget.value)
+                    }}
+                    placeholder={account}
+                    autocomplete="off"
+                  />
+                  <ShowInputErrorLabel
+                    message={errors?.accountName}
+                    isDirty={accountName !== undefined}
+                  />
+                </div>
+                <p class="mt-2 text-sm text-gray-500" >
+                  <i18n.Translate>enter the account name that is going to be deleted</i18n.Translate>
+                </p>
+              </div>
+
+
+
             </div>
           </div>
-        </p>
+          <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
+            {onCancel ?
+              <button type="button" class="text-sm font-semibold leading-6 text-gray-900"
+                onClick={onCancel}
+              >
+                <i18n.Translate>Cancel</i18n.Translate>
+              </button>
+              : <div />
+            }
+            <button type="submit"
+              class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
+              disabled={!!errors}
+              onClick={(e) => {
+                e.preventDefault()
+                doRemove()
+              }}
+            >
+              <i18n.Translate>Delete</i18n.Translate>
+            </button>
+          </div>
+        </form>
       </div>
-    );
-  }
-  
\ No newline at end of file
+    </div>
+  );
+}
diff --git a/packages/demobank-ui/src/pages/business/Home.tsx b/packages/demobank-ui/src/pages/business/Home.tsx
index 8beea640a..318a4cfda 100644
--- a/packages/demobank-ui/src/pages/business/Home.tsx
+++ b/packages/demobank-ui/src/pages/business/Home.tsx
@@ -109,7 +109,7 @@ export function BusinessAccount({
           notifyInfo(i18n.str`Password changed`);
           setUpdatePassword(false);
         }}
-        onClear={() => {
+        onCancel={() => {
           setUpdatePassword(false);
         }}
       />
-- 
cgit v1.2.3


From 56a6f47c7daae088c2017c0d9781ddcf7cee175b Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Thu, 21 Sep 2023 15:44:17 -0300
Subject: more ui

---
 packages/demobank-ui/src/components/Routing.tsx    |  12 +-
 packages/demobank-ui/src/hooks/settings.ts         |   8 +-
 .../demobank-ui/src/pages/AccountPage/views.tsx    |  50 ++++++
 packages/demobank-ui/src/pages/BankFrame.tsx       | 133 ++++++++-------
 packages/demobank-ui/src/pages/HomePage.tsx        |  20 +--
 packages/demobank-ui/src/pages/PaymentOptions.tsx  | 137 +++++++--------
 packages/demobank-ui/src/pages/QrCodeSection.tsx   | 106 ++++++++++++
 .../demobank-ui/src/pages/WalletWithdrawForm.tsx   | 183 +++++++++++----------
 .../demobank-ui/src/pages/WithdrawalQRCode.tsx     | 159 +++++++++++++++---
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  |   2 +-
 10 files changed, 553 insertions(+), 257 deletions(-)

(limited to 'packages/demobank-ui/src/pages/admin/RemoveAccount.tsx')

diff --git a/packages/demobank-ui/src/components/Routing.tsx b/packages/demobank-ui/src/components/Routing.tsx
index b8e39948b..e1fd93737 100644
--- a/packages/demobank-ui/src/components/Routing.tsx
+++ b/packages/demobank-ui/src/components/Routing.tsx
@@ -76,9 +76,9 @@ export function Routing(): VNode {
               onContinue={() => {
                 route("/account");
               }}
-              onLoadNotOk={() => {
-                route("/account");
-              }}
+              // onLoadNotOk={() => {
+              //   route("/account");
+              // }}
             />
           )}
         />
@@ -108,9 +108,9 @@ export function Routing(): VNode {
             } else {
               return <HomePage
                 account={username}
-                onPendingOperationFound={(wopid) => {
-                  route(`/operation/${wopid}`);
-                }}
+                // onPendingOperationFound={(wopid) => {
+                //   route(`/operation/${wopid}`);
+                // }}
                 goToBusinessAccount={() => {
                   route("/business");
                 }}
diff --git a/packages/demobank-ui/src/hooks/settings.ts b/packages/demobank-ui/src/hooks/settings.ts
index 43e803726..c2fd93a0c 100644
--- a/packages/demobank-ui/src/hooks/settings.ts
+++ b/packages/demobank-ui/src/hooks/settings.ts
@@ -29,20 +29,26 @@ import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
 interface Settings {
   currentWithdrawalOperationId: string | undefined;
   showWithdrawalSuccess: boolean;
+  showDemoDescription: boolean;
   maxWithdrawalAmount: number;
+  fastWithdrawal: boolean;
 }
 
 export const codecForSettings = (): Codec<Settings> =>
   buildCodecForObject<Settings>()
     .property("currentWithdrawalOperationId", codecOptional(codecForString()))
     .property("showWithdrawalSuccess", (codecForBoolean()))
+    .property("showDemoDescription", (codecForBoolean()))
+    .property("fastWithdrawal", (codecForBoolean()))
     .property("maxWithdrawalAmount", codecForNumber())
     .build("Settings");
 
 const defaultSettings: Settings = {
   currentWithdrawalOperationId: undefined,
   showWithdrawalSuccess: true,
-  maxWithdrawalAmount: 25
+  showDemoDescription: true,
+  maxWithdrawalAmount: 25,
+  fastWithdrawal: false,
 };
 
 const DEMOBANK_SETTINGS_KEY = buildStorageKey(
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index abd14848f..0187989af 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -23,6 +23,7 @@ import { State } from "./index.js";
 import { CopyButton } from "../../components/CopyButton.js";
 import { bankUiSettings } from "../../settings.js";
 import { useBusinessAccountDetails } from "../../hooks/circuit.js";
+import { useSettings } from "../../hooks/settings.js";
 
 export function InvalidIbanView({ error }: State.InvalidIban) {
   return (
@@ -78,9 +79,58 @@ function ImportantMessage(): VNode {
 
 }
 
+function ShowDemoInfo():VNode {
+  const { i18n } = useTranslationContext();
+  const [settings, updateSettings] = useSettings();
+  if (!settings.showDemoDescription) return <Fragment />
+  return <div class="rounded-md bg-blue-50 p-4">
+  <div class="flex">
+    <div class="flex-shrink-0">
+      <svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+        <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
+      </svg>
+    </div>
+    <div class="ml-3">
+      <h3 class="text-sm font-bold text-blue-800">
+        <i18n.Translate>This is a demo bank!</i18n.Translate>
+      </h3>
+      <div class="mt-2 text-sm text-blue-700">
+        <p>
+          <i18n.Translate>
+            This part of the demo shows how a bank that supports Taler
+            directly would work. In addition to using your own bank
+            account, you can also see the transaction history of some{" "}
+            <a href="/public-accounts">Public Accounts</a>.
+          </i18n.Translate>
+        </p>
+        <p class="mt-3 text-sm flex justify-end">
+          <button type="button" class="inline-flex font-semibold items-center rounded bg-white px-2 py-1 text-xs text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
+            onClick={(e) => {
+              e.preventDefault();
+              updateSettings("showDemoDescription", false);
+            }}
+          >
+            Close
+            <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
+            </svg>
+          </button>
+        </p>
+
+      </div>
+    </div>
+  </div>
+</div>
+}
+
 export function ReadyView({ account, limit, goToBusinessAccount }: State.Ready): VNode<{}> {
+  const { i18n } = useTranslationContext();
+
   return <Fragment>
     <MaybeBusinessButton account={account} onClick={goToBusinessAccount} />
+
+    <ShowDemoInfo />
+    
     <PaymentOptions limit={limit} />
     <Transactions account={account} />
   </Fragment>;
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index 4b23686d6..d1c94135b 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -27,7 +27,6 @@ import { CopyButton, CopyIcon } from "../components/CopyButton.js";
 import logo from "../assets/logo-2021.svg";
 import { useAccountDetails } from "../hooks/access.js";
 
-const IS_PUBLIC_ACCOUNT_ENABLED = false;
 const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
 const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
 
@@ -142,24 +141,40 @@ export function BankFrame({
                         <nav class="flex flex-1 flex-col" aria-label="Sidebar">
                           <ul role="list" class="flex flex-1 flex-col gap-y-7">
                             <li>
-                              <ul role="list" class="-mx-2 space-y-1">
-                                <li>
-                                  <a href="#"
-                                    class="text-gray-700 hover:text-indigo-600 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"
-                                    onClick={() => {
-                                      backend.logOut();
-                                      setOpen(false)
-                                      updateSettings("currentWithdrawalOperationId", undefined);
-                                    }}
-                                  >
-                                    <svg class="h-6 w-6 shrink-0 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
-                                      <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
-                                    </svg>
-                                    Log out
-                                    {/* <span class="ml-auto w-9 min-w-max whitespace-nowrap rounded-full bg-gray-50 px-2.5 py-0.5 text-center text-xs font-medium leading-5 text-gray-600 ring-1 ring-inset ring-gray-200" aria-hidden="true">5</span> */}
-                                  </a>
-                                </li>
-                                <li>
+                              <a href="#"
+                                class="text-gray-700 hover:text-indigo-600 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"
+                                onClick={() => {
+                                  backend.logOut();
+                                  setOpen(false)
+                                  updateSettings("currentWithdrawalOperationId", undefined);
+                                }}
+                              >
+                                <svg class="h-6 w-6 shrink-0 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
+                                  <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
+                                </svg>
+                                Log out
+                                {/* <span class="ml-auto w-9 min-w-max whitespace-nowrap rounded-full bg-gray-50 px-2.5 py-0.5 text-center text-xs font-medium leading-5 text-gray-600 ring-1 ring-inset ring-gray-200" aria-hidden="true">5</span> */}
+                              </a>
+                            </li>
+                            <li class="sm:hidden">
+                              <div class="text-xs font-semibold leading-6 text-gray-400">
+                                <i18n.Translate>Sites</i18n.Translate>
+                              </div>
+                              <ul role="list" class="-mx-2 mt-2 space-y-1">
+                                {bankUiSettings.demoSites.map(([name, url]) => {
+                                  return <li>
+                                    <a href={url} target="_blank" rel="noopener noreferrer" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
+                                      <span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600">&gt;</span>
+                                      <span class="truncate">{name}</span>
+                                    </a>
+                                  </li>
+                                })}
+                              </ul>
+                            </li>
+
+                            <li>
+                              <ul role="list" class="space-y-1">
+                                <li class="mt-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">
@@ -169,29 +184,43 @@ export function BankFrame({
                                     <button type="button" data-enabled={settings.showWithdrawalSuccess} 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={() => {
-                                        console.log(settings.showWithdrawalSuccess)
                                         updateSettings("showWithdrawalSuccess", !settings.showWithdrawalSuccess);
                                       }}>
                                       <span aria-hidden="true" data-enabled={settings.showWithdrawalSuccess} 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>
                                 </li>
-                              </ul>
-                            </li>
-
-
+                                <li class="mt-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">
+                                        <i18n.Translate>Show demo description</i18n.Translate>
+                                      </span>
+                                    </span>
+                                    <button type="button" data-enabled={settings.showDemoDescription} 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"
 
-                            <li class="sm:hidden">
-                              <div class="text-xs font-semibold leading-6 text-gray-400">
-                                <i18n.Translate>Sites</i18n.Translate>
-                              </div>
-                              <ul role="list" class="-mx-2 mt-2 space-y-1">
-                                {bankUiSettings.demoSites.map(([name, url]) => {
-                                  return <a href={url} target="_blank" rel="noopener noreferrer" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
-                                    <span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600">&gt;</span>
-                                    <span class="truncate">{name}</span>
-                                  </a>
-                                })}
+                                      onClick={() => {
+                                        updateSettings("showDemoDescription", !settings.showDemoDescription);
+                                      }}>
+                                      <span aria-hidden="true" data-enabled={settings.showDemoDescription} 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>
+                                </li>
+                                <li class="mt-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">
+                                        <i18n.Translate>Use fast withdrawal</i18n.Translate>
+                                      </span>
+                                    </span>
+                                    <button type="button" data-enabled={settings.fastWithdrawal} 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("fastWithdrawal", !settings.fastWithdrawal);
+                                      }}>
+                                      <span aria-hidden="true" data-enabled={settings.fastWithdrawal} 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>
+                                </li>
                               </ul>
                             </li>
                           </ul>
@@ -240,11 +269,6 @@ export function BankFrame({
     //   >
     //     <a href="#main" class="skip">{i18n.str`Skip to main content`}</a>
     //     <div style="max-width: 50em; margin-left: 2em; margin-right: 2em;">
-    //       <h1>
-    //         <span class="it">
-    //           <a href="/">{bankUiSettings.bankName}</a>
-    //         </span>
-    //       </h1>
     //       {maybeDemoContent(
     //         <p>
     //           {IS_PUBLIC_ACCOUNT_ENABLED ? (
@@ -298,33 +322,6 @@ export function BankFrame({
   );
 }
 
-// function maybeDemoContent(content: VNode): VNode {
-//   if (bankUiSettings.showDemoNav) {
-//     return content;
-//   }
-//   return <Fragment />;
-// }
-
-// export function ErrorBannerFloat({
-//   error,
-//   onClear,
-// }: {
-//   error: ErrorMessage;
-//   onClear?: () => void;
-// }): VNode {
-//   return (
-//     <div
-//       style={{
-//         position: "fixed",
-//         top: 10,
-//         zIndex: 200,
-//         width: "90%",
-//       }}
-//     >
-//       <ErrorBanner error={error} onClear={onClear} />
-//     </div>
-//   );
-// }
 
 function StatusBanner(): VNode {
   const notifs = useNotifications()
@@ -469,5 +466,5 @@ function AccountBalance({ account }: { account: string }): VNode {
     {Amounts.currencyOf(result.data.balance.amount)}
     &nbsp;{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""}
     {Amounts.stringifyValue(result.data.balance.amount)}
-    </div>
+  </div>
 }
diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx
index 40cc147a6..2acfc9b57 100644
--- a/packages/demobank-ui/src/pages/HomePage.tsx
+++ b/packages/demobank-ui/src/pages/HomePage.tsx
@@ -52,21 +52,21 @@ const logger = new Logger("AccountPage");
 export function HomePage({
   onRegister,
   account,
-  onPendingOperationFound,
+  // onPendingOperationFound,
   goToBusinessAccount,
 }: {
   account: string,
-  onPendingOperationFound: (id: string) => void;
+  // onPendingOperationFound: (id: string) => void;
   onRegister: () => void;
   goToBusinessAccount: () => void;
 }): VNode {
   const [settings] = useSettings();
   const { i18n } = useTranslationContext();
 
-  if (settings.currentWithdrawalOperationId) {
-    onPendingOperationFound(settings.currentWithdrawalOperationId);
-    return <Loading />;
-  }
+  // if (settings.currentWithdrawalOperationId) {
+  //   onPendingOperationFound(settings.currentWithdrawalOperationId);
+  //   return <Loading />;
+  // }
 
   return (
     <AccountPage
@@ -79,11 +79,9 @@ export function HomePage({
 
 export function WithdrawalOperationPage({
   operationId,
-  onLoadNotOk,
   onContinue,
 }: {
   operationId: string;
-  onLoadNotOk: () => void;
   onContinue: () => void;
 }): VNode {
   //FIXME: libeufin sandbox should return show to create the integration api endpoint
@@ -95,6 +93,7 @@ export function WithdrawalOperationPage({
   });
   const parsedUri = parseWithdrawUri(uri);
   const { i18n } = useTranslationContext();
+  const [settings, updateSettings] = useSettings();
 
   if (!parsedUri) {
     notifyError(
@@ -107,8 +106,9 @@ export function WithdrawalOperationPage({
   return (
     <WithdrawalQRCode
       withdrawUri={parsedUri}
-      onContinue={onContinue}
-      onLoadNotOk={onLoadNotOk}
+      onClose={() => {
+        updateSettings("currentWithdrawalOperationId", undefined)
+      }}
     />
   );
 }
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx
index 1728074a3..573f8c769 100644
--- a/packages/demobank-ui/src/pages/PaymentOptions.tsx
+++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx
@@ -34,80 +34,83 @@ export function PaymentOptions({ limit }: { limit: AmountJson }): VNode {
   // const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>(undefined);
 
   return (
-    <fieldset>
-      <legend class="px-4 text-base font-semibold leading-6 text-gray-900">
-        <i18n.Translate>Send money to</i18n.Translate>
-      </legend>
+    <div class="mt-2">
 
-      <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4">
-        {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */}
-        <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "charge-wallet" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
-          <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onClick={() => {
-            setTab("charge-wallet")
-          }} />
-          <span class="flex flex-1">
-            <div class="text-lg mr-2">&#x1F4B5;</div>
-            <span class="flex flex-col">
-              <span id="project-type-0-label" class="block text-sm font-medium text-gray-900">
-                <i18n.Translate>a <b>Taler</b> wallet</i18n.Translate>
-              </span>
-              <span id="project-type-0-description-0" class="mt-1 flex items-center text-sm text-gray-500">
-                <i18n.Translate>Withdraw digital money into your mobile wallet or browser extension</i18n.Translate>
+      <fieldset>
+        <legend class="px-4 text-base font-semibold leading-6 text-gray-900">
+          <i18n.Translate>Send money to</i18n.Translate>
+        </legend>
+
+        <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4">
+          {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */}
+          <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "charge-wallet" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
+            <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onClick={() => {
+              setTab("charge-wallet")
+            }} />
+            <span class="flex flex-1">
+              <div class="text-lg mr-2">&#x1F4B5;</div>
+              <span class="flex flex-col">
+                <span id="project-type-0-label" class="block text-sm font-medium text-gray-900">
+                  <i18n.Translate>a <b>Taler</b> wallet</i18n.Translate>
+                </span>
+                <span id="project-type-0-description-0" class="mt-1 flex items-center text-sm text-gray-500">
+                  <i18n.Translate>Withdraw digital money into your mobile wallet or browser extension</i18n.Translate>
+                </span>
               </span>
             </span>
-          </span>
-          <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "charge-wallet" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
-          </svg>
-        </label>
+            <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "charge-wallet" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
+            </svg>
+          </label>
 
 
-        <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "wire-transfer" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
-          <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onClick={() => {
-            setTab("wire-transfer")
-          }} />
-          <span class="flex flex-1">
-          <div class="text-lg mr-2">&#x2194;</div>
-            <span class="flex flex-col">
-              <span id="project-type-1-label" class="block text-sm font-medium text-gray-900">
-                <i18n.Translate>another bank account</i18n.Translate>
-              </span>
-              <span id="project-type-1-description-0" class="mt-1 flex items-center text-sm text-gray-500">
-                <i18n.Translate>Make a wire transfer to an account which you know the address.</i18n.Translate>
+          <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "wire-transfer" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
+            <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onClick={() => {
+              setTab("wire-transfer")
+            }} />
+            <span class="flex flex-1">
+              <div class="text-lg mr-2">&#x2194;</div>
+              <span class="flex flex-col">
+                <span id="project-type-1-label" class="block text-sm font-medium text-gray-900">
+                  <i18n.Translate>another bank account</i18n.Translate>
+                </span>
+                <span id="project-type-1-description-0" class="mt-1 flex items-center text-sm text-gray-500">
+                  <i18n.Translate>Make a wire transfer to an account which you know the address.</i18n.Translate>
+                </span>
               </span>
             </span>
-          </span>
-          <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "wire-transfer" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
-          </svg>
-        </label>
-      </div>
-      {tab === "charge-wallet" && (
-        <WalletWithdrawForm
-          focus
-          limit={limit}
-          onSuccess={(id) => {
-            updateSettings("currentWithdrawalOperationId", id);
-          }}
-          onCancel={() => {
-            setTab(undefined)
-          }}
-        />
-      )}
-      {tab === "wire-transfer" && (
-        <PaytoWireTransferForm
-          focus
-          title={i18n.str`Transfer details`}
-          limit={limit}
-          onSuccess={() => {
-            notifyInfo(i18n.str`Wire transfer created!`);
-          }}
-          onCancel={() => {
-            setTab(undefined)
-          }}
-        />
-      )}
+            <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "wire-transfer" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
+            </svg>
+          </label>
+        </div>
+        {tab === "charge-wallet" && (
+          <WalletWithdrawForm
+            focus
+            limit={limit}
+            onSuccess={(id) => {
+              updateSettings("currentWithdrawalOperationId", id);
+            }}
+            onCancel={() => {
+              setTab(undefined)
+            }}
+          />
+        )}
+        {tab === "wire-transfer" && (
+          <PaytoWireTransferForm
+            focus
+            title={i18n.str`Transfer details`}
+            limit={limit}
+            onSuccess={() => {
+              notifyInfo(i18n.str`Wire transfer created!`);
+            }}
+            onCancel={() => {
+              setTab(undefined)
+            }}
+          />
+        )}
 
-    </fieldset>
+      </fieldset>
+    </div>
   )
 }
diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx b/packages/demobank-ui/src/pages/QrCodeSection.tsx
index 7c1b3bdc5..416c714e2 100644
--- a/packages/demobank-ui/src/pages/QrCodeSection.tsx
+++ b/packages/demobank-ui/src/pages/QrCodeSection.tsx
@@ -135,3 +135,109 @@ export function QrCodeSection({
     </Fragment>
   );
 }
+
+
+export function QrCodeSectionSimpler({
+  withdrawUri,
+  onAborted,
+}: {
+  withdrawUri: WithdrawUriResult;
+  onAborted: () => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  useEffect(() => {
+    //Taler Wallet WebExtension is listening to headers response and tab updates.
+    //In the SPA there is no header response with the Taler URI so
+    //this hack manually triggers the tab update after the QR is in the DOM.
+    // WebExtension will be using
+    // https://developer.chrome.com/docs/extensions/reference/tabs/#event-onUpdated
+    document.title = `${document.title} ${withdrawUri.withdrawalOperationId}`;
+  }, []);
+  const talerWithdrawUri = stringifyWithdrawUri(withdrawUri);
+
+  const { abortWithdrawal } = useAccessAnonAPI();
+
+  async function doAbort() {
+    try {
+      await abortWithdrawal(withdrawUri.withdrawalOperationId);
+      onAborted();
+    } catch (error) {
+      if (error instanceof RequestError) {
+        notify(
+          buildRequestErrorMessage(i18n, error.cause, {
+            onClientError: (status) =>
+              status === HttpStatusCode.Conflict
+                ? i18n.str`The reserve operation has been confirmed previously and can't be aborted`
+                : undefined,
+          }),
+        );
+      } else {
+        notifyError(
+          i18n.str`Operation failed, please report`,
+          (error instanceof Error
+            ? error.message
+            : JSON.stringify(error)) as TranslatedString
+        )
+      }
+    }
+  }
+
+  return (
+    <Fragment>
+      <div class="bg-white shadow-xl sm:rounded-lg">
+        <div class="p2 ">
+          <h3 class="text-base font-semibold leading-6 text-gray-900">
+            <i18n.Translate>If you have a Taler wallet installed in this device</i18n.Translate>
+          </h3>
+          <div class="mt-4">
+            <a href={talerWithdrawUri}
+              // class="text-sm font-semibold leading-6 text-gray-900 btn "
+              class="inline-flex items-center  disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+            >
+              <i18n.Translate>Click here to start</i18n.Translate>
+            </a>
+          </div>
+          <div class="mt-4 max-w-xl text-sm text-gray-500">
+            <p><i18n.Translate>
+              You will see the details of the operation in your wallet including the fees (if applies).
+              If you still one you can install it from <a class="font-semibold text-gray-500 hover:text-gray-400" href="https://taler.net/en/wallet.html">here</a>.
+            </i18n.Translate></p>
+          </div>
+          <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 pt-2 mt-2 ">
+            <div />
+            <button type="button"
+              class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
+              onClick={doAbort}
+            >
+              Cancel withdrawal
+            </button>
+          </div>
+        </div>
+      </div>
+
+      <div class="bg-white shadow-xl sm:rounded-lg mt-8">
+        <div class="px-4 py-5 sm:p-6">
+          <h3 class="text-base font-semibold leading-6 text-gray-900">
+            <i18n.Translate>Or if you have the wallet in another device</i18n.Translate>
+          </h3>
+          <div class="mt-4 max-w-xl text-sm text-gray-500">
+            <i18n.Translate>Scan the QR below to start the withdrawal</i18n.Translate>
+          </div>
+          <div class="mt-2 max-w-md ml-auto mr-auto">
+            <QR text={talerWithdrawUri} />
+          </div>
+        </div>
+        <div class="flex items-center justify-center gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
+          <button type="button"
+            class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
+            onClick={doAbort}
+          >
+            Cancel withdrawal
+          </button>
+        </div>
+      </div>
+
+    </Fragment>
+  );
+}
+
diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
index 8c41f7576..08f706919 100644
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
@@ -20,6 +20,7 @@ import {
   HttpStatusCode,
   Logger,
   TranslatedString,
+  WithdrawUriResult,
   parseWithdrawUri,
 } from "@gnu-taler/taler-util";
 import {
@@ -34,6 +35,9 @@ import { useEffect, useRef, useState } from "preact/hooks";
 import { useAccessAPI } from "../hooks/access.js";
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
 import { Amount } from "./PaytoWireTransferForm.js";
+import { useSettings } from "../hooks/settings.js";
+import { WithdrawalOperationState } from "./WithdrawalQRCode.js";
+import { Loading } from "../components/Loading.js";
 
 const logger = new Logger("WalletWithdrawForm");
 const RefAmount = forwardRef(Amount);
@@ -51,8 +55,9 @@ export function WalletWithdrawForm({
 }): VNode {
   const { i18n } = useTranslationContext();
   const { createWithdrawal } = useAccessAPI();
+  const [settings, updateSettings] = useSettings()
 
-  const [amountStr, setAmountStr] = useState<string | undefined>("5.00");
+  const [amountStr, setAmountStr] = useState<string | undefined>(`${settings.maxWithdrawalAmount}`);
   const ref = useRef<HTMLInputElement>(null);
   useEffect(() => {
     if (focus) ref.current?.focus();
@@ -78,7 +83,6 @@ export function WalletWithdrawForm({
   async function doStart() {
     if (!parsedAmount) return;
     try {
-      console.log("ASDASD")
       const result = await createWithdrawal({
         amount: Amounts.stringify(parsedAmount),
       });
@@ -109,7 +113,6 @@ export function WalletWithdrawForm({
         )
       }
     }
-
   }
 
   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">
@@ -122,91 +125,103 @@ export function WalletWithdrawForm({
         <i18n.Translate>After using your wallet you will be redirected here to confirm or cancel the operation.</i18n.Translate>
       </p>
     </div>
-    <form
-      class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
-      autoCapitalize="none"
-      autoCorrect="off"
-      onSubmit={e => {
-        e.preventDefault()
-      }}
-    >
-      <div class="px-4 py-6 sm:p-8">
-        <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
-          <div class="sm:col-span-5">
-            <label for="withdraw-amount">{i18n.str`Amount`}</label>
-            <RefAmount
-              currency={limit.currency}
-              value={amountStr}
-              name="withdraw-amount"
-              onChange={(v) => {
-                setAmountStr(v);
-              }}
-              error={errors?.amount}
-              ref={ref}
-            />
-          </div>
-          <div class="sm:col-span-5">
-            <span class="isolate inline-flex rounded-md shadow-sm">
-              <button type="button"
-                class="relative               inline-flex px-6 py-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-                onClick={(e) => {
-                  e.preventDefault();
-                  setAmountStr("50.00")
-                }}
-              >
-                50.00
-              </button>
-              <button type="button"
-                class="relative -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center              bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-                onClick={(e) => {
-                  e.preventDefault();
-                  setAmountStr("25.00")
-                }}
-              >
-
-                25.00
-              </button>
-              <button type="button"
-                class="relative -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center              bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-                onClick={(e) => {
-                  e.preventDefault();
-                  setAmountStr("10.00")
-                }}
-              >
-                10.00
-              </button>
-              <button type="button"
-                class="relative               inline-flex px-6 py-4 text-sm items-center rounded-r-md bg-white  text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-                onClick={(e) => {
-                  e.preventDefault();
-                  setAmountStr("5.00")
+
+    {!settings.fastWithdrawal ?
+      <form
+        class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
+        autoCapitalize="none"
+        autoCorrect="off"
+        onSubmit={e => {
+          e.preventDefault()
+        }}
+      >
+        <div class="px-4 py-6 sm:p-8">
+          <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
+            <div class="sm:col-span-5">
+              <label for="withdraw-amount">{i18n.str`Amount`}</label>
+              <RefAmount
+                currency={limit.currency}
+                value={amountStr}
+                name="withdraw-amount"
+                onChange={(v) => {
+                  setAmountStr(v);
                 }}
-              >
-                5.00
-              </button>
-            </span>
-          </div>
+                error={errors?.amount}
+                ref={ref}
+              />
+            </div>
+            <div class="sm:col-span-5">
+              <span class="isolate inline-flex rounded-md shadow-sm">
+                <button type="button"
+                  class="relative               inline-flex px-6 py-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+                  onClick={(e) => {
+                    e.preventDefault();
+                    setAmountStr("50.00")
+                  }}
+                >
+                  50.00
+                </button>
+                <button type="button"
+                  class="relative -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center              bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+                  onClick={(e) => {
+                    e.preventDefault();
+                    setAmountStr("25.00")
+                  }}
+                >
+
+                  25.00
+                </button>
+                <button type="button"
+                  class="relative -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center              bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+                  onClick={(e) => {
+                    e.preventDefault();
+                    setAmountStr("10.00")
+                  }}
+                >
+                  10.00
+                </button>
+                <button type="button"
+                  class="relative               inline-flex px-6 py-4 text-sm items-center rounded-r-md bg-white  text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+                  onClick={(e) => {
+                    e.preventDefault();
+                    setAmountStr("5.00")
+                  }}
+                >
+                  5.00
+                </button>
+              </span>
+            </div>
 
+          </div>
+        </div>
+        <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
+          <button type="button" class="text-sm font-semibold leading-6 text-gray-900"
+            onClick={onCancel}
+          >
+            <i18n.Translate>Cancel</i18n.Translate></button>
+          <button type="submit"
+            class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+            // disabled={isRawPayto ? !!errorsPayto : !!errorsWire}
+            onClick={(e) => {
+              e.preventDefault()
+              doStart()
+            }}
+          >
+            <i18n.Translate>Continue</i18n.Translate>
+          </button>
         </div>
-      </div>
-      <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
-        <button type="button" class="text-sm font-semibold leading-6 text-gray-900"
-          onClick={onCancel}
-        >
-          <i18n.Translate>Cancel</i18n.Translate></button>
-        <button type="submit"
-          class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
-          // disabled={isRawPayto ? !!errorsPayto : !!errorsWire}
-          onClick={(e) => {
-            e.preventDefault()
-            doStart()
-          }}
-        >
-          <i18n.Translate>Continue</i18n.Translate>
-        </button>
-      </div>
 
-    </form>
+      </form>
+      : settings.currentWithdrawalOperationId === undefined ?
+        <Loading /> :
+        <WithdrawalOperationState
+          currentOperation={settings.currentWithdrawalOperationId}
+          currency={limit.currency}
+          onClose={() => {
+            onCancel()
+          }}
+        />
+    }
   </div>
   );
 }
diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
index 2a3a1ec2c..9976babdb 100644
--- a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
@@ -18,24 +18,29 @@ import {
   Amounts,
   HttpStatusCode,
   Logger,
+  TranslatedString,
   WithdrawUriResult,
   parsePaytoUri,
+  parseWithdrawUri,
+  stringifyWithdrawUri,
 } from "@gnu-taler/taler-util";
-import { ErrorType, notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { ErrorType, RequestError, notify, notifyError, notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { Loading } from "../components/Loading.js";
-import { useWithdrawalDetails } from "../hooks/access.js";
+import { useAccessAPI, useWithdrawalDetails } from "../hooks/access.js";
 import { useSettings } from "../hooks/settings.js";
 import { handleNotOkResult } from "./HomePage.js";
-import { QrCodeSection } from "./QrCodeSection.js";
+import { QrCodeSection, QrCodeSectionSimpler } from "./QrCodeSection.js";
 import { WithdrawalConfirmationQuestion } from "./WithdrawalConfirmationQuestion.js";
+import { useEffect, useState } from "preact/hooks";
+import { buildRequestErrorMessage } from "../utils.js";
+import { getInitialBackendBaseURL } from "../hooks/backend.js";
 
 const logger = new Logger("WithdrawalQRCode");
 
 interface Props {
   withdrawUri: WithdrawUriResult;
-  onContinue: () => void;
-  onLoadNotOk: () => void;
+  onClose: () => void;
 }
 /**
  * Offer the QR code (and a clickable taler://-link) to
@@ -44,14 +49,9 @@ interface Props {
  */
 export function WithdrawalQRCode({
   withdrawUri,
-  onContinue,
-  onLoadNotOk,
+  onClose,
 }: Props): VNode {
   const [settings, updateSettings] = useSettings();
-  function clearCurrentWithdrawal(): void {
-    updateSettings("currentWithdrawalOperationId", undefined);
-    onContinue();
-  }
   const { i18n } = useTranslationContext();
   const result = useWithdrawalDetails(withdrawUri.withdrawalOperationId);
   if (!result.ok) {
@@ -62,7 +62,7 @@ export function WithdrawalQRCode({
       result.type === ErrorType.CLIENT &&
       result.status === HttpStatusCode.NotFound
     ) {
-      clearCurrentWithdrawal()
+      onClose()
       return <div>operation not found</div>;
     }
     // onLoadNotOk();
@@ -89,8 +89,7 @@ export function WithdrawalQRCode({
           style={{ float: "right" }}
           onClick={async (e) => {
             e.preventDefault();
-            clearCurrentWithdrawal()
-            onContinue()
+            onClose()
           }}>
           {i18n.str`Continue`}
         </a>
@@ -149,8 +148,7 @@ export function WithdrawalQRCode({
           class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
           onClick={async (e) => {
             e.preventDefault();
-            clearCurrentWithdrawal()
-            onContinue()
+            onClose()
           }}>
           <i18n.Translate>Continue</i18n.Translate>
         </button>
@@ -165,8 +163,7 @@ export function WithdrawalQRCode({
         withdrawUri={withdrawUri}
         onAborted={() => {
           notifyInfo(i18n.str`Operation canceled`);
-          clearCurrentWithdrawal()
-          onContinue()
+          onClose()
         }}
       />
     );
@@ -196,9 +193,131 @@ export function WithdrawalQRCode({
       }}
       onAborted={() => {
         notifyInfo(i18n.str`Operation canceled`);
-        clearCurrentWithdrawal()
-        onContinue()
+        onClose()
       }}
     />
   );
+}
+
+
+export function WithdrawalOperationState({
+  currency,
+  currentOperation,
+  onClose,
+}: {currency:string, currentOperation: string, onClose: () => void}): VNode {
+  const { i18n } = useTranslationContext();
+  const [settings, updateSettings] = useSettings()
+  const { createWithdrawal } = useAccessAPI();
+
+  const amount = settings.maxWithdrawalAmount
+  async function doSilentStart() {
+    //FIXME: if amount is not enough use balance
+    const parsedAmount = Amounts.parseOrThrow(`${currency}:${amount}`)
+
+    try {
+      const result = await createWithdrawal({
+        amount: Amounts.stringify(parsedAmount),
+      });
+      const uri = parseWithdrawUri(result.data.taler_withdraw_uri);
+      if (!uri) {
+        return notifyError(
+          i18n.str`Server responded with an invalid withdraw URI`,
+          i18n.str`Withdraw URI: ${result.data.taler_withdraw_uri}`);
+      } else {
+        updateSettings("currentWithdrawalOperationId", uri.withdrawalOperationId)
+      }
+    } catch (error) {
+      if (error instanceof RequestError) {
+        notify(
+          buildRequestErrorMessage(i18n, error.cause, {
+            onClientError: (status) =>
+              status === HttpStatusCode.Forbidden
+                ? i18n.str`The operation was rejected due to insufficient funds`
+                : undefined,
+          }),
+        );
+      } else {
+        notifyError(
+          i18n.str`Operation failed, please report`,
+          (error instanceof Error
+            ? error.message
+            : JSON.stringify(error)) as TranslatedString
+        )
+      }
+    }
+  }
+
+  useEffect(() => {
+    doSilentStart()
+  }, [settings.fastWithdrawal, amount])
+
+  const result = useWithdrawalDetails(currentOperation);
+  if (!result.ok) {
+    if (result.loading) {
+      return <Loading />;
+    }
+    if (
+      result.type === ErrorType.CLIENT &&
+      result.status === HttpStatusCode.NotFound
+    ) {
+      onClose()
+      return <div>operation not found</div>;
+    }
+    // onLoadNotOk();
+    return handleNotOkResult(i18n)(result);
+  }
+  const { data } = result;
+
+  const baseUrl = getInitialBackendBaseURL()
+  const uri = stringifyWithdrawUri({
+    bankIntegrationApiBaseUrl: `${baseUrl}/integration-api`,
+    withdrawalOperationId: currentOperation,
+  });
+  const parsedUri = parseWithdrawUri(uri);
+
+  if (data.aborted) {
+    return <div>
+      the operation was aborted, you can create another one
+    </div>
+  }
+
+  if (data.confirmation_done) {
+    return <div>
+      the wire transfer is made, you coin should arrive shortly
+    </div>
+  }
+  if (!parsedUri) {
+    return <div>
+      the operation is not valid, create another one
+    </div>
+  }
+  if (!data.selection_done) {
+    return (
+      <QrCodeSectionSimpler
+        withdrawUri={parsedUri}
+        onAborted={() => {
+          notifyInfo(i18n.str`Operation canceled`);
+          onClose()
+        }}
+      />
+    );
+  }
+
+  if (!data.selected_reserve_pub) {
+    return <div>
+      the exchange is selcted but no reserve pub
+    </div>
+  }
+
+  const account = !data.selected_exchange_account ? undefined : parsePaytoUri(data.selected_exchange_account)
+
+  if (!account) {
+    return <div>
+      the exchange is selected but no account
+    </div>
+  }
+
+  return <div>
+    the operation is wating for the question to be answered
+  </div>;
 }
\ No newline at end of file
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index 050f1fb8a..1e5370afc 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -61,7 +61,7 @@ export function RemoveAccount({
             </h3>
             <div class="mt-2 text-sm text-yellow-700">
               <p>
-                <i18n.Translate>The account can be delete while still holding some balance. First make sure that the owner make a complete cashout.</i18n.Translate>
+                <i18n.Translate>The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.</i18n.Translate>
               </p>
             </div>
           </div>
-- 
cgit v1.2.3


From 15af6c619de70336bcdfbabbd32b9d93aabefc5b Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Fri, 22 Sep 2023 18:34:49 -0300
Subject: towards new core bank api

---
 packages/demobank-ui/src/components/Routing.tsx    |   40 +-
 packages/demobank-ui/src/declaration.d.ts          |  166 +-
 packages/demobank-ui/src/hooks/access.ts           |  100 +-
 packages/demobank-ui/src/hooks/backend.ts          |    2 +-
 .../demobank-ui/src/hooks/useCredentialsChecker.ts |   15 +-
 .../demobank-ui/src/pages/AccountPage/index.ts     |    2 +-
 .../demobank-ui/src/pages/AccountPage/state.ts     |   16 +-
 .../demobank-ui/src/pages/AccountPage/views.tsx    |    2 +-
 packages/demobank-ui/src/pages/BankFrame.tsx       |   12 +-
 packages/demobank-ui/src/pages/HomePage.tsx        |    8 +-
 packages/demobank-ui/src/pages/LoginForm.tsx       |  104 +-
 .../demobank-ui/src/pages/PublicHistoriesPage.tsx  |   16 +-
 .../demobank-ui/src/pages/RegistrationPage.tsx     |   47 +-
 .../demobank-ui/src/pages/WalletWithdrawForm.tsx   |   50 +-
 packages/demobank-ui/src/pages/admin/Account.tsx   |   11 +-
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  |    4 +-
 packages/demobank-ui/src/pages/business/Home.tsx   |   93 +-
 packages/demobank-ui/src/pages/rnd.ts              | 5759 ++++++++++----------
 packages/demobank-ui/src/settings.ts               |    4 +
 19 files changed, 3293 insertions(+), 3158 deletions(-)

(limited to 'packages/demobank-ui/src/pages/admin/RemoveAccount.tsx')

diff --git a/packages/demobank-ui/src/components/Routing.tsx b/packages/demobank-ui/src/components/Routing.tsx
index 90d2d4c48..d51bd01eb 100644
--- a/packages/demobank-ui/src/components/Routing.tsx
+++ b/packages/demobank-ui/src/components/Routing.tsx
@@ -27,6 +27,7 @@ import { Test } from "../pages/Test.js";
 import { useBackendContext } from "../context/backend.js";
 import { LoginForm } from "../pages/LoginForm.js";
 import { AdminHome } from "../pages/admin/Home.js";
+import { bankUiSettings } from "../settings.js";
 
 export function Routing(): VNode {
   const history = createHashHistory();
@@ -45,6 +46,10 @@ export function Routing(): VNode {
             />
           )}
         />
+        <Route
+          path="/public-accounts"
+          component={() => <PublicHistoriesPage />}
+        />
         <Route
           path="/operation/:wopid"
           component={({ wopid }: { wopid: string }) => (
@@ -53,22 +58,21 @@ export function Routing(): VNode {
               onContinue={() => {
                 route("/account");
               }}
-              // onLoadNotOk={() => {
-              //   route("/account");
-              // }}
-            />
-          )}
-        />
-        <Route
-          path="/register"
-          component={() => (
-            <RegistrationPage
-              onComplete={() => {
-                route("/account");
-              }}
             />
           )}
         />
+        {bankUiSettings.allowRegistrations &&
+          <Route
+            path="/register"
+            component={() => (
+              <RegistrationPage
+                onComplete={() => {
+                  route("/account");
+                }}
+              />
+            )}
+          />
+        }
         <Route default component={Redirect} to="/login" />
       </Router>
     </BankFrame>
@@ -93,16 +97,6 @@ export function Routing(): VNode {
           path="/public-accounts"
           component={() => <PublicHistoriesPage />}
         />
-        <Route
-          path="/register"
-          component={() => (
-            <RegistrationPage
-              onComplete={() => {
-                route("/account");
-              }}
-            />
-          )}
-        />
         <Route
           path="/account"
           component={() => {
diff --git a/packages/demobank-ui/src/declaration.d.ts b/packages/demobank-ui/src/declaration.d.ts
index 462287c59..a9573fbcd 100644
--- a/packages/demobank-ui/src/declaration.d.ts
+++ b/packages/demobank-ui/src/declaration.d.ts
@@ -99,11 +99,6 @@ type Amount = string;
 type UUID = string;
 type Integer = number;
 
-interface Balance {
-  amount: Amount;
-  credit_debit_indicator: "credit" | "debit";
-}
-
 namespace SandboxBackend {
   export interface Config {
     // Name of this API, always "circuit".
@@ -126,7 +121,7 @@ namespace SandboxBackend {
   }
 
   export interface SandboxError {
-    error: SandboxErrorDetail;
+    error?: SandboxErrorDetail;
   }
   interface SandboxErrorDetail {
     // String enum classifying the error.
@@ -152,26 +147,12 @@ namespace SandboxBackend {
     UtilError = "util-error",
   }
 
-  namespace Access {
-    interface PublicAccountsResponse {
-      publicAccounts: PublicAccount[];
-    }
-    interface PublicAccount {
-      iban: string;
-      balance: string;
-      // The account name _and_ the username of the
-      // Sandbox customer that owns such a bank account.
-      accountLabel: string;
-    }
 
-    interface BankAccountBalanceResponse {
-      // Available balance on the account.
-      balance: Balance;
-      // payto://-URI of the account. (New)
-      paytoUri: string;
-      // Number indicating the max debit allowed for the requesting user.
-      debitThreshold: Amount;
-    }
+  type EmailAddress = string;
+  type PhoneNumber = string;
+
+  namespace CoreBank {
+
     interface BankAccountCreateWithdrawalRequest {
       // Amount to withdraw.
       amount: Amount;
@@ -243,11 +224,144 @@ namespace SandboxBackend {
       amount?: string;
     }
 
-    interface BankRegistrationRequest {
+    interface RegisterAccountRequest {
+      // Username
       username: string;
 
+      // Password.
       password: string;
+
+      // Legal name of the account owner
+      name: string;
+
+      // Defaults to false.
+      is_public?: boolean;
+
+      // Is this a taler exchange account?
+      // If true:
+      // - incoming transactions to the account that do not
+      //   have a valid reserve public key are automatically
+      // - the account provides the taler-wire-gateway-api endpoints
+      // Defaults to false.
+      is_taler_exchange?: boolean;
+
+      // Addresses where to send the TAN for transactions.
+      // Currently only used for cashouts.
+      // If missing, cashouts will fail.
+      // In the future, might be used for other transactions
+      // as well.
+      challenge_contact_data?: ChallengeContactData;
+
+      // 'payto' address pointing a bank account
+      // external to the libeufin-bank.
+      // Payments will be sent to this bank account
+      // when the user wants to convert the local currency
+      // back to fiat currency outside libeufin-bank.
+      cashout_payto_uri?: string;
+
+      // Internal payto URI of this bank account.
+      // Used mostly for testing.
+      internal_payto_uri?: string;
+    }
+    interface ChallengeContactData {
+
+      // E-Mail address
+      email?: EmailAddress;
+
+      // Phone number.
+      phone?: PhoneNumber;
+    }
+
+    interface AccountReconfiguration {
+
+      // Addresses where to send the TAN for transactions.
+      // Currently only used for cashouts.
+      // If missing, cashouts will fail.
+      // In the future, might be used for other transactions
+      // as well.
+      challenge_contact_data?: ChallengeContactData;
+
+      // 'payto' address pointing a bank account
+      // external to the libeufin-bank.
+      // Payments will be sent to this bank account
+      // when the user wants to convert the local currency
+      // back to fiat currency outside libeufin-bank.
+      cashout_address?: string;
+
+      // Legal name associated with $username.
+      // When missing, the old name is kept.
+      name?: string;
+
+      // If present, change the is_exchange configuration.
+      // See RegisterAccountRequest
+      is_exchange?: boolean;
+    }
+
+
+    interface AccountPasswordChange {
+
+      // New password.
+      new_password: string;
+    }
+    interface PublicAccountsResponse {
+      public_accounts: PublicAccount[];
+    }
+    interface PublicAccount {
+      payto_uri: string;
+
+      balance: Balance;
+
+      // The account name (=username) of the
+      // libeufin-bank account.
+      account_name: string;
+    }
+
+    interface ListBankAccountsResponse {
+      accounts: AccountMinimalData[];
+    }
+    // interface Balance {
+    //   amount: Amount;
+    //   credit_debit_indicator: "credit" | "debit";
+    // }
+    type Balance = Amount
+    interface AccountMinimalData {
+      // Username
+      username: string;
+    
+      // Legal name of the account owner.
+      name: string;
+    
+      // current balance of the account
+      balance: Balance;
+    
+      // Number indicating the max debit allowed for the requesting user.
+      debit_threshold: Amount;
+    }
+    
+    interface AccountData {
+      // Legal name of the account owner.
+      name: string;
+    
+      // Available balance on the account.
+      balance: Balance;
+    
+      // payto://-URI of the account.
+      payto_uri: string;
+    
+      // Number indicating the max debit allowed for the requesting user.
+      debit_threshold: Amount;
+    
+      contact_data?: ChallengeContactData;
+    
+      // 'payto' address pointing the bank account
+      // where to send cashouts.  This field is optional
+      // because not all the accounts are required to participate
+      // in the merchants' circuit.  One example is the exchange:
+      // that never cashouts.  Registering these accounts can
+      // be done via the access API.
+      cashout_payto_uri?: string;
     }
+    
   }
 
   namespace Circuit {
diff --git a/packages/demobank-ui/src/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts
index af8381135..13fee71f0 100644
--- a/packages/demobank-ui/src/hooks/access.ts
+++ b/packages/demobank-ui/src/hooks/access.ts
@@ -44,13 +44,13 @@ export function useAccessAPI(): AccessAPI {
   const account = state.username;
 
   const createWithdrawal = async (
-    data: SandboxBackend.Access.BankAccountCreateWithdrawalRequest,
+    data: SandboxBackend.CoreBank.BankAccountCreateWithdrawalRequest,
   ): Promise<
-    HttpResponseOk<SandboxBackend.Access.BankAccountCreateWithdrawalResponse>
+    HttpResponseOk<SandboxBackend.CoreBank.BankAccountCreateWithdrawalResponse>
   > => {
     const res =
-      await request<SandboxBackend.Access.BankAccountCreateWithdrawalResponse>(
-        `access-api/accounts/${account}/withdrawals`,
+      await request<SandboxBackend.CoreBank.BankAccountCreateWithdrawalResponse>(
+        `accounts/${account}/withdrawals`,
         {
           method: "POST",
           data,
@@ -60,10 +60,10 @@ export function useAccessAPI(): AccessAPI {
     return res;
   };
   const createTransaction = async (
-    data: SandboxBackend.Access.CreateBankAccountTransactionCreate,
+    data: SandboxBackend.CoreBank.CreateBankAccountTransactionCreate,
   ): Promise<HttpResponseOk<void>> => {
     const res = await request<void>(
-      `access-api/accounts/${account}/transactions`,
+      `accounts/${account}/transactions`,
       {
         method: "POST",
         data,
@@ -74,7 +74,7 @@ export function useAccessAPI(): AccessAPI {
     return res;
   };
   const deleteAccount = async (): Promise<HttpResponseOk<void>> => {
-    const res = await request<void>(`access-api/accounts/${account}`, {
+    const res = await request<void>(`accounts/${account}`, {
       method: "DELETE",
       contentType: "json",
     });
@@ -94,7 +94,7 @@ export function useAccessAnonAPI(): AccessAnonAPI {
   const { request } = useAuthenticatedBackend();
 
   const abortWithdrawal = async (id: string): Promise<HttpResponseOk<void>> => {
-    const res = await request<void>(`access-api/withdrawals/${id}/abort`, {
+    const res = await request<void>(`accounts/withdrawals/${id}/abort`, {
       method: "POST",
       contentType: "json",
     });
@@ -104,7 +104,7 @@ export function useAccessAnonAPI(): AccessAnonAPI {
   const confirmWithdrawal = async (
     id: string,
   ): Promise<HttpResponseOk<void>> => {
-    const res = await request<void>(`access-api/withdrawals/${id}/confirm`, {
+    const res = await request<void>(`withdrawals/${id}/confirm`, {
       method: "POST",
       contentType: "json",
     });
@@ -122,10 +122,10 @@ export function useTestingAPI(): TestingAPI {
   const mutateAll = useMatchMutate();
   const { request: noAuthRequest } = usePublicBackend();
   const register = async (
-    data: SandboxBackend.Access.BankRegistrationRequest,
+    data: SandboxBackend.CoreBank.RegisterAccountRequest,
   ): Promise<HttpResponseOk<void>> => {
     // FIXME: This API is deprecated.  The normal account registration API should be used instead.
-    const res = await noAuthRequest<void>(`access-api/testing/register`, {
+    const res = await noAuthRequest<void>(`accounts`, {
       method: "POST",
       data,
       contentType: "json",
@@ -139,18 +139,18 @@ export function useTestingAPI(): TestingAPI {
 
 export interface TestingAPI {
   register: (
-    data: SandboxBackend.Access.BankRegistrationRequest,
+    data: SandboxBackend.CoreBank.RegisterAccountRequest,
   ) => Promise<HttpResponseOk<void>>;
 }
 
 export interface AccessAPI {
   createWithdrawal: (
-    data: SandboxBackend.Access.BankAccountCreateWithdrawalRequest,
+    data: SandboxBackend.CoreBank.BankAccountCreateWithdrawalRequest,
   ) => Promise<
-    HttpResponseOk<SandboxBackend.Access.BankAccountCreateWithdrawalResponse>
+    HttpResponseOk<SandboxBackend.CoreBank.BankAccountCreateWithdrawalResponse>
   >;
   createTransaction: (
-    data: SandboxBackend.Access.CreateBankAccountTransactionCreate,
+    data: SandboxBackend.CoreBank.CreateBankAccountTransactionCreate,
   ) => Promise<HttpResponseOk<void>>;
   deleteAccount: () => Promise<HttpResponseOk<void>>;
 }
@@ -167,15 +167,15 @@ export interface InstanceTemplateFilter {
 export function useAccountDetails(
   account: string,
 ): HttpResponse<
-  SandboxBackend.Access.BankAccountBalanceResponse,
+  SandboxBackend.CoreBank.AccountData,
   SandboxBackend.SandboxError
 > {
   const { fetcher } = useAuthenticatedBackend();
 
   const { data, error } = useSWR<
-    HttpResponseOk<SandboxBackend.Access.BankAccountBalanceResponse>,
+    HttpResponseOk<SandboxBackend.CoreBank.AccountData>,
     RequestError<SandboxBackend.SandboxError>
-  >([`access-api/accounts/${account}`], fetcher, {
+  >([`accounts/${account}`], fetcher, {
     refreshInterval: 0,
     refreshWhenHidden: false,
     revalidateOnFocus: false,
@@ -187,28 +187,8 @@ export function useAccountDetails(
     keepPreviousData: true,
   });
 
-  //FIXME: remove optional when libeufin sandbox has implemented the feature
-  if (data && typeof data.data.debitThreshold === "undefined") {
-    data.data.debitThreshold = "0";
-  }
-  //FIXME: sandbox server should return amount string
   if (data) {
-    const isAmount = Amounts.parse(data.data.debitThreshold);
-    if (isAmount) {
-      //server response with correct format
-      return data;
-    }
-    const { currency } = Amounts.parseOrThrow(data.data.balance.amount);
-    const clone = structuredClone(data);
-
-    const theNumber = Number.parseInt(data.data.debitThreshold, 10);
-    const value = Number.isNaN(theNumber) ? 0 : theNumber;
-    clone.data.debitThreshold = Amounts.stringify({
-      currency,
-      value: value,
-      fraction: 0,
-    });
-    return clone;
+    return data;
   }
   if (error) return error.cause;
   return { loading: true };
@@ -218,15 +198,15 @@ export function useAccountDetails(
 export function useWithdrawalDetails(
   wid: string,
 ): HttpResponse<
-  SandboxBackend.Access.BankAccountGetWithdrawalResponse,
+  SandboxBackend.CoreBank.BankAccountGetWithdrawalResponse,
   SandboxBackend.SandboxError
 > {
   const { fetcher } = useAuthenticatedBackend();
 
   const { data, error } = useSWR<
-    HttpResponseOk<SandboxBackend.Access.BankAccountGetWithdrawalResponse>,
+    HttpResponseOk<SandboxBackend.CoreBank.BankAccountGetWithdrawalResponse>,
     RequestError<SandboxBackend.SandboxError>
-  >([`access-api/withdrawals/${wid}`], fetcher, {
+  >([`withdrawals/${wid}`], fetcher, {
     refreshInterval: 1000,
     refreshWhenHidden: false,
     revalidateOnFocus: false,
@@ -248,15 +228,15 @@ export function useTransactionDetails(
   account: string,
   tid: string,
 ): HttpResponse<
-  SandboxBackend.Access.BankAccountTransactionInfo,
+  SandboxBackend.CoreBank.BankAccountTransactionInfo,
   SandboxBackend.SandboxError
 > {
-  const { fetcher } = useAuthenticatedBackend();
+  const { paginatedFetcher } = useAuthenticatedBackend();
 
   const { data, error } = useSWR<
-    HttpResponseOk<SandboxBackend.Access.BankAccountTransactionInfo>,
+    HttpResponseOk<SandboxBackend.CoreBank.BankAccountTransactionInfo>,
     RequestError<SandboxBackend.SandboxError>
-  >([`access-api/accounts/${account}/transactions/${tid}`], fetcher, {
+  >([`accounts/${account}/transactions/${tid}`], paginatedFetcher, {
     refreshInterval: 0,
     refreshWhenHidden: false,
     revalidateOnFocus: false,
@@ -281,7 +261,7 @@ interface PaginationFilter {
 export function usePublicAccounts(
   args?: PaginationFilter,
 ): HttpResponsePaginated<
-  SandboxBackend.Access.PublicAccountsResponse,
+  SandboxBackend.CoreBank.PublicAccountsResponse,
   SandboxBackend.SandboxError
 > {
   const { paginatedFetcher } = usePublicBackend();
@@ -293,13 +273,13 @@ export function usePublicAccounts(
     error: afterError,
     isValidating: loadingAfter,
   } = useSWR<
-    HttpResponseOk<SandboxBackend.Access.PublicAccountsResponse>,
+    HttpResponseOk<SandboxBackend.CoreBank.PublicAccountsResponse>,
     RequestError<SandboxBackend.SandboxError>
-  >([`access-api/public-accounts`, args?.page, PAGE_SIZE], paginatedFetcher);
+  >([`public-accounts`, args?.page, PAGE_SIZE], paginatedFetcher);
 
   const [lastAfter, setLastAfter] = useState<
     HttpResponse<
-      SandboxBackend.Access.PublicAccountsResponse,
+      SandboxBackend.CoreBank.PublicAccountsResponse,
       SandboxBackend.SandboxError
     >
   >({ loading: true });
@@ -312,7 +292,7 @@ export function usePublicAccounts(
 
   // if the query returns less that we ask, then we have reach the end or beginning
   const isReachingEnd =
-    afterData && afterData.data.publicAccounts.length < PAGE_SIZE;
+    afterData && afterData.data.public_accounts.length < PAGE_SIZE;
   const isReachingStart = false;
 
   const pagination = {
@@ -320,7 +300,7 @@ export function usePublicAccounts(
     isReachingStart,
     loadMore: () => {
       if (!afterData || isReachingEnd) return;
-      if (afterData.data.publicAccounts.length < MAX_RESULT_SIZE) {
+      if (afterData.data.public_accounts.length < MAX_RESULT_SIZE) {
         setPage(page + 1);
       }
     },
@@ -329,12 +309,12 @@ export function usePublicAccounts(
     },
   };
 
-  const publicAccounts = !afterData
+  const public_accounts = !afterData
     ? []
-    : (afterData || lastAfter).data.publicAccounts;
-  if (loadingAfter) return { loading: true, data: { publicAccounts } };
+    : (afterData || lastAfter).data.public_accounts;
+  if (loadingAfter) return { loading: true, data: { public_accounts } };
   if (afterData) {
-    return { ok: true, data: { publicAccounts }, ...pagination };
+    return { ok: true, data: { public_accounts }, ...pagination };
   }
   return { loading: true };
 }
@@ -349,7 +329,7 @@ export function useTransactions(
   account: string,
   args?: PaginationFilter,
 ): HttpResponsePaginated<
-  SandboxBackend.Access.BankAccountTransactionsResponse,
+  SandboxBackend.CoreBank.BankAccountTransactionsResponse,
   SandboxBackend.SandboxError
 > {
   const { paginatedFetcher } = useAuthenticatedBackend();
@@ -361,10 +341,10 @@ export function useTransactions(
     error: afterError,
     isValidating: loadingAfter,
   } = useSWR<
-    HttpResponseOk<SandboxBackend.Access.BankAccountTransactionsResponse>,
+    HttpResponseOk<SandboxBackend.CoreBank.BankAccountTransactionsResponse>,
     RequestError<SandboxBackend.SandboxError>
   >(
-    [`access-api/accounts/${account}/transactions`, args?.page, PAGE_SIZE],
+    [`accounts/${account}/transactions`, args?.page, PAGE_SIZE],
     paginatedFetcher, {
     refreshInterval: 0,
     refreshWhenHidden: false,
@@ -378,7 +358,7 @@ export function useTransactions(
 
   const [lastAfter, setLastAfter] = useState<
     HttpResponse<
-      SandboxBackend.Access.BankAccountTransactionsResponse,
+      SandboxBackend.CoreBank.BankAccountTransactionsResponse,
       SandboxBackend.SandboxError
     >
   >({ loading: true });
diff --git a/packages/demobank-ui/src/hooks/backend.ts b/packages/demobank-ui/src/hooks/backend.ts
index 9d32db4b8..f2be90f08 100644
--- a/packages/demobank-ui/src/hooks/backend.ts
+++ b/packages/demobank-ui/src/hooks/backend.ts
@@ -310,7 +310,7 @@ export function useAuthenticatedBackend(): useBackendType {
     ]): Promise<HttpResponseOk<T>> {
       return requestHandler<T>(baseUrl, endpoint, {
         basicAuth: creds,
-        params: { page, size },
+        params: { delta: size, start: size * page },
       });
     },
     [baseUrl, creds],
diff --git a/packages/demobank-ui/src/hooks/useCredentialsChecker.ts b/packages/demobank-ui/src/hooks/useCredentialsChecker.ts
index b76754ffe..05954348f 100644
--- a/packages/demobank-ui/src/hooks/useCredentialsChecker.ts
+++ b/packages/demobank-ui/src/hooks/useCredentialsChecker.ts
@@ -9,20 +9,25 @@ export function useCredentialsChecker() {
   //while merchant backend doesn't have a login endpoint
   async function requestNewLoginToken(
     username: string,
-    password: AccessToken,
+    password: string,
   ): Promise<LoginResult> {
     const data: LoginTokenRequest = {
-      scope: "write",
+      scope: "readwrite" as "write", //FIX: different than merchant
       duration: {
-        d_us: "forever"
+        // d_us: "forever" //FIX: should return shortest
+        d_us: 1000 * 60 * 60 * 23
       },
       refreshable: true,
     }
     try {
       const response = await request<LoginTokenSuccessResponse>(baseUrl, `accounts/${username}/token`, {
         method: "POST",
-        token: password,
-        data
+        basicAuth: {
+          username: username,
+          password,
+        },
+        data,
+        contentType: "json"
       });
       return { valid: true, token: response.data.token, expiration: response.data.expiration };
     } catch (error) {
diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts
index 81eeb4a03..ba9b85710 100644
--- a/packages/demobank-ui/src/pages/AccountPage/index.ts
+++ b/packages/demobank-ui/src/pages/AccountPage/index.ts
@@ -60,7 +60,7 @@ export namespace State {
 
   export interface InvalidIban {
     status: "invalid-iban",
-    error: HttpResponseOk<SandboxBackend.Access.BankAccountBalanceResponse>;
+    error: HttpResponseOk<SandboxBackend.CoreBank.AccountData>;
   }
 
   export interface UserNotFound {
diff --git a/packages/demobank-ui/src/pages/AccountPage/state.ts b/packages/demobank-ui/src/pages/AccountPage/state.ts
index 1a1475c0d..b12afbf9e 100644
--- a/packages/demobank-ui/src/pages/AccountPage/state.ts
+++ b/packages/demobank-ui/src/pages/AccountPage/state.ts
@@ -40,7 +40,7 @@ export function useComponentState({ account, goToBusinessAccount, goToConfirmOpe
       };
     }
     //logout if there is any error, not if loading
-    backend.logOut();
+    // backend.logOut();
     if (result.status === HttpStatusCode.NotFound) {
       notifyError(i18n.str`Username or account label "${account}" not found`, undefined);
       return {
@@ -55,9 +55,13 @@ export function useComponentState({ account, goToBusinessAccount, goToConfirmOpe
   }
 
   const { data } = result;
-  const balance = Amounts.parseOrThrow(data.balance.amount);
-  const debitThreshold = Amounts.parseOrThrow(data.debitThreshold);
-  const payto = parsePaytoUri(data.paytoUri);
+
+  // FIXME: balance
+  // const balance = Amounts.parseOrThrow(data.balance.amount);
+  const balance = Amounts.parseOrThrow(data.balance);
+
+  const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
+  const payto = parsePaytoUri(data.payto_uri);
 
   if (!payto || !payto.isKnown || (payto.targetType !== "iban" && payto.targetType !== "x-taler-bank")) {
     return {
@@ -66,7 +70,9 @@ export function useComponentState({ account, goToBusinessAccount, goToConfirmOpe
     };
   }
 
-  const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
+  // FIXME: balance
+  const balanceIsDebit = true;
+  // data.balance.credit_debit_indicator == "debit";
   const limit = balanceIsDebit
     ? Amounts.sub(debitThreshold, balance).amount
     : Amounts.add(balance, debitThreshold).amount;
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index 23a815bd8..b3996c5fc 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -27,7 +27,7 @@ import { useSettings } from "../../hooks/settings.js";
 
 export function InvalidIbanView({ error }: State.InvalidIban) {
   return (
-    <div>Payto from server is not valid &quot;{error.data.paytoUri}&quot;</div>
+    <div>Payto from server is not valid &quot;{error.data.payto_uri}&quot;</div>
   );
 }
 
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index 5bfaa63ec..a1414544e 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -458,15 +458,14 @@ function WelcomeAccount({ account }: { account: string }): VNode {
   const result = useAccountDetails(account);
   if (!result.ok) return <div />
 
-  // const account = "Sebastian"
-  const payto = parsePaytoUri(result.data.paytoUri)
+  const payto = parsePaytoUri(result.data.payto_uri)
   if (!payto) return <div />
 
   const accountNumber = !payto.isKnown ? undefined : payto.targetType === "iban" ? payto.iban : payto.targetType === "x-taler-bank" ? payto.account : undefined;
   return <i18n.Translate>
     Welcome,  {account} {accountNumber !== undefined ?
       <span>
-        (<a href={result.data.paytoUri}>{accountNumber}</a> <CopyButton getContent={() => result.data.paytoUri} />)
+        (<a href={result.data.payto_uri}>{accountNumber}</a> <CopyButton getContent={() => result.data.payto_uri} />)
       </span>
       : <Fragment />}!
   </i18n.Translate>
@@ -477,9 +476,12 @@ function AccountBalance({ account }: { account: string }): VNode {
   const result = useAccountDetails(account);
   if (!result.ok) return <div />
 
+  // FIXME: balance
   return <div>
-    {Amounts.currencyOf(result.data.balance.amount)}
+    {Amounts.currencyOf(result.data.balance)}
+    {Amounts.stringifyValue(result.data.balance)}
+    {/* {Amounts.currencyOf(result.data.balance.amount)}
     &nbsp;{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""}
-    {Amounts.stringifyValue(result.data.balance.amount)}
+    {Amounts.stringifyValue(result.data.balance.amount)} */}
   </div>
 }
diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx
index 8d5e1f3b9..d80a57d21 100644
--- a/packages/demobank-ui/src/pages/HomePage.tsx
+++ b/packages/demobank-ui/src/pages/HomePage.tsx
@@ -120,8 +120,8 @@ export function handleNotOkResult(
 ) => VNode {
   return function handleNotOkResult2<T>(
     result:
-      | HttpResponsePaginated<T, SandboxBackend.SandboxError>
-      | HttpResponse<T, SandboxBackend.SandboxError>,
+      | HttpResponsePaginated<T, SandboxBackend.SandboxError | undefined>
+      | HttpResponse<T, SandboxBackend.SandboxError| undefined>,
   ): VNode {
     if (result.loading) return <Loading />;
     if (!result.ok) {
@@ -139,7 +139,7 @@ export function handleNotOkResult(
           notify({
             type: "error",
             title: i18n.str`Could not load due to a client error`,
-            description: errorData.error.description as TranslatedString,
+            description: errorData?.error?.description as TranslatedString,
             debug: JSON.stringify(result),
           });
           break;
@@ -148,7 +148,7 @@ export function handleNotOkResult(
           notify({
             type: "error",
             title: i18n.str`Server returned with error`,
-            description: result.payload.error.description as TranslatedString,
+            description: result.payload?.error?.description as TranslatedString,
             debug: JSON.stringify(result.payload),
           });
           break;
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx
index f6ea0e1d1..0d4bd1261 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -31,12 +31,13 @@ import { useCredentialsCheckerOld } from "../hooks/backend.js";
  */
 export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
   const backend = useBackendContext();
-  const [username, setUsername] = useState<string | undefined>();
+  const currentUser = backend.state.status === "loggedIn" ? backend.state.username : undefined
+  const [username, setUsername] = useState<string | undefined>(currentUser);
   const [password, setPassword] = useState<string | undefined>();
   const { i18n } = useTranslationContext();
-  // const { requestNewLoginToken, refreshLoginToken } = useCredentialsChecker();
+  const { requestNewLoginToken, refreshLoginToken } = useCredentialsChecker();
 
-  const testLogin = useCredentialsCheckerOld();
+  // const testLogin = useCredentialsCheckerOld();
   const ref = useRef<HTMLInputElement>(null);
   useEffect(function focusInput() {
     ref.current?.focus();
@@ -46,8 +47,8 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
   const errors = undefinedIfEmpty({
     username: !username
       ? i18n.str`Missing username`
-      : !USERNAME_REGEX.test(username)
-        ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
+      // : !USERNAME_REGEX.test(username)
+      //   ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
         : undefined,
     password: !password ? i18n.str`Missing password` : undefined,
   }) ?? busy;
@@ -59,19 +60,18 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
   async function doLogin() {
     if (!username || !password) return;
     setBusy({})
-    const testResult = await testLogin(username, password);
-    if (testResult.valid) {
+    const result = await requestNewLoginToken(username, password);
+    if (result.valid) {
       backend.logIn({ username, password });
     } else {
-      if (testResult.requestError) {
-        const { cause } = testResult;
-        switch (cause.type) {
-          case ErrorType.CLIENT: {
-            if (cause.status === HttpStatusCode.Unauthorized) {
-              saveError({
-                title: i18n.str`Wrong credentials for "${username}"`,
-              });
-            } else
+      const { cause } = result;
+      switch (cause.type) {
+        case ErrorType.CLIENT: {
+          if (cause.status === HttpStatusCode.Unauthorized) {
+            saveError({
+              title: i18n.str`Wrong credentials for "${username}"`,
+            });
+          } else
             if (cause.status === HttpStatusCode.NotFound) {
               saveError({
                 title: i18n.str`Account not found`,
@@ -79,50 +79,44 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
             } else {
               saveError({
                 title: i18n.str`Could not load due to a client error`,
-                description: cause.payload.error.description,
+                // description: cause.payload.error.description,
                 debug: JSON.stringify(cause.payload),
               });
             }
-            break;
-          }
-          case ErrorType.SERVER: {
-            saveError({
-              title: i18n.str`Server had a problem, try again later or report.`,
-              description: cause.payload.error.description,
-              debug: JSON.stringify(cause.payload),
-            });
-            break;
-          }
-          case ErrorType.TIMEOUT: {
-            saveError({
-              title: i18n.str`Request timeout, try again later.`,
-            });
-            break;
-          }
-          case ErrorType.UNREADABLE: {
-            saveError({
-              title: i18n.str`Unexpected error.`,
-              description: `Response from ${cause.info?.url} is unreadable, http status: ${cause.status}` as TranslatedString,
-              debug: JSON.stringify(cause),
-            });
-            break;
-          }
-          default: {
-            saveError({
-              title: i18n.str`Unexpected error, please report.`,
-              description: `Diagnostic from ${cause.info?.url} is "${cause.message}"` as TranslatedString,
-              debug: JSON.stringify(cause),
-            });
-            break;
-          }
+          break;
+        }
+        case ErrorType.SERVER: {
+          saveError({
+            title: i18n.str`Server had a problem, try again later or report.`,
+            // description: cause.payload.error.description,
+            debug: JSON.stringify(cause.payload),
+          });
+          break;
+        }
+        case ErrorType.TIMEOUT: {
+          saveError({
+            title: i18n.str`Request timeout, try again later.`,
+          });
+          break;
+        }
+        case ErrorType.UNREADABLE: {
+          saveError({
+            title: i18n.str`Unexpected error.`,
+            description: `Response from ${cause.info?.url} is unreadable, http status: ${cause.status}` as TranslatedString,
+            debug: JSON.stringify(cause),
+          });
+          break;
+        }
+        default: {
+          saveError({
+            title: i18n.str`Unexpected error, please report.`,
+            description: `Diagnostic from ${cause.info?.url} is "${cause.message}"` as TranslatedString,
+            debug: JSON.stringify(cause),
+          });
+          break;
         }
-      } else {
-        saveError({
-          title: i18n.str`Unexpected error, please report.`,
-          debug: JSON.stringify(testResult.error),
-        });
       }
-      backend.logOut();
+      // backend.logOut();
     }
     setPassword(undefined);
     setBusy(undefined)
diff --git a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx b/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx
index 03bdb78b7..680368919 100644
--- a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx
+++ b/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx
@@ -36,8 +36,8 @@ export function PublicHistoriesPage({}: Props): VNode {
   const result = usePublicAccounts();
 
   const [showAccount, setShowAccount] = useState(
-    result.ok && result.data.publicAccounts.length > 0
-      ? result.data.publicAccounts[0].accountLabel
+    result.ok && result.data.public_accounts.length > 0
+      ? result.data.public_accounts[0].account_name
       : undefined,
   );
 
@@ -51,9 +51,9 @@ export function PublicHistoriesPage({}: Props): VNode {
   const accountsBar = [];
 
   // Ask story of all the public accounts.
-  for (const account of data.publicAccounts) {
-    logger.trace("Asking transactions for", account.accountLabel);
-    const isSelected = account.accountLabel == showAccount;
+  for (const account of data.public_accounts) {
+    logger.trace("Asking transactions for", account.account_name);
+    const isSelected = account.account_name == showAccount;
     accountsBar.push(
       <li
         class={
@@ -65,13 +65,13 @@ export function PublicHistoriesPage({}: Props): VNode {
         <a
           href="#"
           class="pure-menu-link"
-          onClick={() => setShowAccount(account.accountLabel)}
+          onClick={() => setShowAccount(account.account_name)}
         >
-          {account.accountLabel}
+          {account.account_name}
         </a>
       </li>,
     );
-    txs[account.accountLabel] = <Transactions account={account.accountLabel} />;
+    txs[account.account_name] = <Transactions account={account.account_name} />;
   }
 
   return (
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index f972e0380..8221457bf 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -53,6 +53,7 @@ export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9-]*$/;
 function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
   const backend = useBackendContext();
   const [username, setUsername] = useState<string | undefined>();
+  const [name, setName] = useState<string | undefined>();
   const [password, setPassword] = useState<string | undefined>();
   const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
 
@@ -60,6 +61,9 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
   const { i18n } = useTranslationContext();
 
   const errors = undefinedIfEmpty({
+    name: !name
+      ? i18n.str`Missing name`
+      : undefined,
     username: !username
       ? i18n.str`Missing username`
       : !USERNAME_REGEX.test(username)
@@ -74,9 +78,9 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
   });
 
   async function doRegistrationStep() {
-    if (!username || !password) return;
+    if (!username || !password || !name) return;
     try {
-      await register({ username, password });
+      await register({ name, username, password });
       setUsername(undefined);
       backend.logIn({ username, password });
       onComplete();
@@ -97,13 +101,13 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
             ? error.message
             : JSON.stringify(error)) as TranslatedString
         )
-}
+      }
     }
     setPassword(undefined);
     setRepeatPassword(undefined);
-}
+  }
 
-  async function delay(ms: number):Promise<void> {
+  async function delay(ms: number): Promise<void> {
     return new Promise((resolve) => {
       setTimeout(() => {
         resolve(undefined);
@@ -117,14 +121,15 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
       setUsername(undefined);
       setPassword(undefined);
       setRepeatPassword(undefined);
-      await register({ username: user, password: pass });
-      backend.logIn({ username: user, password: pass });
+      const username = `_${user.first}-${user.second}_`
+      await register({ username, name: `${user.first} ${user.second}`, password: pass });
+      backend.logIn({ username, password: pass });
       onComplete();
     } catch (error) {
       if (error instanceof RequestError) {
         if (tries > 0) {
           await delay(200)
-          await doRandomRegistration(tries-1)
+          await doRandomRegistration(tries - 1)
         } else {
           notify(
             buildRequestErrorMessage(i18n, error.cause, {
@@ -142,7 +147,7 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
             ? error.message
             : JSON.stringify(error)) as TranslatedString
         )
-}
+      }
     }
   }
 
@@ -257,17 +262,19 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode {
 
           </form>
 
-          <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"
-              onClick={(e) => {
-                e.preventDefault()
-                doRandomRegistration()
-              }}
-            >
-              <i18n.Translate>Create a random user</i18n.Translate>
-            </button>
-          </p>
+          {bankUiSettings.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"
+                onClick={(e) => {
+                  e.preventDefault()
+                  doRandomRegistration()
+                }}
+              >
+                <i18n.Translate>Create a random user</i18n.Translate>
+              </button>
+            </p>
+          }
         </div>
       </div>
 
diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
index 8dbdd9da6..e16825527 100644
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
@@ -59,27 +59,41 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
   }, [focus]);
 
   if (!!settings.currentWithdrawalOperationId) {
-    return <div class="rounded-md bg-yellow-50 ring-yellow-2 p-4">
-      <div class="flex">
-        <div class="flex-shrink-0">
-          <svg class="h-5 w-5 text-yellow-300" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-            <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
-          </svg>
-        </div>
-        <div class="ml-3">
-          <h3 class="text-sm font-bold text-yellow-800">
-            <i18n.Translate>There is an operation already</i18n.Translate>
-          </h3>
-          <div class="mt-2 text-sm text-yellow-700">
-            <p>
-              <i18n.Translate>
-                To complete or cancel the operation click <a class="font-semibold text-yellow-700 hover:text-yellow-600" href={`#/operation/${settings.currentWithdrawalOperationId}`}>here</a>
-              </i18n.Translate>
-            </p>
+    return <div>
+
+      <div class="rounded-md bg-yellow-50 ring-yellow-2 p-4">
+        <div class="flex">
+          <div class="flex-shrink-0">
+            <svg class="h-5 w-5 text-yellow-300" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
+            </svg>
+          </div>
+          <div class="ml-3">
+            <h3 class="text-sm font-bold text-yellow-800">
+              <i18n.Translate>There is an operation already</i18n.Translate>
+            </h3>
+            <div class="mt-2 text-sm text-yellow-700">
+              <p>
+                <i18n.Translate>
+                  To complete or cancel the operation click <a class="font-semibold text-yellow-700 hover:text-yellow-600" href={`#/operation/${settings.currentWithdrawalOperationId}`}>here</a>
+                </i18n.Translate>
+              </p>
+            </div>
+
+          </div>
         </div>
+      </div >
+      <div class="flex justify-end gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8 " >
+        <button type="button" class="text-sm font-semibold leading-6 text-gray-900 bg-white p-2 rounded-sm"
+          onClick={() => {
+            updateSettings("currentWithdrawalOperationId", undefined)
+            onCancel()
+          }}
+        >
+          <i18n.Translate>Cancel</i18n.Translate>
+        </button>
       </div>
     </div>
-  </div >
   }
 
   const trimmedAmountStr = amountStr?.trim();
diff --git a/packages/demobank-ui/src/pages/admin/Account.tsx b/packages/demobank-ui/src/pages/admin/Account.tsx
index 90ddd611d..d368c4319 100644
--- a/packages/demobank-ui/src/pages/admin/Account.tsx
+++ b/packages/demobank-ui/src/pages/admin/Account.tsx
@@ -16,9 +16,14 @@ export function AdminAccount({ onRegister }: { onRegister: () => void }): VNode
     return handleNotOkResult(i18n, onRegister)(result);
   }
   const { data } = result;
-  const balance = Amounts.parseOrThrow(data.balance.amount);
-  const debitThreshold = Amounts.parseOrThrow(result.data.debitThreshold);
-  const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+
+  //FIXME: libeufin does not follow the spec
+  const balance = Amounts.parseOrThrow(data.balance);
+  const balanceIsDebit = true;
+  // const balance = Amounts.parseOrThrow(data.balance.amount);
+  // const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+  
+  const debitThreshold = Amounts.parseOrThrow(result.data.debit_threshold);
   const limit = balanceIsDebit
     ? Amounts.sub(debitThreshold, balance).amount
     : Amounts.add(balance, debitThreshold).amount;
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index 1e5370afc..63a7c79f3 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -41,7 +41,9 @@ export function RemoveAccount({
     if (focus) ref.current?.focus();
   }, [focus]);
 
-  const balance = Amounts.parse(result.data.balance.amount);
+  //FIXME: libeufin does not follow the spec
+  const balance = Amounts.parse(result.data.balance);
+  // const balance = Amounts.parse(result.data.balance.amount);
   if (!balance) {
     return <div>there was an error reading the balance</div>;
   }
diff --git a/packages/demobank-ui/src/pages/business/Home.tsx b/packages/demobank-ui/src/pages/business/Home.tsx
index f5f77a3ea..427cfc656 100644
--- a/packages/demobank-ui/src/pages/business/Home.tsx
+++ b/packages/demobank-ui/src/pages/business/Home.tsx
@@ -201,13 +201,13 @@ function useRatiosAndFeeConfigWithChangeDetection(): HttpResponse<
     (result.data.name !== oldResult.name ||
       result.data.version !== oldResult.version ||
       result.data.ratios_and_fees.buy_at_ratio !==
-        oldResult.ratios_and_fees.buy_at_ratio ||
+      oldResult.ratios_and_fees.buy_at_ratio ||
       result.data.ratios_and_fees.buy_in_fee !==
-        oldResult.ratios_and_fees.buy_in_fee ||
+      oldResult.ratios_and_fees.buy_in_fee ||
       result.data.ratios_and_fees.sell_at_ratio !==
-        oldResult.ratios_and_fees.sell_at_ratio ||
+      oldResult.ratios_and_fees.sell_at_ratio ||
       result.data.ratios_and_fees.sell_out_fee !==
-        oldResult.ratios_and_fees.sell_out_fee ||
+      oldResult.ratios_and_fees.sell_out_fee ||
       result.data.fiat_currency !== oldResult.fiat_currency);
 
   return {
@@ -236,10 +236,14 @@ function CreateCashout({
   if (!ratiosResult.ok) return onLoadNotOk(ratiosResult);
   const config = ratiosResult.data;
 
-  const balance = Amounts.parseOrThrow(result.data.balance.amount);
-  const debitThreshold = Amounts.parseOrThrow(result.data.debitThreshold);
+  //FIXME: libeufin does not follow the spec
+  const balance = Amounts.parseOrThrow(result.data.balance);
+  const balanceIsDebit = true;
+  // const balance = Amounts.parseOrThrow(result.data.balance.amount);
+  // const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+
+  const debitThreshold = Amounts.parseOrThrow(result.data.debit_threshold);
   const zero = Amounts.zeroOfCurrency(balance.currency);
-  const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
   const limit = balanceIsDebit
     ? Amounts.sub(debitThreshold, balance).amount
     : Amounts.add(balance, debitThreshold).amount;
@@ -250,15 +254,14 @@ function CreateCashout({
   const sellFee = !config.ratios_and_fees.sell_out_fee
     ? zero
     : Amounts.parseOrThrow(
-        `${balance.currency}:${config.ratios_and_fees.sell_out_fee}`,
-      );
+      `${balance.currency}:${config.ratios_and_fees.sell_out_fee}`,
+    );
   const fiatCurrency = config.fiat_currency;
 
   if (!sellRate || sellRate < 0) return <div>error rate</div>;
 
   const amount = Amounts.parseOrThrow(
-    `${!form.isDebit ? fiatCurrency : balance.currency}:${
-      !form.amount ? "0" : form.amount
+    `${!form.isDebit ? fiatCurrency : balance.currency}:${!form.amount ? "0" : form.amount
     }`,
   );
 
@@ -273,10 +276,10 @@ function CreateCashout({
             error instanceof RequestError
               ? buildRequestErrorMessage(i18n, error.cause)
               : {
-                  type: "error",
-                  title: i18n.str`Could not estimate the cashout`,
-                  description: error.message as TranslatedString
-                },
+                type: "error",
+                title: i18n.str`Could not estimate the cashout`,
+                description: error.message as TranslatedString
+              },
           );
         });
     } else {
@@ -289,10 +292,10 @@ function CreateCashout({
             error instanceof RequestError
               ? buildRequestErrorMessage(i18n, error.cause)
               : {
-                  type: "error",
-                  title: i18n.str`Could not estimate the cashout`,
-                  description: error.message,
-                },
+                type: "error",
+                title: i18n.str`Could not estimate the cashout`,
+                description: error.message,
+              },
           );
         });
     }
@@ -307,14 +310,14 @@ function CreateCashout({
     amount: !form.amount
       ? i18n.str`required`
       : !amount
-      ? i18n.str`could not be parsed`
-      : Amounts.cmp(limit, calc.debit) === -1
-      ? i18n.str`balance is not enough`
-      : Amounts.cmp(calc.beforeFee, sellFee) === -1
-      ? i18n.str`the total amount to transfer does not cover the fees`
-      : Amounts.isZero(calc.credit)
-      ? i18n.str`the total transfer at destination will be zero`
-      : undefined,
+        ? i18n.str`could not be parsed`
+        : Amounts.cmp(limit, calc.debit) === -1
+          ? i18n.str`balance is not enough`
+          : Amounts.cmp(calc.beforeFee, sellFee) === -1
+            ? i18n.str`the total amount to transfer does not cover the fees`
+            : Amounts.isZero(calc.credit)
+              ? i18n.str`the total transfer at destination will be zero`
+              : undefined,
     channel: !form.channel ? i18n.str`required` : undefined,
   });
 
@@ -341,7 +344,7 @@ function CreateCashout({
             {form.isDebit
               ? i18n.str`Amount to send`
               : i18n.str`Amount to receive`}
-            
+
           </label>
           <div style={{ display: "flex" }}>
             <Amount
@@ -520,12 +523,12 @@ function CreateCashout({
                         status === HttpStatusCode.BadRequest
                           ? i18n.str`The exchange rate was incorrectly applied`
                           : status === HttpStatusCode.Forbidden
-                          ? i18n.str`A institutional user tried the operation`
-                          : status === HttpStatusCode.Conflict
-                          ? i18n.str`Need a contact data where to send the TAN`
-                          : status === HttpStatusCode.PreconditionFailed
-                          ? i18n.str`The account does not have sufficient funds`
-                          : undefined,
+                            ? i18n.str`A institutional user tried the operation`
+                            : status === HttpStatusCode.Conflict
+                              ? i18n.str`Need a contact data where to send the TAN`
+                              : status === HttpStatusCode.PreconditionFailed
+                                ? i18n.str`The account does not have sufficient funds`
+                                : undefined,
                       onServerError: (status) =>
                         status === HttpStatusCode.ServiceUnavailable
                           ? i18n.str`The bank does not support the TAN channel for this operation`
@@ -539,7 +542,7 @@ function CreateCashout({
                       ? error.message
                       : JSON.stringify(error)) as TranslatedString
                   )
-            }
+                }
               }
             }}
           >
@@ -665,8 +668,8 @@ export function ShowCashoutDetails({
                           status === HttpStatusCode.NotFound
                             ? i18n.str`Cashout not found. It may be also mean that it was already aborted.`
                             : status === HttpStatusCode.PreconditionFailed
-                            ? i18n.str`Cashout was already confimed`
-                            : undefined,
+                              ? i18n.str`Cashout was already confimed`
+                              : undefined,
                       }),
                     );
                   } else {
@@ -676,7 +679,7 @@ export function ShowCashoutDetails({
                         ? error.message
                         : JSON.stringify(error)) as TranslatedString
                     )
-                }
+                  }
                 }
               }}
             >
@@ -702,12 +705,12 @@ export function ShowCashoutDetails({
                           status === HttpStatusCode.NotFound
                             ? i18n.str`Cashout not found. It may be also mean that it was already aborted.`
                             : status === HttpStatusCode.PreconditionFailed
-                            ? i18n.str`Cashout was already confimed`
-                            : status === HttpStatusCode.Conflict
-                            ? i18n.str`Confirmation failed. Maybe the user changed their cash-out address between the creation and the confirmation`
-                            : status === HttpStatusCode.Forbidden
-                            ? i18n.str`Invalid code`
-                            : undefined,
+                              ? i18n.str`Cashout was already confimed`
+                              : status === HttpStatusCode.Conflict
+                                ? i18n.str`Confirmation failed. Maybe the user changed their cash-out address between the creation and the confirmation`
+                                : status === HttpStatusCode.Forbidden
+                                  ? i18n.str`Invalid code`
+                                  : undefined,
                       }),
                     );
                   } else {
@@ -717,7 +720,7 @@ export function ShowCashoutDetails({
                         ? error.message
                         : JSON.stringify(error)) as TranslatedString
                     )
-                }
+                  }
                 }
               }}
             >
diff --git a/packages/demobank-ui/src/pages/rnd.ts b/packages/demobank-ui/src/pages/rnd.ts
index 8c9bae875..32c3a934f 100644
--- a/packages/demobank-ui/src/pages/rnd.ts
+++ b/packages/demobank-ui/src/pages/rnd.ts
@@ -1,2890 +1,2895 @@
 import { createEddsaKeyPair, encodeCrock, getRandomBytes } from "@gnu-taler/taler-util"
+import { bankUiSettings } from "../settings.js"
 
 
 const noun = [
-    "people",
-    "history",
-    "way",
-    "art",
-    "world",
-    "information",
-    "map",
-    "two",
-    "family",
-    "government",
-    "health",
-    "system",
-    "computer",
-    "meat",
-    "year",
-    "thanks",
-    "music",
-    "person",
-    "reading",
-    "method",
-    "data",
-    "food",
-    "understanding",
-    "theory",
-    "law",
-    "bird",
-    "literature",
-    "problem",
-    "software",
-    "control",
-    "knowledge",
-    "power",
-    "ability",
-    "economics",
-    "love",
-    "internet",
-    "television",
-    "science",
-    "library",
-    "nature",
-    "fact",
-    "product",
-    "idea",
-    "temperature",
-    "investment",
-    "area",
-    "society",
-    "activity",
-    "story",
-    "industry",
-    "media",
-    "thing",
-    "oven",
-    "community",
-    "definition",
-    "safety",
-    "quality",
-    "development",
-    "language",
-    "management",
-    "player",
-    "variety",
-    "video",
-    "week",
-    "security",
-    "country",
-    "exam",
-    "movie",
-    "organization",
-    "equipment",
-    "physics",
-    "analysis",
-    "policy",
-    "series",
-    "thought",
-    "basis",
-    "boyfriend",
-    "direction",
-    "strategy",
-    "technology",
-    "army",
-    "camera",
-    "freedom",
-    "paper",
-    "environment",
-    "child",
-    "instance",
-    "month",
-    "truth",
-    "marketing",
-    "university",
-    "writing",
-    "article",
-    "department",
-    "difference",
-    "goal",
-    "news",
-    "audience",
-    "fishing",
-    "growth",
-    "income",
-    "marriage",
-    "user",
-    "combination",
-    "failure",
-    "meaning",
-    "medicine",
-    "philosophy",
-    "teacher",
-    "communication",
-    "night",
-    "chemistry",
-    "disease",
-    "disk",
-    "energy",
-    "nation",
-    "road",
-    "role",
-    "soup",
-    "advertising",
-    "location",
-    "success",
-    "addition",
-    "apartment",
-    "education",
-    "math",
-    "moment",
-    "painting",
-    "politics",
-    "attention",
-    "decision",
-    "event",
-    "property",
-    "shopping",
-    "student",
-    "wood",
-    "competition",
-    "distribution",
-    "entertainment",
-    "office",
-    "population",
-    "president",
-    "unit",
-    "category",
-    "cigarette",
-    "context",
-    "introduction",
-    "opportunity",
-    "performance",
-    "driver",
-    "flight",
-    "length",
-    "magazine",
-    "newspaper",
-    "relationship",
-    "teaching",
-    "cell",
-    "dealer",
-    "finding",
-    "lake",
-    "member",
-    "message",
-    "phone",
-    "scene",
-    "appearance",
-    "association",
-    "concept",
-    "customer",
-    "death",
-    "discussion",
-    "housing",
-    "inflation",
-    "insurance",
-    "mood",
-    "woman",
-    "advice",
-    "blood",
-    "effort",
-    "expression",
-    "importance",
-    "opinion",
-    "payment",
-    "reality",
-    "responsibility",
-    "situation",
-    "skill",
-    "statement",
-    "wealth",
-    "application",
-    "city",
-    "county",
-    "depth",
-    "estate",
-    "foundation",
-    "grandmother",
-    "heart",
-    "perspective",
-    "photo",
-    "recipe",
-    "studio",
-    "topic",
-    "collection",
-    "depression",
-    "imagination",
-    "passion",
-    "percentage",
-    "resource",
-    "setting",
-    "ad",
-    "agency",
-    "college",
-    "connection",
-    "criticism",
-    "debt",
-    "description",
-    "memory",
-    "patience",
-    "secretary",
-    "solution",
-    "administration",
-    "aspect",
-    "attitude",
-    "director",
-    "personality",
-    "psychology",
-    "recommendation",
-    "response",
-    "selection",
-    "storage",
-    "version",
-    "alcohol",
-    "argument",
-    "complaint",
-    "contract",
-    "emphasis",
-    "highway",
-    "loss",
-    "membership",
-    "possession",
-    "preparation",
-    "steak",
-    "union",
-    "agreement",
-    "cancer",
-    "currency",
-    "employment",
-    "engineering",
-    "entry",
-    "interaction",
-    "mixture",
-    "preference",
-    "region",
-    "republic",
-    "tradition",
-    "virus",
-    "actor",
-    "classroom",
-    "delivery",
-    "device",
-    "difficulty",
-    "drama",
-    "election",
-    "engine",
-    "football",
-    "guidance",
-    "hotel",
-    "owner",
-    "priority",
-    "protection",
-    "suggestion",
-    "tension",
-    "variation",
-    "anxiety",
-    "atmosphere",
-    "awareness",
-    "bath",
-    "bread",
-    "candidate",
-    "climate",
-    "comparison",
-    "confusion",
-    "construction",
-    "elevator",
-    "emotion",
-    "employee",
-    "employer",
-    "guest",
-    "height",
-    "leadership",
-    "mall",
-    "manager",
-    "operation",
-    "recording",
-    "sample",
-    "transportation",
-    "charity",
-    "cousin",
-    "disaster",
-    "editor",
-    "efficiency",
-    "excitement",
-    "extent",
-    "feedback",
-    "guitar",
-    "homework",
-    "leader",
-    "mom",
-    "outcome",
-    "permission",
-    "presentation",
-    "promotion",
-    "reflection",
-    "refrigerator",
-    "resolution",
-    "revenue",
-    "session",
-    "singer",
-    "tennis",
-    "basket",
-    "bonus",
-    "cabinet",
-    "childhood",
-    "church",
-    "clothes",
-    "coffee",
-    "dinner",
-    "drawing",
-    "hair",
-    "hearing",
-    "initiative",
-    "judgment",
-    "lab",
-    "measurement",
-    "mode",
-    "mud",
-    "orange",
-    "poetry",
-    "police",
-    "possibility",
-    "procedure",
-    "queen",
-    "ratio",
-    "relation",
-    "restaurant",
-    "satisfaction",
-    "sector",
-    "signature",
-    "significance",
-    "song",
-    "tooth",
-    "town",
-    "vehicle",
-    "volume",
-    "wife",
-    "accident",
-    "airport",
-    "appointment",
-    "arrival",
-    "assumption",
-    "baseball",
-    "chapter",
-    "committee",
-    "conversation",
-    "database",
-    "enthusiasm",
-    "error",
-    "explanation",
-    "farmer",
-    "gate",
-    "girl",
-    "hall",
-    "historian",
-    "hospital",
-    "injury",
-    "instruction",
-    "maintenance",
-    "manufacturer",
-    "meal",
-    "perception",
-    "pie",
-    "poem",
-    "presence",
-    "proposal",
-    "reception",
-    "replacement",
-    "revolution",
-    "river",
-    "son",
-    "speech",
-    "tea",
-    "village",
-    "warning",
-    "winner",
-    "worker",
-    "writer",
-    "assistance",
-    "breath",
-    "buyer",
-    "chest",
-    "chocolate",
-    "conclusion",
-    "contribution",
-    "cookie",
-    "courage",
-    "dad",
-    "desk",
-    "drawer",
-    "establishment",
-    "examination",
-    "garbage",
-    "grocery",
-    "honey",
-    "impression",
-    "improvement",
-    "independence",
-    "insect",
-    "inspection",
-    "inspector",
-    "king",
-    "ladder",
-    "menu",
-    "penalty",
-    "piano",
-    "potato",
-    "profession",
-    "professor",
-    "quantity",
-    "reaction",
-    "requirement",
-    "salad",
-    "sister",
-    "supermarket",
-    "tongue",
-    "weakness",
-    "wedding",
-    "affair",
-    "ambition",
-    "analyst",
-    "apple",
-    "assignment",
-    "assistant",
-    "bathroom",
-    "bedroom",
-    "beer",
-    "birthday",
-    "celebration",
-    "championship",
-    "cheek",
-    "client",
-    "consequence",
-    "departure",
-    "diamond",
-    "dirt",
-    "ear",
-    "fortune",
-    "friendship",
-    "funeral",
-    "gene",
-    "girlfriend",
-    "hat",
-    "indication",
-    "intention",
-    "lady",
-    "midnight",
-    "negotiation",
-    "obligation",
-    "passenger",
-    "pizza",
-    "platform",
-    "poet",
-    "pollution",
-    "recognition",
-    "reputation",
-    "shirt",
-    "sir",
-    "speaker",
-    "stranger",
-    "surgery",
-    "sympathy",
-    "tale",
-    "throat",
-    "trainer",
-    "uncle",
-    "youth",
-    "time",
-    "work",
-    "film",
-    "water",
-    "money",
-    "example",
-    "while",
-    "business",
-    "study",
-    "game",
-    "life",
-    "form",
-    "air",
-    "day",
-    "place",
-    "number",
-    "part",
-    "field",
-    "fish",
-    "back",
-    "process",
-    "heat",
-    "hand",
-    "experience",
-    "job",
-    "book",
-    "end",
-    "point",
-    "type",
-    "home",
-    "economy",
-    "value",
-    "body",
-    "market",
-    "guide",
-    "interest",
-    "state",
-    "radio",
-    "course",
-    "company",
-    "price",
-    "size",
-    "card",
-    "list",
-    "mind",
-    "trade",
-    "line",
-    "care",
-    "group",
-    "risk",
-    "word",
-    "fat",
-    "force",
-    "key",
-    "light",
-    "training",
-    "name",
-    "school",
-    "top",
-    "amount",
-    "level",
-    "order",
-    "practice",
-    "research",
-    "sense",
-    "service",
-    "piece",
-    "web",
-    "boss",
-    "sport",
-    "fun",
-    "house",
-    "page",
-    "term",
-    "test",
-    "answer",
-    "sound",
-    "focus",
-    "matter",
-    "kind",
-    "soil",
-    "board",
-    "oil",
-    "picture",
-    "access",
-    "garden",
-    "range",
-    "rate",
-    "reason",
-    "future",
-    "site",
-    "demand",
-    "exercise",
-    "image",
-    "case",
-    "cause",
-    "coast",
-    "action",
-    "age",
-    "bad",
-    "boat",
-    "record",
-    "result",
-    "section",
-    "building",
-    "mouse",
-    "cash",
-    "class",
-    "nothing",
-    "period",
-    "plan",
-    "store",
-    "tax",
-    "side",
-    "subject",
-    "space",
-    "rule",
-    "stock",
-    "weather",
-    "chance",
-    "figure",
-    "man",
-    "model",
-    "source",
-    "beginning",
-    "earth",
-    "program",
-    "chicken",
-    "design",
-    "feature",
-    "head",
-    "material",
-    "purpose",
-    "question",
-    "rock",
-    "salt",
-    "act",
-    "birth",
-    "car",
-    "dog",
-    "object",
-    "scale",
-    "sun",
-    "note",
-    "profit",
-    "rent",
-    "speed",
-    "style",
-    "war",
-    "bank",
-    "craft",
-    "half",
-    "inside",
-    "outside",
-    "standard",
-    "bus",
-    "exchange",
-    "eye",
-    "fire",
-    "position",
-    "pressure",
-    "stress",
-    "advantage",
-    "benefit",
-    "box",
-    "frame",
-    "issue",
-    "step",
-    "cycle",
-    "face",
-    "item",
-    "metal",
-    "paint",
-    "review",
-    "room",
-    "screen",
-    "structure",
-    "view",
-    "account",
-    "ball",
-    "discipline",
-    "medium",
-    "share",
-    "balance",
-    "bit",
-    "black",
-    "bottom",
-    "choice",
-    "gift",
-    "impact",
-    "machine",
-    "shape",
-    "tool",
-    "wind",
-    "address",
-    "average",
-    "career",
-    "culture",
-    "morning",
-    "pot",
-    "sign",
-    "table",
-    "task",
-    "condition",
-    "contact",
-    "credit",
-    "egg",
-    "hope",
-    "ice",
-    "network",
-    "north",
-    "square",
-    "attempt",
-    "date",
-    "effect",
-    "link",
-    "post",
-    "star",
-    "voice",
-    "capital",
-    "challenge",
-    "friend",
-    "self",
-    "shot",
-    "brush",
-    "couple",
-    "debate",
-    "exit",
-    "front",
-    "function",
-    "lack",
-    "living",
-    "plant",
-    "plastic",
-    "spot",
-    "summer",
-    "taste",
-    "theme",
-    "track",
-    "wing",
-    "brain",
-    "button",
-    "click",
-    "desire",
-    "foot",
-    "gas",
-    "influence",
-    "notice",
-    "rain",
-    "wall",
-    "base",
-    "damage",
-    "distance",
-    "feeling",
-    "pair",
-    "savings",
-    "staff",
-    "sugar",
-    "target",
-    "text",
-    "animal",
-    "author",
-    "budget",
-    "discount",
-    "file",
-    "ground",
-    "lesson",
-    "minute",
-    "officer",
-    "phase",
-    "reference",
-    "register",
-    "sky",
-    "stage",
-    "stick",
-    "title",
-    "trouble",
-    "bowl",
-    "bridge",
-    "campaign",
-    "character",
-    "club",
-    "edge",
-    "evidence",
-    "fan",
-    "letter",
-    "lock",
-    "maximum",
-    "novel",
-    "option",
-    "pack",
-    "park",
-    "plenty",
-    "quarter",
-    "skin",
-    "sort",
-    "weight",
-    "baby",
-    "background",
-    "carry",
-    "dish",
-    "factor",
-    "fruit",
-    "glass",
-    "joint",
-    "master",
-    "muscle",
-    "red",
-    "strength",
-    "traffic",
-    "trip",
-    "vegetable",
-    "appeal",
-    "chart",
-    "gear",
-    "ideal",
-    "kitchen",
-    "land",
-    "log",
-    "mother",
-    "net",
-    "party",
-    "principle",
-    "relative",
-    "sale",
-    "season",
-    "signal",
-    "spirit",
-    "street",
-    "tree",
-    "wave",
-    "belt",
-    "bench",
-    "commission",
-    "copy",
-    "drop",
-    "minimum",
-    "path",
-    "progress",
-    "project",
-    "sea",
-    "south",
-    "status",
-    "stuff",
-    "ticket",
-    "tour",
-    "angle",
-    "blue",
-    "breakfast",
-    "confidence",
-    "daughter",
-    "degree",
-    "doctor",
-    "dot",
-    "dream",
-    "duty",
-    "essay",
-    "father",
-    "fee",
-    "finance",
-    "hour",
-    "juice",
-    "limit",
-    "luck",
-    "milk",
-    "mouth",
-    "peace",
-    "pipe",
-    "seat",
-    "stable",
-    "storm",
-    "substance",
-    "team",
-    "trick",
-    "afternoon",
-    "bat",
-    "beach",
-    "blank",
-    "catch",
-    "chain",
-    "consideration",
-    "cream",
-    "crew",
-    "detail",
-    "gold",
-    "interview",
-    "kid",
-    "mark",
-    "match",
-    "mission",
-    "pain",
-    "pleasure",
-    "score",
-    "screw",
-    "sex",
-    "shop",
-    "shower",
-    "suit",
-    "tone",
-    "window",
-    "agent",
-    "band",
-    "block",
-    "bone",
-    "calendar",
-    "cap",
-    "coat",
-    "contest",
-    "corner",
-    "court",
-    "cup",
-    "district",
-    "door",
-    "east",
-    "finger",
-    "garage",
-    "guarantee",
-    "hole",
-    "hook",
-    "implement",
-    "layer",
-    "lecture",
-    "lie",
-    "manner",
-    "meeting",
-    "nose",
-    "parking",
-    "partner",
-    "profile",
-    "respect",
-    "rice",
-    "routine",
-    "schedule",
-    "swimming",
-    "telephone",
-    "tip",
-    "winter",
-    "airline",
-    "bag",
-    "battle",
-    "bed",
-    "bill",
-    "bother",
-    "cake",
-    "code",
-    "curve",
-    "designer",
-    "dimension",
-    "dress",
-    "ease",
-    "emergency",
-    "evening",
-    "extension",
-    "farm",
-    "fight",
-    "gap",
-    "grade",
-    "holiday",
-    "horror",
-    "horse",
-    "host",
-    "husband",
-    "loan",
-    "mistake",
-    "mountain",
-    "nail",
-    "noise",
-    "occasion",
-    "package",
-    "patient",
-    "pause",
-    "phrase",
-    "proof",
-    "race",
-    "relief",
-    "sand",
-    "sentence",
-    "shoulder",
-    "smoke",
-    "stomach",
-    "string",
-    "tourist",
-    "towel",
-    "vacation",
-    "west",
-    "wheel",
-    "wine",
-    "arm",
-    "aside",
-    "associate",
-    "bet",
-    "blow",
-    "border",
-    "branch",
-    "breast",
-    "brother",
-    "buddy",
-    "bunch",
-    "chip",
-    "coach",
-    "cross",
-    "document",
-    "draft",
-    "dust",
-    "expert",
-    "floor",
-    "god",
-    "golf",
-    "habit",
-    "iron",
-    "judge",
-    "knife",
-    "landscape",
-    "league",
-    "mail",
-    "mess",
-    "native",
-    "opening",
-    "parent",
-    "pattern",
-    "pin",
-    "pool",
-    "pound",
-    "request",
-    "salary",
-    "shame",
-    "shelter",
-    "shoe",
-    "silver",
-    "tackle",
-    "tank",
-    "trust",
-    "assist",
-    "bake",
-    "bar",
-    "bell",
-    "bike",
-    "blame",
-    "boy",
-    "brick",
-    "chair",
-    "closet",
-    "clue",
-    "collar",
-    "comment",
-    "conference",
-    "devil",
-    "diet",
-    "fear",
-    "fuel",
-    "glove",
-    "jacket",
-    "lunch",
-    "monitor",
-    "mortgage",
-    "nurse",
-    "pace",
-    "panic",
-    "peak",
-    "plane",
-    "reward",
-    "row",
-    "sandwich",
-    "shock",
-    "spite",
-    "spray",
-    "surprise",
-    "till",
-    "transition",
-    "weekend",
-    "welcome",
-    "yard",
-    "alarm",
-    "bend",
-    "bicycle",
-    "bite",
-    "blind",
-    "bottle",
-    "cable",
-    "candle",
-    "clerk",
-    "cloud",
-    "concert",
-    "counter",
-    "flower",
-    "grandfather",
-    "harm",
-    "knee",
-    "lawyer",
-    "leather",
-    "load",
-    "mirror",
-    "neck",
-    "pension",
-    "plate",
-    "purple",
-    "ruin",
-    "ship",
-    "skirt",
-    "slice",
-    "snow",
-    "specialist",
-    "stroke",
-    "switch",
-    "trash",
-    "tune",
-    "zone",
-    "anger",
-    "award",
-    "bid",
-    "bitter",
-    "boot",
-    "bug",
-    "camp",
-    "candy",
-    "carpet",
-    "cat",
-    "champion",
-    "channel",
-    "clock",
-    "comfort",
-    "cow",
-    "crack",
-    "engineer",
-    "entrance",
-    "fault",
-    "grass",
-    "guy",
-    "hell",
-    "highlight",
-    "incident",
-    "island",
-    "joke",
-    "jury",
-    "leg",
-    "lip",
-    "mate",
-    "motor",
-    "nerve",
-    "passage",
-    "pen",
-    "pride",
-    "priest",
-    "prize",
-    "promise",
-    "resident",
-    "resort",
-    "ring",
-    "roof",
-    "rope",
-    "sail",
-    "scheme",
-    "script",
-    "sock",
-    "station",
-    "toe",
-    "tower",
-    "truck",
-    "witness",
-    "a",
-    "you",
-    "it",
-    "can",
-    "will",
-    "if",
-    "one",
-    "many",
-    "most",
-    "other",
-    "use",
-    "make",
-    "good",
-    "look",
-    "help",
-    "go",
-    "great",
-    "being",
-    "few",
-    "might",
-    "still",
-    "public",
-    "read",
-    "keep",
-    "start",
-    "give",
-    "human",
-    "local",
-    "general",
-    "she",
-    "specific",
-    "long",
-    "play",
-    "feel",
-    "high",
-    "tonight",
-    "put",
-    "common",
-    "set",
-    "change",
-    "simple",
-    "past",
-    "big",
-    "possible",
-    "particular",
-    "today",
-    "major",
-    "personal",
-    "current",
-    "national",
-    "cut",
-    "natural",
-    "physical",
-    "show",
-    "try",
-    "check",
-    "second",
-    "call",
-    "move",
-    "pay",
-    "let",
-    "increase",
-    "single",
-    "individual",
-    "turn",
-    "ask",
-    "buy",
-    "guard",
-    "hold",
-    "main",
-    "offer",
-    "potential",
-    "professional",
-    "international",
-    "travel",
-    "cook",
-    "alternative",
-    "following",
-    "special",
-    "working",
-    "whole",
-    "dance",
-    "excuse",
-    "cold",
-    "commercial",
-    "low",
-    "purchase",
-    "deal",
-    "primary",
-    "worth",
-    "fall",
-    "necessary",
-    "positive",
-    "produce",
-    "search",
-    "present",
-    "spend",
-    "talk",
-    "creative",
-    "tell",
-    "cost",
-    "drive",
-    "green",
-    "support",
-    "glad",
-    "remove",
-    "return",
-    "run",
-    "complex",
-    "due",
-    "effective",
-    "middle",
-    "regular",
-    "reserve",
-    "independent",
-    "leave",
-    "original",
-    "reach",
-    "rest",
-    "serve",
-    "watch",
-    "beautiful",
-    "charge",
-    "active",
-    "break",
-    "negative",
-    "safe",
-    "stay",
-    "visit",
-    "visual",
-    "affect",
-    "cover",
-    "report",
-    "rise",
-    "walk",
-    "white",
-    "beyond",
-    "junior",
-    "pick",
-    "unique",
-    "anything",
-    "classic",
-    "final",
-    "lift",
-    "mix",
-    "private",
-    "stop",
-    "teach",
-    "western",
-    "concern",
-    "familiar",
-    "fly",
-    "official",
-    "broad",
-    "comfortable",
-    "gain",
-    "maybe",
-    "rich",
-    "save",
-    "stand",
-    "young",
-    "fail",
-    "heavy",
-    "hello",
-    "lead",
-    "listen",
-    "valuable",
-    "worry",
-    "handle",
-    "leading",
-    "meet",
-    "release",
-    "sell",
-    "finish",
-    "normal",
-    "press",
-    "ride",
-    "secret",
-    "spread",
-    "spring",
-    "tough",
-    "wait",
-    "brown",
-    "deep",
-    "display",
-    "flow",
-    "hit",
-    "objective",
-    "shoot",
-    "touch",
-    "cancel",
-    "chemical",
-    "cry",
-    "dump",
-    "extreme",
-    "push",
-    "conflict",
-    "eat",
-    "fill",
-    "formal",
-    "jump",
-    "kick",
-    "opposite",
-    "pass",
-    "pitch",
-    "remote",
-    "total",
-    "treat",
-    "vast",
-    "abuse",
-    "beat",
-    "burn",
-    "deposit",
-    "print",
-    "raise",
-    "sleep",
-    "somewhere",
-    "advance",
-    "anywhere",
-    "consist",
-    "dark",
-    "double",
-    "draw",
-    "equal",
-    "fix",
-    "hire",
-    "internal",
-    "join",
-    "kill",
-    "sensitive",
-    "tap",
-    "win",
-    "attack",
-    "claim",
-    "constant",
-    "drag",
-    "drink",
-    "guess",
-    "minor",
-    "pull",
-    "raw",
-    "soft",
-    "solid",
-    "wear",
-    "weird",
-    "wonder",
-    "annual",
-    "count",
-    "dead",
-    "doubt",
-    "feed",
-    "forever",
-    "impress",
-    "nobody",
-    "repeat",
-    "round",
-    "sing",
-    "slide",
-    "strip",
-    "whereas",
-    "wish",
-    "combine",
-    "command",
-    "dig",
-    "divide",
-    "equivalent",
-    "hang",
-    "hunt",
-    "initial",
-    "march",
-    "mention",
-    "smell",
-    "spiritual",
-    "survey",
-    "tie",
-    "adult",
-    "brief",
-    "crazy",
-    "escape",
-    "gather",
-    "hate",
-    "prior",
-    "repair",
-    "rough",
-    "sad",
-    "scratch",
-    "sick",
-    "strike",
-    "employ",
-    "external",
-    "hurt",
-    "illegal",
-    "laugh",
-    "lay",
-    "mobile",
-    "nasty",
-    "ordinary",
-    "respond",
-    "royal",
-    "senior",
-    "split",
-    "strain",
-    "struggle",
-    "swim",
-    "train",
-    "upper",
-    "wash",
-    "yellow",
-    "convert",
-    "crash",
-    "dependent",
-    "fold",
-    "funny",
-    "grab",
-    "hide",
-    "miss",
-    "permit",
-    "quote",
-    "recover",
-    "resolve",
-    "roll",
-    "sink",
-    "slip",
-    "spare",
-    "suspect",
-    "sweet",
-    "swing",
-    "twist",
-    "upstairs",
-    "usual",
-    "abroad",
-    "brave",
-    "calm",
-    "concentrate",
-    "estimate",
-    "grand",
-    "male",
-    "mine",
-    "prompt",
-    "quiet",
-    "refuse",
-    "regret",
-    "reveal",
-    "rush",
-    "shake",
-    "shift",
-    "shine",
-    "steal",
-    "suck",
-    "surround",
-    "anybody",
-    "bear",
-    "brilliant",
-    "dare",
-    "dear",
-    "delay",
-    "drunk",
-    "female",
-    "hurry",
-    "inevitable",
-    "invite",
-    "kiss",
-    "neat",
-    "pop",
-    "punch",
-    "quit",
-    "reply",
-    "representative",
-    "resist",
-    "rip",
-    "rub",
-    "silly",
-    "smile",
-    "spell",
-    "stretch",
-    "stupid",
-    "tear",
-    "temporary",
-    "tomorrow",
-    "wake",
-    "wrap",
-    "yesterday"
+  "people",
+  "history",
+  "way",
+  "art",
+  "world",
+  "information",
+  "map",
+  "two",
+  "family",
+  "government",
+  "health",
+  "system",
+  "computer",
+  "meat",
+  "year",
+  "thanks",
+  "music",
+  "person",
+  "reading",
+  "method",
+  "data",
+  "food",
+  "understanding",
+  "theory",
+  "law",
+  "bird",
+  "literature",
+  "problem",
+  "software",
+  "control",
+  "knowledge",
+  "power",
+  "ability",
+  "economics",
+  "love",
+  "internet",
+  "television",
+  "science",
+  "library",
+  "nature",
+  "fact",
+  "product",
+  "idea",
+  "temperature",
+  "investment",
+  "area",
+  "society",
+  "activity",
+  "story",
+  "industry",
+  "media",
+  "thing",
+  "oven",
+  "community",
+  "definition",
+  "safety",
+  "quality",
+  "development",
+  "language",
+  "management",
+  "player",
+  "variety",
+  "video",
+  "week",
+  "security",
+  "country",
+  "exam",
+  "movie",
+  "organization",
+  "equipment",
+  "physics",
+  "analysis",
+  "policy",
+  "series",
+  "thought",
+  "basis",
+  "boyfriend",
+  "direction",
+  "strategy",
+  "technology",
+  "army",
+  "camera",
+  "freedom",
+  "paper",
+  "environment",
+  "child",
+  "instance",
+  "month",
+  "truth",
+  "marketing",
+  "university",
+  "writing",
+  "article",
+  "department",
+  "difference",
+  "goal",
+  "news",
+  "audience",
+  "fishing",
+  "growth",
+  "income",
+  "marriage",
+  "user",
+  "combination",
+  "failure",
+  "meaning",
+  "medicine",
+  "philosophy",
+  "teacher",
+  "communication",
+  "night",
+  "chemistry",
+  "disease",
+  "disk",
+  "energy",
+  "nation",
+  "road",
+  "role",
+  "soup",
+  "advertising",
+  "location",
+  "success",
+  "addition",
+  "apartment",
+  "education",
+  "math",
+  "moment",
+  "painting",
+  "politics",
+  "attention",
+  "decision",
+  "event",
+  "property",
+  "shopping",
+  "student",
+  "wood",
+  "competition",
+  "distribution",
+  "entertainment",
+  "office",
+  "population",
+  "president",
+  "unit",
+  "category",
+  "cigarette",
+  "context",
+  "introduction",
+  "opportunity",
+  "performance",
+  "driver",
+  "flight",
+  "length",
+  "magazine",
+  "newspaper",
+  "relationship",
+  "teaching",
+  "cell",
+  "dealer",
+  "finding",
+  "lake",
+  "member",
+  "message",
+  "phone",
+  "scene",
+  "appearance",
+  "association",
+  "concept",
+  "customer",
+  "death",
+  "discussion",
+  "housing",
+  "inflation",
+  "insurance",
+  "mood",
+  "woman",
+  "advice",
+  "blood",
+  "effort",
+  "expression",
+  "importance",
+  "opinion",
+  "payment",
+  "reality",
+  "responsibility",
+  "situation",
+  "skill",
+  "statement",
+  "wealth",
+  "application",
+  "city",
+  "county",
+  "depth",
+  "estate",
+  "foundation",
+  "grandmother",
+  "heart",
+  "perspective",
+  "photo",
+  "recipe",
+  "studio",
+  "topic",
+  "collection",
+  "depression",
+  "imagination",
+  "passion",
+  "percentage",
+  "resource",
+  "setting",
+  "ad",
+  "agency",
+  "college",
+  "connection",
+  "criticism",
+  "debt",
+  "description",
+  "memory",
+  "patience",
+  "secretary",
+  "solution",
+  "administration",
+  "aspect",
+  "attitude",
+  "director",
+  "personality",
+  "psychology",
+  "recommendation",
+  "response",
+  "selection",
+  "storage",
+  "version",
+  "alcohol",
+  "argument",
+  "complaint",
+  "contract",
+  "emphasis",
+  "highway",
+  "loss",
+  "membership",
+  "possession",
+  "preparation",
+  "steak",
+  "union",
+  "agreement",
+  "cancer",
+  "currency",
+  "employment",
+  "engineering",
+  "entry",
+  "interaction",
+  "mixture",
+  "preference",
+  "region",
+  "republic",
+  "tradition",
+  "virus",
+  "actor",
+  "classroom",
+  "delivery",
+  "device",
+  "difficulty",
+  "drama",
+  "election",
+  "engine",
+  "football",
+  "guidance",
+  "hotel",
+  "owner",
+  "priority",
+  "protection",
+  "suggestion",
+  "tension",
+  "variation",
+  "anxiety",
+  "atmosphere",
+  "awareness",
+  "bath",
+  "bread",
+  "candidate",
+  "climate",
+  "comparison",
+  "confusion",
+  "construction",
+  "elevator",
+  "emotion",
+  "employee",
+  "employer",
+  "guest",
+  "height",
+  "leadership",
+  "mall",
+  "manager",
+  "operation",
+  "recording",
+  "sample",
+  "transportation",
+  "charity",
+  "cousin",
+  "disaster",
+  "editor",
+  "efficiency",
+  "excitement",
+  "extent",
+  "feedback",
+  "guitar",
+  "homework",
+  "leader",
+  "mom",
+  "outcome",
+  "permission",
+  "presentation",
+  "promotion",
+  "reflection",
+  "refrigerator",
+  "resolution",
+  "revenue",
+  "session",
+  "singer",
+  "tennis",
+  "basket",
+  "bonus",
+  "cabinet",
+  "childhood",
+  "church",
+  "clothes",
+  "coffee",
+  "dinner",
+  "drawing",
+  "hair",
+  "hearing",
+  "initiative",
+  "judgment",
+  "lab",
+  "measurement",
+  "mode",
+  "mud",
+  "orange",
+  "poetry",
+  "police",
+  "possibility",
+  "procedure",
+  "queen",
+  "ratio",
+  "relation",
+  "restaurant",
+  "satisfaction",
+  "sector",
+  "signature",
+  "significance",
+  "song",
+  "tooth",
+  "town",
+  "vehicle",
+  "volume",
+  "wife",
+  "accident",
+  "airport",
+  "appointment",
+  "arrival",
+  "assumption",
+  "baseball",
+  "chapter",
+  "committee",
+  "conversation",
+  "database",
+  "enthusiasm",
+  "error",
+  "explanation",
+  "farmer",
+  "gate",
+  "girl",
+  "hall",
+  "historian",
+  "hospital",
+  "injury",
+  "instruction",
+  "maintenance",
+  "manufacturer",
+  "meal",
+  "perception",
+  "pie",
+  "poem",
+  "presence",
+  "proposal",
+  "reception",
+  "replacement",
+  "revolution",
+  "river",
+  "son",
+  "speech",
+  "tea",
+  "village",
+  "warning",
+  "winner",
+  "worker",
+  "writer",
+  "assistance",
+  "breath",
+  "buyer",
+  "chest",
+  "chocolate",
+  "conclusion",
+  "contribution",
+  "cookie",
+  "courage",
+  "dad",
+  "desk",
+  "drawer",
+  "establishment",
+  "examination",
+  "garbage",
+  "grocery",
+  "honey",
+  "impression",
+  "improvement",
+  "independence",
+  "insect",
+  "inspection",
+  "inspector",
+  "king",
+  "ladder",
+  "menu",
+  "penalty",
+  "piano",
+  "potato",
+  "profession",
+  "professor",
+  "quantity",
+  "reaction",
+  "requirement",
+  "salad",
+  "sister",
+  "supermarket",
+  "tongue",
+  "weakness",
+  "wedding",
+  "affair",
+  "ambition",
+  "analyst",
+  "apple",
+  "assignment",
+  "assistant",
+  "bathroom",
+  "bedroom",
+  "beer",
+  "birthday",
+  "celebration",
+  "championship",
+  "cheek",
+  "client",
+  "consequence",
+  "departure",
+  "diamond",
+  "dirt",
+  "ear",
+  "fortune",
+  "friendship",
+  "funeral",
+  "gene",
+  "girlfriend",
+  "hat",
+  "indication",
+  "intention",
+  "lady",
+  "midnight",
+  "negotiation",
+  "obligation",
+  "passenger",
+  "pizza",
+  "platform",
+  "poet",
+  "pollution",
+  "recognition",
+  "reputation",
+  "shirt",
+  "sir",
+  "speaker",
+  "stranger",
+  "surgery",
+  "sympathy",
+  "tale",
+  "throat",
+  "trainer",
+  "uncle",
+  "youth",
+  "time",
+  "work",
+  "film",
+  "water",
+  "money",
+  "example",
+  "while",
+  "business",
+  "study",
+  "game",
+  "life",
+  "form",
+  "air",
+  "day",
+  "place",
+  "number",
+  "part",
+  "field",
+  "fish",
+  "back",
+  "process",
+  "heat",
+  "hand",
+  "experience",
+  "job",
+  "book",
+  "end",
+  "point",
+  "type",
+  "home",
+  "economy",
+  "value",
+  "body",
+  "market",
+  "guide",
+  "interest",
+  "state",
+  "radio",
+  "course",
+  "company",
+  "price",
+  "size",
+  "card",
+  "list",
+  "mind",
+  "trade",
+  "line",
+  "care",
+  "group",
+  "risk",
+  "word",
+  "fat",
+  "force",
+  "key",
+  "light",
+  "training",
+  "name",
+  "school",
+  "top",
+  "amount",
+  "level",
+  "order",
+  "practice",
+  "research",
+  "sense",
+  "service",
+  "piece",
+  "web",
+  "boss",
+  "sport",
+  "fun",
+  "house",
+  "page",
+  "term",
+  "test",
+  "answer",
+  "sound",
+  "focus",
+  "matter",
+  "kind",
+  "soil",
+  "board",
+  "oil",
+  "picture",
+  "access",
+  "garden",
+  "range",
+  "rate",
+  "reason",
+  "future",
+  "site",
+  "demand",
+  "exercise",
+  "image",
+  "case",
+  "cause",
+  "coast",
+  "action",
+  "age",
+  "bad",
+  "boat",
+  "record",
+  "result",
+  "section",
+  "building",
+  "mouse",
+  "cash",
+  "class",
+  "nothing",
+  "period",
+  "plan",
+  "store",
+  "tax",
+  "side",
+  "subject",
+  "space",
+  "rule",
+  "stock",
+  "weather",
+  "chance",
+  "figure",
+  "man",
+  "model",
+  "source",
+  "beginning",
+  "earth",
+  "program",
+  "chicken",
+  "design",
+  "feature",
+  "head",
+  "material",
+  "purpose",
+  "question",
+  "rock",
+  "salt",
+  "act",
+  "birth",
+  "car",
+  "dog",
+  "object",
+  "scale",
+  "sun",
+  "note",
+  "profit",
+  "rent",
+  "speed",
+  "style",
+  "war",
+  "bank",
+  "craft",
+  "half",
+  "inside",
+  "outside",
+  "standard",
+  "bus",
+  "exchange",
+  "eye",
+  "fire",
+  "position",
+  "pressure",
+  "stress",
+  "advantage",
+  "benefit",
+  "box",
+  "frame",
+  "issue",
+  "step",
+  "cycle",
+  "face",
+  "item",
+  "metal",
+  "paint",
+  "review",
+  "room",
+  "screen",
+  "structure",
+  "view",
+  "account",
+  "ball",
+  "discipline",
+  "medium",
+  "share",
+  "balance",
+  "bit",
+  "black",
+  "bottom",
+  "choice",
+  "gift",
+  "impact",
+  "machine",
+  "shape",
+  "tool",
+  "wind",
+  "address",
+  "average",
+  "career",
+  "culture",
+  "morning",
+  "pot",
+  "sign",
+  "table",
+  "task",
+  "condition",
+  "contact",
+  "credit",
+  "egg",
+  "hope",
+  "ice",
+  "network",
+  "north",
+  "square",
+  "attempt",
+  "date",
+  "effect",
+  "link",
+  "post",
+  "star",
+  "voice",
+  "capital",
+  "challenge",
+  "friend",
+  "self",
+  "shot",
+  "brush",
+  "couple",
+  "debate",
+  "exit",
+  "front",
+  "function",
+  "lack",
+  "living",
+  "plant",
+  "plastic",
+  "spot",
+  "summer",
+  "taste",
+  "theme",
+  "track",
+  "wing",
+  "brain",
+  "button",
+  "click",
+  "desire",
+  "foot",
+  "gas",
+  "influence",
+  "notice",
+  "rain",
+  "wall",
+  "base",
+  "damage",
+  "distance",
+  "feeling",
+  "pair",
+  "savings",
+  "staff",
+  "sugar",
+  "target",
+  "text",
+  "animal",
+  "author",
+  "budget",
+  "discount",
+  "file",
+  "ground",
+  "lesson",
+  "minute",
+  "officer",
+  "phase",
+  "reference",
+  "register",
+  "sky",
+  "stage",
+  "stick",
+  "title",
+  "trouble",
+  "bowl",
+  "bridge",
+  "campaign",
+  "character",
+  "club",
+  "edge",
+  "evidence",
+  "fan",
+  "letter",
+  "lock",
+  "maximum",
+  "novel",
+  "option",
+  "pack",
+  "park",
+  "plenty",
+  "quarter",
+  "skin",
+  "sort",
+  "weight",
+  "baby",
+  "background",
+  "carry",
+  "dish",
+  "factor",
+  "fruit",
+  "glass",
+  "joint",
+  "master",
+  "muscle",
+  "red",
+  "strength",
+  "traffic",
+  "trip",
+  "vegetable",
+  "appeal",
+  "chart",
+  "gear",
+  "ideal",
+  "kitchen",
+  "land",
+  "log",
+  "mother",
+  "net",
+  "party",
+  "principle",
+  "relative",
+  "sale",
+  "season",
+  "signal",
+  "spirit",
+  "street",
+  "tree",
+  "wave",
+  "belt",
+  "bench",
+  "commission",
+  "copy",
+  "drop",
+  "minimum",
+  "path",
+  "progress",
+  "project",
+  "sea",
+  "south",
+  "status",
+  "stuff",
+  "ticket",
+  "tour",
+  "angle",
+  "blue",
+  "breakfast",
+  "confidence",
+  "daughter",
+  "degree",
+  "doctor",
+  "dot",
+  "dream",
+  "duty",
+  "essay",
+  "father",
+  "fee",
+  "finance",
+  "hour",
+  "juice",
+  "limit",
+  "luck",
+  "milk",
+  "mouth",
+  "peace",
+  "pipe",
+  "seat",
+  "stable",
+  "storm",
+  "substance",
+  "team",
+  "trick",
+  "afternoon",
+  "bat",
+  "beach",
+  "blank",
+  "catch",
+  "chain",
+  "consideration",
+  "cream",
+  "crew",
+  "detail",
+  "gold",
+  "interview",
+  "kid",
+  "mark",
+  "match",
+  "mission",
+  "pain",
+  "pleasure",
+  "score",
+  "screw",
+  "sex",
+  "shop",
+  "shower",
+  "suit",
+  "tone",
+  "window",
+  "agent",
+  "band",
+  "block",
+  "bone",
+  "calendar",
+  "cap",
+  "coat",
+  "contest",
+  "corner",
+  "court",
+  "cup",
+  "district",
+  "door",
+  "east",
+  "finger",
+  "garage",
+  "guarantee",
+  "hole",
+  "hook",
+  "implement",
+  "layer",
+  "lecture",
+  "lie",
+  "manner",
+  "meeting",
+  "nose",
+  "parking",
+  "partner",
+  "profile",
+  "respect",
+  "rice",
+  "routine",
+  "schedule",
+  "swimming",
+  "telephone",
+  "tip",
+  "winter",
+  "airline",
+  "bag",
+  "battle",
+  "bed",
+  "bill",
+  "bother",
+  "cake",
+  "code",
+  "curve",
+  "designer",
+  "dimension",
+  "dress",
+  "ease",
+  "emergency",
+  "evening",
+  "extension",
+  "farm",
+  "fight",
+  "gap",
+  "grade",
+  "holiday",
+  "horror",
+  "horse",
+  "host",
+  "husband",
+  "loan",
+  "mistake",
+  "mountain",
+  "nail",
+  "noise",
+  "occasion",
+  "package",
+  "patient",
+  "pause",
+  "phrase",
+  "proof",
+  "race",
+  "relief",
+  "sand",
+  "sentence",
+  "shoulder",
+  "smoke",
+  "stomach",
+  "string",
+  "tourist",
+  "towel",
+  "vacation",
+  "west",
+  "wheel",
+  "wine",
+  "arm",
+  "aside",
+  "associate",
+  "bet",
+  "blow",
+  "border",
+  "branch",
+  "breast",
+  "brother",
+  "buddy",
+  "bunch",
+  "chip",
+  "coach",
+  "cross",
+  "document",
+  "draft",
+  "dust",
+  "expert",
+  "floor",
+  "god",
+  "golf",
+  "habit",
+  "iron",
+  "judge",
+  "knife",
+  "landscape",
+  "league",
+  "mail",
+  "mess",
+  "native",
+  "opening",
+  "parent",
+  "pattern",
+  "pin",
+  "pool",
+  "pound",
+  "request",
+  "salary",
+  "shame",
+  "shelter",
+  "shoe",
+  "silver",
+  "tackle",
+  "tank",
+  "trust",
+  "assist",
+  "bake",
+  "bar",
+  "bell",
+  "bike",
+  "blame",
+  "boy",
+  "brick",
+  "chair",
+  "closet",
+  "clue",
+  "collar",
+  "comment",
+  "conference",
+  "devil",
+  "diet",
+  "fear",
+  "fuel",
+  "glove",
+  "jacket",
+  "lunch",
+  "monitor",
+  "mortgage",
+  "nurse",
+  "pace",
+  "panic",
+  "peak",
+  "plane",
+  "reward",
+  "row",
+  "sandwich",
+  "shock",
+  "spite",
+  "spray",
+  "surprise",
+  "till",
+  "transition",
+  "weekend",
+  "welcome",
+  "yard",
+  "alarm",
+  "bend",
+  "bicycle",
+  "bite",
+  "blind",
+  "bottle",
+  "cable",
+  "candle",
+  "clerk",
+  "cloud",
+  "concert",
+  "counter",
+  "flower",
+  "grandfather",
+  "harm",
+  "knee",
+  "lawyer",
+  "leather",
+  "load",
+  "mirror",
+  "neck",
+  "pension",
+  "plate",
+  "purple",
+  "ruin",
+  "ship",
+  "skirt",
+  "slice",
+  "snow",
+  "specialist",
+  "stroke",
+  "switch",
+  "trash",
+  "tune",
+  "zone",
+  "anger",
+  "award",
+  "bid",
+  "bitter",
+  "boot",
+  "bug",
+  "camp",
+  "candy",
+  "carpet",
+  "cat",
+  "champion",
+  "channel",
+  "clock",
+  "comfort",
+  "cow",
+  "crack",
+  "engineer",
+  "entrance",
+  "fault",
+  "grass",
+  "guy",
+  "hell",
+  "highlight",
+  "incident",
+  "island",
+  "joke",
+  "jury",
+  "leg",
+  "lip",
+  "mate",
+  "motor",
+  "nerve",
+  "passage",
+  "pen",
+  "pride",
+  "priest",
+  "prize",
+  "promise",
+  "resident",
+  "resort",
+  "ring",
+  "roof",
+  "rope",
+  "sail",
+  "scheme",
+  "script",
+  "sock",
+  "station",
+  "toe",
+  "tower",
+  "truck",
+  "witness",
+  "a",
+  "you",
+  "it",
+  "can",
+  "will",
+  "if",
+  "one",
+  "many",
+  "most",
+  "other",
+  "use",
+  "make",
+  "good",
+  "look",
+  "help",
+  "go",
+  "great",
+  "being",
+  "few",
+  "might",
+  "still",
+  "public",
+  "read",
+  "keep",
+  "start",
+  "give",
+  "human",
+  "local",
+  "general",
+  "she",
+  "specific",
+  "long",
+  "play",
+  "feel",
+  "high",
+  "tonight",
+  "put",
+  "common",
+  "set",
+  "change",
+  "simple",
+  "past",
+  "big",
+  "possible",
+  "particular",
+  "today",
+  "major",
+  "personal",
+  "current",
+  "national",
+  "cut",
+  "natural",
+  "physical",
+  "show",
+  "try",
+  "check",
+  "second",
+  "call",
+  "move",
+  "pay",
+  "let",
+  "increase",
+  "single",
+  "individual",
+  "turn",
+  "ask",
+  "buy",
+  "guard",
+  "hold",
+  "main",
+  "offer",
+  "potential",
+  "professional",
+  "international",
+  "travel",
+  "cook",
+  "alternative",
+  "following",
+  "special",
+  "working",
+  "whole",
+  "dance",
+  "excuse",
+  "cold",
+  "commercial",
+  "low",
+  "purchase",
+  "deal",
+  "primary",
+  "worth",
+  "fall",
+  "necessary",
+  "positive",
+  "produce",
+  "search",
+  "present",
+  "spend",
+  "talk",
+  "creative",
+  "tell",
+  "cost",
+  "drive",
+  "green",
+  "support",
+  "glad",
+  "remove",
+  "return",
+  "run",
+  "complex",
+  "due",
+  "effective",
+  "middle",
+  "regular",
+  "reserve",
+  "independent",
+  "leave",
+  "original",
+  "reach",
+  "rest",
+  "serve",
+  "watch",
+  "beautiful",
+  "charge",
+  "active",
+  "break",
+  "negative",
+  "safe",
+  "stay",
+  "visit",
+  "visual",
+  "affect",
+  "cover",
+  "report",
+  "rise",
+  "walk",
+  "white",
+  "beyond",
+  "junior",
+  "pick",
+  "unique",
+  "anything",
+  "classic",
+  "final",
+  "lift",
+  "mix",
+  "private",
+  "stop",
+  "teach",
+  "western",
+  "concern",
+  "familiar",
+  "fly",
+  "official",
+  "broad",
+  "comfortable",
+  "gain",
+  "maybe",
+  "rich",
+  "save",
+  "stand",
+  "young",
+  "fail",
+  "heavy",
+  "hello",
+  "lead",
+  "listen",
+  "valuable",
+  "worry",
+  "handle",
+  "leading",
+  "meet",
+  "release",
+  "sell",
+  "finish",
+  "normal",
+  "press",
+  "ride",
+  "secret",
+  "spread",
+  "spring",
+  "tough",
+  "wait",
+  "brown",
+  "deep",
+  "display",
+  "flow",
+  "hit",
+  "objective",
+  "shoot",
+  "touch",
+  "cancel",
+  "chemical",
+  "cry",
+  "dump",
+  "extreme",
+  "push",
+  "conflict",
+  "eat",
+  "fill",
+  "formal",
+  "jump",
+  "kick",
+  "opposite",
+  "pass",
+  "pitch",
+  "remote",
+  "total",
+  "treat",
+  "vast",
+  "abuse",
+  "beat",
+  "burn",
+  "deposit",
+  "print",
+  "raise",
+  "sleep",
+  "somewhere",
+  "advance",
+  "anywhere",
+  "consist",
+  "dark",
+  "double",
+  "draw",
+  "equal",
+  "fix",
+  "hire",
+  "internal",
+  "join",
+  "kill",
+  "sensitive",
+  "tap",
+  "win",
+  "attack",
+  "claim",
+  "constant",
+  "drag",
+  "drink",
+  "guess",
+  "minor",
+  "pull",
+  "raw",
+  "soft",
+  "solid",
+  "wear",
+  "weird",
+  "wonder",
+  "annual",
+  "count",
+  "dead",
+  "doubt",
+  "feed",
+  "forever",
+  "impress",
+  "nobody",
+  "repeat",
+  "round",
+  "sing",
+  "slide",
+  "strip",
+  "whereas",
+  "wish",
+  "combine",
+  "command",
+  "dig",
+  "divide",
+  "equivalent",
+  "hang",
+  "hunt",
+  "initial",
+  "march",
+  "mention",
+  "smell",
+  "spiritual",
+  "survey",
+  "tie",
+  "adult",
+  "brief",
+  "crazy",
+  "escape",
+  "gather",
+  "hate",
+  "prior",
+  "repair",
+  "rough",
+  "sad",
+  "scratch",
+  "sick",
+  "strike",
+  "employ",
+  "external",
+  "hurt",
+  "illegal",
+  "laugh",
+  "lay",
+  "mobile",
+  "nasty",
+  "ordinary",
+  "respond",
+  "royal",
+  "senior",
+  "split",
+  "strain",
+  "struggle",
+  "swim",
+  "train",
+  "upper",
+  "wash",
+  "yellow",
+  "convert",
+  "crash",
+  "dependent",
+  "fold",
+  "funny",
+  "grab",
+  "hide",
+  "miss",
+  "permit",
+  "quote",
+  "recover",
+  "resolve",
+  "roll",
+  "sink",
+  "slip",
+  "spare",
+  "suspect",
+  "sweet",
+  "swing",
+  "twist",
+  "upstairs",
+  "usual",
+  "abroad",
+  "brave",
+  "calm",
+  "concentrate",
+  "estimate",
+  "grand",
+  "male",
+  "mine",
+  "prompt",
+  "quiet",
+  "refuse",
+  "regret",
+  "reveal",
+  "rush",
+  "shake",
+  "shift",
+  "shine",
+  "steal",
+  "suck",
+  "surround",
+  "anybody",
+  "bear",
+  "brilliant",
+  "dare",
+  "dear",
+  "delay",
+  "drunk",
+  "female",
+  "hurry",
+  "inevitable",
+  "invite",
+  "kiss",
+  "neat",
+  "pop",
+  "punch",
+  "quit",
+  "reply",
+  "representative",
+  "resist",
+  "rip",
+  "rub",
+  "silly",
+  "smile",
+  "spell",
+  "stretch",
+  "stupid",
+  "tear",
+  "temporary",
+  "tomorrow",
+  "wake",
+  "wrap",
+  "yesterday"
 ]
 
 const adj = [
-    "abandoned",
-    "able",
-    "absolute",
-    "adorable",
-    "adventurous",
-    "academic",
-    "acceptable",
-    "acclaimed",
-    "accomplished",
-    "accurate",
-    "aching",
-    "acidic",
-    "acrobatic",
-    "active",
-    "actual",
-    "adept",
-    "admirable",
-    "admired",
-    "adolescent",
-    "adorable",
-    "adored",
-    "advanced",
-    "afraid",
-    "affectionate",
-    "aged",
-    "aggravating",
-    "aggressive",
-    "agile",
-    "agitated",
-    "agonizing",
-    "agreeable",
-    "ajar",
-    "alarmed",
-    "alarming",
-    "alert",
-    "alienated",
-    "alive",
-    "all",
-    "altruistic",
-    "amazing",
-    "ambitious",
-    "ample",
-    "amused",
-    "amusing",
-    "anchored",
-    "ancient",
-    "angelic",
-    "angry",
-    "anguished",
-    "animated",
-    "annual",
-    "another",
-    "antique",
-    "anxious",
-    "any",
-    "apprehensive",
-    "appropriate",
-    "apt",
-    "arctic",
-    "arid",
-    "aromatic",
-    "artistic",
-    "ashamed",
-    "assured",
-    "astonishing",
-    "athletic",
-    "attached",
-    "attentive",
-    "attractive",
-    "austere",
-    "authentic",
-    "authorized",
-    "automatic",
-    "avaricious",
-    "average",
-    "aware",
-    "awesome",
-    "awful",
-    "awkward",
-    "babyish",
-    "bad",
-    "back",
-    "baggy",
-    "bare",
-    "barren",
-    "basic",
-    "beautiful",
-    "belated",
-    "beloved",
-    "beneficial",
-    "better",
-    "best",
-    "bewitched",
-    "big",
-    "big-hearted",
-    "biodegradable",
-    "bite-sized",
-    "bitter",
-    "black",
-    "black-and-white",
-    "bland",
-    "blank",
-    "blaring",
-    "bleak",
-    "blind",
-    "blissful",
-    "blond",
-    "blue",
-    "blushing",
-    "bogus",
-    "boiling",
-    "bold",
-    "bony",
-    "boring",
-    "bossy",
-    "both",
-    "bouncy",
-    "bountiful",
-    "bowed",
-    "brave",
-    "breakable",
-    "brief",
-    "bright",
-    "brilliant",
-    "brisk",
-    "broken",
-    "bronze",
-    "brown",
-    "bruised",
-    "bubbly",
-    "bulky",
-    "bumpy",
-    "buoyant",
-    "burdensome",
-    "burly",
-    "bustling",
-    "busy",
-    "buttery",
-    "buzzing",
-    "calculating",
-    "calm",
-    "candid",
-    "canine",
-    "capital",
-    "carefree",
-    "careful",
-    "careless",
-    "caring",
-    "cautious",
-    "cavernous",
-    "celebrated",
-    "charming",
-    "cheap",
-    "cheerful",
-    "cheery",
-    "chief",
-    "chilly",
-    "chubby",
-    "circular",
-    "classic",
-    "clean",
-    "clear",
-    "clear-cut",
-    "clever",
-    "close",
-    "closed",
-    "cloudy",
-    "clueless",
-    "clumsy",
-    "cluttered",
-    "coarse",
-    "cold",
-    "colorful",
-    "colorless",
-    "colossal",
-    "comfortable",
-    "common",
-    "compassionate",
-    "competent",
-    "complete",
-    "complex",
-    "complicated",
-    "composed",
-    "concerned",
-    "concrete",
-    "confused",
-    "conscious",
-    "considerate",
-    "constant",
-    "content",
-    "conventional",
-    "cooked",
-    "cool",
-    "cooperative",
-    "coordinated",
-    "corny",
-    "corrupt",
-    "costly",
-    "courageous",
-    "courteous",
-    "crafty",
-    "crazy",
-    "creamy",
-    "creative",
-    "creepy",
-    "criminal",
-    "crisp",
-    "critical",
-    "crooked",
-    "crowded",
-    "cruel",
-    "crushing",
-    "cuddly",
-    "cultivated",
-    "cultured",
-    "cumbersome",
-    "curly",
-    "curvy",
-    "cute",
-    "cylindrical",
-    "damaged",
-    "damp",
-    "dangerous",
-    "dapper",
-    "daring",
-    "darling",
-    "dark",
-    "dazzling",
-    "dead",
-    "deadly",
-    "deafening",
-    "dear",
-    "dearest",
-    "decent",
-    "decimal",
-    "decisive",
-    "deep",
-    "defenseless",
-    "defensive",
-    "defiant",
-    "deficient",
-    "definite",
-    "definitive",
-    "delayed",
-    "delectable",
-    "delicious",
-    "delightful",
-    "delirious",
-    "demanding",
-    "dense",
-    "dental",
-    "dependable",
-    "dependent",
-    "descriptive",
-    "deserted",
-    "detailed",
-    "determined",
-    "devoted",
-    "different",
-    "difficult",
-    "digital",
-    "diligent",
-    "dim",
-    "dimpled",
-    "dimwitted",
-    "direct",
-    "disastrous",
-    "discrete",
-    "disfigured",
-    "disgusting",
-    "disloyal",
-    "dismal",
-    "distant",
-    "downright",
-    "dreary",
-    "dirty",
-    "disguised",
-    "dishonest",
-    "dismal",
-    "distant",
-    "distinct",
-    "distorted",
-    "dizzy",
-    "dopey",
-    "doting",
-    "double",
-    "downright",
-    "drab",
-    "drafty",
-    "dramatic",
-    "dreary",
-    "droopy",
-    "dry",
-    "dual",
-    "dull",
-    "dutiful",
-    "each",
-    "eager",
-    "earnest",
-    "early",
-    "easy",
-    "easy-going",
-    "ecstatic",
-    "edible",
-    "educated",
-    "elaborate",
-    "elastic",
-    "elated",
-    "elderly",
-    "electric",
-    "elegant",
-    "elementary",
-    "elliptical",
-    "embarrassed",
-    "embellished",
-    "eminent",
-    "emotional",
-    "empty",
-    "enchanted",
-    "enchanting",
-    "energetic",
-    "enlightened",
-    "enormous",
-    "enraged",
-    "entire",
-    "envious",
-    "equal",
-    "equatorial",
-    "essential",
-    "esteemed",
-    "ethical",
-    "euphoric",
-    "even",
-    "evergreen",
-    "everlasting",
-    "every",
-    "evil",
-    "exalted",
-    "excellent",
-    "exemplary",
-    "exhausted",
-    "excitable",
-    "excited",
-    "exciting",
-    "exotic",
-    "expensive",
-    "experienced",
-    "expert",
-    "extraneous",
-    "extroverted",
-    "extra-large",
-    "extra-small",
-    "fabulous",
-    "failing",
-    "faint",
-    "fair",
-    "faithful",
-    "fake",
-    "false",
-    "familiar",
-    "famous",
-    "fancy",
-    "fantastic",
-    "far",
-    "faraway",
-    "far-flung",
-    "far-off",
-    "fast",
-    "fat",
-    "fatal",
-    "fatherly",
-    "favorable",
-    "favorite",
-    "fearful",
-    "fearless",
-    "feisty",
-    "feline",
-    "female",
-    "feminine",
-    "few",
-    "fickle",
-    "filthy",
-    "fine",
-    "finished",
-    "firm",
-    "first",
-    "firsthand",
-    "fitting",
-    "fixed",
-    "flaky",
-    "flamboyant",
-    "flashy",
-    "flat",
-    "flawed",
-    "flawless",
-    "flickering",
-    "flimsy",
-    "flippant",
-    "flowery",
-    "fluffy",
-    "fluid",
-    "flustered",
-    "focused",
-    "fond",
-    "foolhardy",
-    "foolish",
-    "forceful",
-    "forked",
-    "formal",
-    "forsaken",
-    "forthright",
-    "fortunate",
-    "fragrant",
-    "frail",
-    "frank",
-    "frayed",
-    "free",
-    "French",
-    "fresh",
-    "frequent",
-    "friendly",
-    "frightened",
-    "frightening",
-    "frigid",
-    "frilly",
-    "frizzy",
-    "frivolous",
-    "front",
-    "frosty",
-    "frozen",
-    "frugal",
-    "fruitful",
-    "full",
-    "fumbling",
-    "functional",
-    "funny",
-    "fussy",
-    "fuzzy",
-    "gargantuan",
-    "gaseous",
-    "general",
-    "generous",
-    "gentle",
-    "genuine",
-    "giant",
-    "giddy",
-    "gigantic",
-    "gifted",
-    "giving",
-    "glamorous",
-    "glaring",
-    "glass",
-    "gleaming",
-    "gleeful",
-    "glistening",
-    "glittering",
-    "gloomy",
-    "glorious",
-    "glossy",
-    "glum",
-    "golden",
-    "good",
-    "good-natured",
-    "gorgeous",
-    "graceful",
-    "gracious",
-    "grand",
-    "grandiose",
-    "granular",
-    "grateful",
-    "grave",
-    "gray",
-    "great",
-    "greedy",
-    "green",
-    "gregarious",
-    "grim",
-    "grimy",
-    "gripping",
-    "grizzled",
-    "gross",
-    "grotesque",
-    "grouchy",
-    "grounded",
-    "growing",
-    "growling",
-    "grown",
-    "grubby",
-    "gruesome",
-    "grumpy",
-    "guilty",
-    "gullible",
-    "gummy",
-    "hairy",
-    "half",
-    "handmade",
-    "handsome",
-    "handy",
-    "happy",
-    "happy-go-lucky",
-    "hard",
-    "hard-to-find",
-    "harmful",
-    "harmless",
-    "harmonious",
-    "harsh",
-    "hasty",
-    "hateful",
-    "haunting",
-    "healthy",
-    "heartfelt",
-    "hearty",
-    "heavenly",
-    "heavy",
-    "hefty",
-    "helpful",
-    "helpless",
-    "hidden",
-    "hideous",
-    "high",
-    "high-level",
-    "hilarious",
-    "hoarse",
-    "hollow",
-    "homely",
-    "honest",
-    "honorable",
-    "honored",
-    "hopeful",
-    "horrible",
-    "hospitable",
-    "hot",
-    "huge",
-    "humble",
-    "humiliating",
-    "humming",
-    "humongous",
-    "hungry",
-    "hurtful",
-    "husky",
-    "icky",
-    "icy",
-    "ideal",
-    "idealistic",
-    "identical",
-    "idle",
-    "idiotic",
-    "idolized",
-    "ignorant",
-    "ill",
-    "illegal",
-    "ill-fated",
-    "ill-informed",
-    "illiterate",
-    "illustrious",
-    "imaginary",
-    "imaginative",
-    "immaculate",
-    "immaterial",
-    "immediate",
-    "immense",
-    "impassioned",
-    "impeccable",
-    "impartial",
-    "imperfect",
-    "imperturbable",
-    "impish",
-    "impolite",
-    "important",
-    "impossible",
-    "impractical",
-    "impressionable",
-    "impressive",
-    "improbable",
-    "impure",
-    "inborn",
-    "incomparable",
-    "incompatible",
-    "incomplete",
-    "inconsequential",
-    "incredible",
-    "indelible",
-    "inexperienced",
-    "indolent",
-    "infamous",
-    "infantile",
-    "infatuated",
-    "inferior",
-    "infinite",
-    "informal",
-    "innocent",
-    "insecure",
-    "insidious",
-    "insignificant",
-    "insistent",
-    "instructive",
-    "insubstantial",
-    "intelligent",
-    "intent",
-    "intentional",
-    "interesting",
-    "internal",
-    "international",
-    "intrepid",
-    "ironclad",
-    "irresponsible",
-    "irritating",
-    "itchy",
-    "jaded",
-    "jagged",
-    "jam-packed",
-    "jaunty",
-    "jealous",
-    "jittery",
-    "joint",
-    "jolly",
-    "jovial",
-    "joyful",
-    "joyous",
-    "jubilant",
-    "judicious",
-    "juicy",
-    "jumbo",
-    "junior",
-    "jumpy",
-    "juvenile",
-    "kaleidoscopic",
-    "keen",
-    "key",
-    "kind",
-    "kindhearted",
-    "kindly",
-    "klutzy",
-    "knobby",
-    "knotty",
-    "knowledgeable",
-    "knowing",
-    "known",
-    "kooky",
-    "kosher",
-    "lame",
-    "lanky",
-    "large",
-    "last",
-    "lasting",
-    "late",
-    "lavish",
-    "lawful",
-    "lazy",
-    "leading",
-    "lean",
-    "leafy",
-    "left",
-    "legal",
-    "legitimate",
-    "light",
-    "lighthearted",
-    "likable",
-    "likely",
-    "limited",
-    "limp",
-    "limping",
-    "linear",
-    "lined",
-    "liquid",
-    "little",
-    "live",
-    "lively",
-    "livid",
-    "loathsome",
-    "lone",
-    "lonely",
-    "long",
-    "long-term",
-    "loose",
-    "lopsided",
-    "lost",
-    "loud",
-    "lovable",
-    "lovely",
-    "loving",
-    "low",
-    "loyal",
-    "lucky",
-    "lumbering",
-    "luminous",
-    "lumpy",
-    "lustrous",
-    "luxurious",
-    "mad",
-    "made-up",
-    "magnificent",
-    "majestic",
-    "major",
-    "male",
-    "mammoth",
-    "married",
-    "marvelous",
-    "masculine",
-    "massive",
-    "mature",
-    "meager",
-    "mealy",
-    "mean",
-    "measly",
-    "meaty",
-    "medical",
-    "mediocre",
-    "medium",
-    "meek",
-    "mellow",
-    "melodic",
-    "memorable",
-    "menacing",
-    "merry",
-    "messy",
-    "metallic",
-    "mild",
-    "milky",
-    "mindless",
-    "miniature",
-    "minor",
-    "minty",
-    "miserable",
-    "miserly",
-    "misguided",
-    "misty",
-    "mixed",
-    "modern",
-    "modest",
-    "moist",
-    "monstrous",
-    "monthly",
-    "monumental",
-    "moral",
-    "mortified",
-    "motherly",
-    "motionless",
-    "mountainous",
-    "muddy",
-    "muffled",
-    "multicolored",
-    "mundane",
-    "murky",
-    "mushy",
-    "musty",
-    "muted",
-    "mysterious",
-    "naive",
-    "narrow",
-    "nasty",
-    "natural",
-    "naughty",
-    "nautical",
-    "near",
-    "neat",
-    "necessary",
-    "needy",
-    "negative",
-    "neglected",
-    "negligible",
-    "neighboring",
-    "nervous",
-    "new",
-    "next",
-    "nice",
-    "nifty",
-    "nimble",
-    "nippy",
-    "nocturnal",
-    "noisy",
-    "nonstop",
-    "normal",
-    "notable",
-    "noted",
-    "noteworthy",
-    "novel",
-    "noxious",
-    "numb",
-    "nutritious",
-    "nutty",
-    "obedient",
-    "obese",
-    "oblong",
-    "oily",
-    "oblong",
-    "obvious",
-    "occasional",
-    "odd",
-    "oddball",
-    "offbeat",
-    "offensive",
-    "official",
-    "old",
-    "old-fashioned",
-    "only",
-    "open",
-    "optimal",
-    "optimistic",
-    "opulent",
-    "orange",
-    "orderly",
-    "organic",
-    "ornate",
-    "ornery",
-    "ordinary",
-    "original",
-    "other",
-    "our",
-    "outlying",
-    "outgoing",
-    "outlandish",
-    "outrageous",
-    "outstanding",
-    "oval",
-    "overcooked",
-    "overdue",
-    "overjoyed",
-    "overlooked",
-    "palatable",
-    "pale",
-    "paltry",
-    "parallel",
-    "parched",
-    "partial",
-    "passionate",
-    "past",
-    "pastel",
-    "peaceful",
-    "peppery",
-    "perfect",
-    "perfumed",
-    "periodic",
-    "perky",
-    "personal",
-    "pertinent",
-    "pesky",
-    "pessimistic",
-    "petty",
-    "phony",
-    "physical",
-    "piercing",
-    "pink",
-    "pitiful",
-    "plain",
-    "plaintive",
-    "plastic",
-    "playful",
-    "pleasant",
-    "pleased",
-    "pleasing",
-    "plump",
-    "plush",
-    "polished",
-    "polite",
-    "political",
-    "pointed",
-    "pointless",
-    "poised",
-    "poor",
-    "popular",
-    "portly",
-    "posh",
-    "positive",
-    "possible",
-    "potable",
-    "powerful",
-    "powerless",
-    "practical",
-    "precious",
-    "present",
-    "prestigious",
-    "pretty",
-    "precious",
-    "previous",
-    "pricey",
-    "prickly",
-    "primary",
-    "prime",
-    "pristine",
-    "private",
-    "prize",
-    "probable",
-    "productive",
-    "profitable",
-    "profuse",
-    "proper",
-    "proud",
-    "prudent",
-    "punctual",
-    "pungent",
-    "puny",
-    "pure",
-    "purple",
-    "pushy",
-    "putrid",
-    "puzzled",
-    "puzzling",
-    "quaint",
-    "qualified",
-    "quarrelsome",
-    "quarterly",
-    "queasy",
-    "querulous",
-    "questionable",
-    "quick",
-    "quick-witted",
-    "quiet",
-    "quintessential",
-    "quirky",
-    "quixotic",
-    "quizzical",
-    "radiant",
-    "ragged",
-    "rapid",
-    "rare",
-    "rash",
-    "raw",
-    "recent",
-    "reckless",
-    "rectangular",
-    "ready",
-    "real",
-    "realistic",
-    "reasonable",
-    "red",
-    "reflecting",
-    "regal",
-    "regular",
-    "reliable",
-    "relieved",
-    "remarkable",
-    "remorseful",
-    "remote",
-    "repentant",
-    "required",
-    "respectful",
-    "responsible",
-    "repulsive",
-    "revolving",
-    "rewarding",
-    "rich",
-    "rigid",
-    "right",
-    "ringed",
-    "ripe",
-    "roasted",
-    "robust",
-    "rosy",
-    "rotating",
-    "rotten",
-    "rough",
-    "round",
-    "rowdy",
-    "royal",
-    "rubbery",
-    "rundown",
-    "ruddy",
-    "rude",
-    "runny",
-    "rural",
-    "rusty",
-    "sad",
-    "safe",
-    "salty",
-    "same",
-    "sandy",
-    "sane",
-    "sarcastic",
-    "sardonic",
-    "satisfied",
-    "scaly",
-    "scarce",
-    "scared",
-    "scary",
-    "scented",
-    "scholarly",
-    "scientific",
-    "scornful",
-    "scratchy",
-    "scrawny",
-    "second",
-    "secondary",
-    "second-hand",
-    "secret",
-    "self-assured",
-    "self-reliant",
-    "selfish",
-    "sentimental",
-    "separate",
-    "serene",
-    "serious",
-    "serpentine",
-    "several",
-    "severe",
-    "shabby",
-    "shadowy",
-    "shady",
-    "shallow",
-    "shameful",
-    "shameless",
-    "sharp",
-    "shimmering",
-    "shiny",
-    "shocked",
-    "shocking",
-    "shoddy",
-    "short",
-    "short-term",
-    "showy",
-    "shrill",
-    "shy",
-    "sick",
-    "silent",
-    "silky",
-    "silly",
-    "silver",
-    "similar",
-    "simple",
-    "simplistic",
-    "sinful",
-    "single",
-    "sizzling",
-    "skeletal",
-    "skinny",
-    "sleepy",
-    "slight",
-    "slim",
-    "slimy",
-    "slippery",
-    "slow",
-    "slushy",
-    "small",
-    "smart",
-    "smoggy",
-    "smooth",
-    "smug",
-    "snappy",
-    "snarling",
-    "sneaky",
-    "sniveling",
-    "snoopy",
-    "sociable",
-    "soft",
-    "soggy",
-    "solid",
-    "somber",
-    "some",
-    "spherical",
-    "sophisticated",
-    "sore",
-    "sorrowful",
-    "soulful",
-    "soupy",
-    "sour",
-    "Spanish",
-    "sparkling",
-    "sparse",
-    "specific",
-    "spectacular",
-    "speedy",
-    "spicy",
-    "spiffy",
-    "spirited",
-    "spiteful",
-    "splendid",
-    "spotless",
-    "spotted",
-    "spry",
-    "square",
-    "squeaky",
-    "squiggly",
-    "stable",
-    "staid",
-    "stained",
-    "stale",
-    "standard",
-    "starchy",
-    "stark",
-    "starry",
-    "steep",
-    "sticky",
-    "stiff",
-    "stimulating",
-    "stingy",
-    "stormy",
-    "straight",
-    "strange",
-    "steel",
-    "strict",
-    "strident",
-    "striking",
-    "striped",
-    "strong",
-    "studious",
-    "stunning",
-    "stupendous",
-    "stupid",
-    "sturdy",
-    "stylish",
-    "subdued",
-    "submissive",
-    "substantial",
-    "subtle",
-    "suburban",
-    "sudden",
-    "sugary",
-    "sunny",
-    "super",
-    "superb",
-    "superficial",
-    "superior",
-    "supportive",
-    "sure-footed",
-    "surprised",
-    "suspicious",
-    "svelte",
-    "sweaty",
-    "sweet",
-    "sweltering",
-    "swift",
-    "sympathetic",
-    "tall",
-    "talkative",
-    "tame",
-    "tan",
-    "tangible",
-    "tart",
-    "tasty",
-    "tattered",
-    "taut",
-    "tedious",
-    "teeming",
-    "tempting",
-    "tender",
-    "tense",
-    "tepid",
-    "terrible",
-    "terrific",
-    "testy",
-    "thankful",
-    "that",
-    "these",
-    "thick",
-    "thin",
-    "third",
-    "thirsty",
-    "this",
-    "thorough",
-    "thorny",
-    "those",
-    "thoughtful",
-    "threadbare",
-    "thrifty",
-    "thunderous",
-    "tidy",
-    "tight",
-    "timely",
-    "tinted",
-    "tiny",
-    "tired",
-    "torn",
-    "total",
-    "tough",
-    "traumatic",
-    "treasured",
-    "tremendous",
-    "tragic",
-    "trained",
-    "tremendous",
-    "triangular",
-    "tricky",
-    "trifling",
-    "trim",
-    "trivial",
-    "troubled",
-    "true",
-    "trusting",
-    "trustworthy",
-    "trusty",
-    "truthful",
-    "tubby",
-    "turbulent",
-    "twin",
-    "ugly",
-    "ultimate",
-    "unacceptable",
-    "unaware",
-    "uncomfortable",
-    "uncommon",
-    "unconscious",
-    "understated",
-    "unequaled",
-    "uneven",
-    "unfinished",
-    "unfit",
-    "unfolded",
-    "unfortunate",
-    "unhappy",
-    "unhealthy",
-    "uniform",
-    "unimportant",
-    "unique",
-    "united",
-    "unkempt",
-    "unknown",
-    "unlawful",
-    "unlined",
-    "unlucky",
-    "unnatural",
-    "unpleasant",
-    "unrealistic",
-    "unripe",
-    "unruly",
-    "unselfish",
-    "unsightly",
-    "unsteady",
-    "unsung",
-    "untidy",
-    "untimely",
-    "untried",
-    "untrue",
-    "unused",
-    "unusual",
-    "unwelcome",
-    "unwieldy",
-    "unwilling",
-    "unwitting",
-    "unwritten",
-    "upbeat",
-    "upright",
-    "upset",
-    "urban",
-    "usable",
-    "used",
-    "useful",
-    "useless",
-    "utilized",
-    "utter",
-    "vacant",
-    "vague",
-    "vain",
-    "valid",
-    "valuable",
-    "vapid",
-    "variable",
-    "vast",
-    "velvety",
-    "venerated",
-    "vengeful",
-    "verifiable",
-    "vibrant",
-    "vicious",
-    "victorious",
-    "vigilant",
-    "vigorous",
-    "villainous",
-    "violet",
-    "violent",
-    "virtual",
-    "virtuous",
-    "visible",
-    "vital",
-    "vivacious",
-    "vivid",
-    "voluminous",
-    "wan",
-    "warlike",
-    "warm",
-    "warmhearted",
-    "warped",
-    "wary",
-    "wasteful",
-    "watchful",
-    "waterlogged",
-    "watery",
-    "wavy",
-    "wealthy",
-    "weak",
-    "weary",
-    "webbed",
-    "wee",
-    "weekly",
-    "weepy",
-    "weighty",
-    "weird",
-    "welcome",
-    "well-documented",
-    "well-groomed",
-    "well-informed",
-    "well-lit",
-    "well-made",
-    "well-off",
-    "well-to-do",
-    "well-worn",
-    "wet",
-    "which",
-    "whimsical",
-    "whirlwind",
-    "whispered",
-    "white",
-    "whole",
-    "whopping",
-    "wicked",
-    "wide",
-    "wide-eyed",
-    "wiggly",
-    "wild",
-    "willing",
-    "wilted",
-    "winding",
-    "windy",
-    "winged",
-    "wiry",
-    "wise",
-    "witty",
-    "wobbly",
-    "woeful",
-    "wonderful",
-    "wooden",
-    "woozy",
-    "wordy",
-    "worldly",
-    "worn",
-    "worried",
-    "worrisome",
-    "worse",
-    "worst",
-    "worthless",
-    "worthwhile",
-    "worthy",
-    "wrathful",
-    "wretched",
-    "writhing",
-    "wrong",
-    "wry",
-    "yawning",
-    "yearly",
-    "yellow",
-    "yellowish",
-    "young",
-    "youthful",
-    "yummy",
-    "zany",
-    "zealous",
-    "zesty",
-    "zigzag",
+  "abandoned",
+  "able",
+  "absolute",
+  "adorable",
+  "adventurous",
+  "academic",
+  "acceptable",
+  "acclaimed",
+  "accomplished",
+  "accurate",
+  "aching",
+  "acidic",
+  "acrobatic",
+  "active",
+  "actual",
+  "adept",
+  "admirable",
+  "admired",
+  "adolescent",
+  "adorable",
+  "adored",
+  "advanced",
+  "afraid",
+  "affectionate",
+  "aged",
+  "aggravating",
+  "aggressive",
+  "agile",
+  "agitated",
+  "agonizing",
+  "agreeable",
+  "ajar",
+  "alarmed",
+  "alarming",
+  "alert",
+  "alienated",
+  "alive",
+  "all",
+  "altruistic",
+  "amazing",
+  "ambitious",
+  "ample",
+  "amused",
+  "amusing",
+  "anchored",
+  "ancient",
+  "angelic",
+  "angry",
+  "anguished",
+  "animated",
+  "annual",
+  "another",
+  "antique",
+  "anxious",
+  "any",
+  "apprehensive",
+  "appropriate",
+  "apt",
+  "arctic",
+  "arid",
+  "aromatic",
+  "artistic",
+  "ashamed",
+  "assured",
+  "astonishing",
+  "athletic",
+  "attached",
+  "attentive",
+  "attractive",
+  "austere",
+  "authentic",
+  "authorized",
+  "automatic",
+  "avaricious",
+  "average",
+  "aware",
+  "awesome",
+  "awful",
+  "awkward",
+  "babyish",
+  "bad",
+  "back",
+  "baggy",
+  "bare",
+  "barren",
+  "basic",
+  "beautiful",
+  "belated",
+  "beloved",
+  "beneficial",
+  "better",
+  "best",
+  "bewitched",
+  "big",
+  "big-hearted",
+  "biodegradable",
+  "bite-sized",
+  "bitter",
+  "black",
+  "black-and-white",
+  "bland",
+  "blank",
+  "blaring",
+  "bleak",
+  "blind",
+  "blissful",
+  "blond",
+  "blue",
+  "blushing",
+  "bogus",
+  "boiling",
+  "bold",
+  "bony",
+  "boring",
+  "bossy",
+  "both",
+  "bouncy",
+  "bountiful",
+  "bowed",
+  "brave",
+  "breakable",
+  "brief",
+  "bright",
+  "brilliant",
+  "brisk",
+  "broken",
+  "bronze",
+  "brown",
+  "bruised",
+  "bubbly",
+  "bulky",
+  "bumpy",
+  "buoyant",
+  "burdensome",
+  "burly",
+  "bustling",
+  "busy",
+  "buttery",
+  "buzzing",
+  "calculating",
+  "calm",
+  "candid",
+  "canine",
+  "capital",
+  "carefree",
+  "careful",
+  "careless",
+  "caring",
+  "cautious",
+  "cavernous",
+  "celebrated",
+  "charming",
+  "cheap",
+  "cheerful",
+  "cheery",
+  "chief",
+  "chilly",
+  "chubby",
+  "circular",
+  "classic",
+  "clean",
+  "clear",
+  "clear-cut",
+  "clever",
+  "close",
+  "closed",
+  "cloudy",
+  "clueless",
+  "clumsy",
+  "cluttered",
+  "coarse",
+  "cold",
+  "colorful",
+  "colorless",
+  "colossal",
+  "comfortable",
+  "common",
+  "compassionate",
+  "competent",
+  "complete",
+  "complex",
+  "complicated",
+  "composed",
+  "concerned",
+  "concrete",
+  "confused",
+  "conscious",
+  "considerate",
+  "constant",
+  "content",
+  "conventional",
+  "cooked",
+  "cool",
+  "cooperative",
+  "coordinated",
+  "corny",
+  "corrupt",
+  "costly",
+  "courageous",
+  "courteous",
+  "crafty",
+  "crazy",
+  "creamy",
+  "creative",
+  "creepy",
+  "criminal",
+  "crisp",
+  "critical",
+  "crooked",
+  "crowded",
+  "cruel",
+  "crushing",
+  "cuddly",
+  "cultivated",
+  "cultured",
+  "cumbersome",
+  "curly",
+  "curvy",
+  "cute",
+  "cylindrical",
+  "damaged",
+  "damp",
+  "dangerous",
+  "dapper",
+  "daring",
+  "darling",
+  "dark",
+  "dazzling",
+  "dead",
+  "deadly",
+  "deafening",
+  "dear",
+  "dearest",
+  "decent",
+  "decimal",
+  "decisive",
+  "deep",
+  "defenseless",
+  "defensive",
+  "defiant",
+  "deficient",
+  "definite",
+  "definitive",
+  "delayed",
+  "delectable",
+  "delicious",
+  "delightful",
+  "delirious",
+  "demanding",
+  "dense",
+  "dental",
+  "dependable",
+  "dependent",
+  "descriptive",
+  "deserted",
+  "detailed",
+  "determined",
+  "devoted",
+  "different",
+  "difficult",
+  "digital",
+  "diligent",
+  "dim",
+  "dimpled",
+  "dimwitted",
+  "direct",
+  "disastrous",
+  "discrete",
+  "disfigured",
+  "disgusting",
+  "disloyal",
+  "dismal",
+  "distant",
+  "downright",
+  "dreary",
+  "dirty",
+  "disguised",
+  "dishonest",
+  "dismal",
+  "distant",
+  "distinct",
+  "distorted",
+  "dizzy",
+  "dopey",
+  "doting",
+  "double",
+  "downright",
+  "drab",
+  "drafty",
+  "dramatic",
+  "dreary",
+  "droopy",
+  "dry",
+  "dual",
+  "dull",
+  "dutiful",
+  "each",
+  "eager",
+  "earnest",
+  "early",
+  "easy",
+  "easy-going",
+  "ecstatic",
+  "edible",
+  "educated",
+  "elaborate",
+  "elastic",
+  "elated",
+  "elderly",
+  "electric",
+  "elegant",
+  "elementary",
+  "elliptical",
+  "embarrassed",
+  "embellished",
+  "eminent",
+  "emotional",
+  "empty",
+  "enchanted",
+  "enchanting",
+  "energetic",
+  "enlightened",
+  "enormous",
+  "enraged",
+  "entire",
+  "envious",
+  "equal",
+  "equatorial",
+  "essential",
+  "esteemed",
+  "ethical",
+  "euphoric",
+  "even",
+  "evergreen",
+  "everlasting",
+  "every",
+  "evil",
+  "exalted",
+  "excellent",
+  "exemplary",
+  "exhausted",
+  "excitable",
+  "excited",
+  "exciting",
+  "exotic",
+  "expensive",
+  "experienced",
+  "expert",
+  "extraneous",
+  "extroverted",
+  "extra-large",
+  "extra-small",
+  "fabulous",
+  "failing",
+  "faint",
+  "fair",
+  "faithful",
+  "fake",
+  "false",
+  "familiar",
+  "famous",
+  "fancy",
+  "fantastic",
+  "far",
+  "faraway",
+  "far-flung",
+  "far-off",
+  "fast",
+  "fat",
+  "fatal",
+  "fatherly",
+  "favorable",
+  "favorite",
+  "fearful",
+  "fearless",
+  "feisty",
+  "feline",
+  "female",
+  "feminine",
+  "few",
+  "fickle",
+  "filthy",
+  "fine",
+  "finished",
+  "firm",
+  "first",
+  "firsthand",
+  "fitting",
+  "fixed",
+  "flaky",
+  "flamboyant",
+  "flashy",
+  "flat",
+  "flawed",
+  "flawless",
+  "flickering",
+  "flimsy",
+  "flippant",
+  "flowery",
+  "fluffy",
+  "fluid",
+  "flustered",
+  "focused",
+  "fond",
+  "foolhardy",
+  "foolish",
+  "forceful",
+  "forked",
+  "formal",
+  "forsaken",
+  "forthright",
+  "fortunate",
+  "fragrant",
+  "frail",
+  "frank",
+  "frayed",
+  "free",
+  "French",
+  "fresh",
+  "frequent",
+  "friendly",
+  "frightened",
+  "frightening",
+  "frigid",
+  "frilly",
+  "frizzy",
+  "frivolous",
+  "front",
+  "frosty",
+  "frozen",
+  "frugal",
+  "fruitful",
+  "full",
+  "fumbling",
+  "functional",
+  "funny",
+  "fussy",
+  "fuzzy",
+  "gargantuan",
+  "gaseous",
+  "general",
+  "generous",
+  "gentle",
+  "genuine",
+  "giant",
+  "giddy",
+  "gigantic",
+  "gifted",
+  "giving",
+  "glamorous",
+  "glaring",
+  "glass",
+  "gleaming",
+  "gleeful",
+  "glistening",
+  "glittering",
+  "gloomy",
+  "glorious",
+  "glossy",
+  "glum",
+  "golden",
+  "good",
+  "good-natured",
+  "gorgeous",
+  "graceful",
+  "gracious",
+  "grand",
+  "grandiose",
+  "granular",
+  "grateful",
+  "grave",
+  "gray",
+  "great",
+  "greedy",
+  "green",
+  "gregarious",
+  "grim",
+  "grimy",
+  "gripping",
+  "grizzled",
+  "gross",
+  "grotesque",
+  "grouchy",
+  "grounded",
+  "growing",
+  "growling",
+  "grown",
+  "grubby",
+  "gruesome",
+  "grumpy",
+  "guilty",
+  "gullible",
+  "gummy",
+  "hairy",
+  "half",
+  "handmade",
+  "handsome",
+  "handy",
+  "happy",
+  "happy-go-lucky",
+  "hard",
+  "hard-to-find",
+  "harmful",
+  "harmless",
+  "harmonious",
+  "harsh",
+  "hasty",
+  "hateful",
+  "haunting",
+  "healthy",
+  "heartfelt",
+  "hearty",
+  "heavenly",
+  "heavy",
+  "hefty",
+  "helpful",
+  "helpless",
+  "hidden",
+  "hideous",
+  "high",
+  "high-level",
+  "hilarious",
+  "hoarse",
+  "hollow",
+  "homely",
+  "honest",
+  "honorable",
+  "honored",
+  "hopeful",
+  "horrible",
+  "hospitable",
+  "hot",
+  "huge",
+  "humble",
+  "humiliating",
+  "humming",
+  "humongous",
+  "hungry",
+  "hurtful",
+  "husky",
+  "icky",
+  "icy",
+  "ideal",
+  "idealistic",
+  "identical",
+  "idle",
+  "idiotic",
+  "idolized",
+  "ignorant",
+  "ill",
+  "illegal",
+  "ill-fated",
+  "ill-informed",
+  "illiterate",
+  "illustrious",
+  "imaginary",
+  "imaginative",
+  "immaculate",
+  "immaterial",
+  "immediate",
+  "immense",
+  "impassioned",
+  "impeccable",
+  "impartial",
+  "imperfect",
+  "imperturbable",
+  "impish",
+  "impolite",
+  "important",
+  "impossible",
+  "impractical",
+  "impressionable",
+  "impressive",
+  "improbable",
+  "impure",
+  "inborn",
+  "incomparable",
+  "incompatible",
+  "incomplete",
+  "inconsequential",
+  "incredible",
+  "indelible",
+  "inexperienced",
+  "indolent",
+  "infamous",
+  "infantile",
+  "infatuated",
+  "inferior",
+  "infinite",
+  "informal",
+  "innocent",
+  "insecure",
+  "insidious",
+  "insignificant",
+  "insistent",
+  "instructive",
+  "insubstantial",
+  "intelligent",
+  "intent",
+  "intentional",
+  "interesting",
+  "internal",
+  "international",
+  "intrepid",
+  "ironclad",
+  "irresponsible",
+  "irritating",
+  "itchy",
+  "jaded",
+  "jagged",
+  "jam-packed",
+  "jaunty",
+  "jealous",
+  "jittery",
+  "joint",
+  "jolly",
+  "jovial",
+  "joyful",
+  "joyous",
+  "jubilant",
+  "judicious",
+  "juicy",
+  "jumbo",
+  "junior",
+  "jumpy",
+  "juvenile",
+  "kaleidoscopic",
+  "keen",
+  "key",
+  "kind",
+  "kindhearted",
+  "kindly",
+  "klutzy",
+  "knobby",
+  "knotty",
+  "knowledgeable",
+  "knowing",
+  "known",
+  "kooky",
+  "kosher",
+  "lame",
+  "lanky",
+  "large",
+  "last",
+  "lasting",
+  "late",
+  "lavish",
+  "lawful",
+  "lazy",
+  "leading",
+  "lean",
+  "leafy",
+  "left",
+  "legal",
+  "legitimate",
+  "light",
+  "lighthearted",
+  "likable",
+  "likely",
+  "limited",
+  "limp",
+  "limping",
+  "linear",
+  "lined",
+  "liquid",
+  "little",
+  "live",
+  "lively",
+  "livid",
+  "loathsome",
+  "lone",
+  "lonely",
+  "long",
+  "long-term",
+  "loose",
+  "lopsided",
+  "lost",
+  "loud",
+  "lovable",
+  "lovely",
+  "loving",
+  "low",
+  "loyal",
+  "lucky",
+  "lumbering",
+  "luminous",
+  "lumpy",
+  "lustrous",
+  "luxurious",
+  "mad",
+  "made-up",
+  "magnificent",
+  "majestic",
+  "major",
+  "male",
+  "mammoth",
+  "married",
+  "marvelous",
+  "masculine",
+  "massive",
+  "mature",
+  "meager",
+  "mealy",
+  "mean",
+  "measly",
+  "meaty",
+  "medical",
+  "mediocre",
+  "medium",
+  "meek",
+  "mellow",
+  "melodic",
+  "memorable",
+  "menacing",
+  "merry",
+  "messy",
+  "metallic",
+  "mild",
+  "milky",
+  "mindless",
+  "miniature",
+  "minor",
+  "minty",
+  "miserable",
+  "miserly",
+  "misguided",
+  "misty",
+  "mixed",
+  "modern",
+  "modest",
+  "moist",
+  "monstrous",
+  "monthly",
+  "monumental",
+  "moral",
+  "mortified",
+  "motherly",
+  "motionless",
+  "mountainous",
+  "muddy",
+  "muffled",
+  "multicolored",
+  "mundane",
+  "murky",
+  "mushy",
+  "musty",
+  "muted",
+  "mysterious",
+  "naive",
+  "narrow",
+  "nasty",
+  "natural",
+  "naughty",
+  "nautical",
+  "near",
+  "neat",
+  "necessary",
+  "needy",
+  "negative",
+  "neglected",
+  "negligible",
+  "neighboring",
+  "nervous",
+  "new",
+  "next",
+  "nice",
+  "nifty",
+  "nimble",
+  "nippy",
+  "nocturnal",
+  "noisy",
+  "nonstop",
+  "normal",
+  "notable",
+  "noted",
+  "noteworthy",
+  "novel",
+  "noxious",
+  "numb",
+  "nutritious",
+  "nutty",
+  "obedient",
+  "obese",
+  "oblong",
+  "oily",
+  "oblong",
+  "obvious",
+  "occasional",
+  "odd",
+  "oddball",
+  "offbeat",
+  "offensive",
+  "official",
+  "old",
+  "old-fashioned",
+  "only",
+  "open",
+  "optimal",
+  "optimistic",
+  "opulent",
+  "orange",
+  "orderly",
+  "organic",
+  "ornate",
+  "ornery",
+  "ordinary",
+  "original",
+  "other",
+  "our",
+  "outlying",
+  "outgoing",
+  "outlandish",
+  "outrageous",
+  "outstanding",
+  "oval",
+  "overcooked",
+  "overdue",
+  "overjoyed",
+  "overlooked",
+  "palatable",
+  "pale",
+  "paltry",
+  "parallel",
+  "parched",
+  "partial",
+  "passionate",
+  "past",
+  "pastel",
+  "peaceful",
+  "peppery",
+  "perfect",
+  "perfumed",
+  "periodic",
+  "perky",
+  "personal",
+  "pertinent",
+  "pesky",
+  "pessimistic",
+  "petty",
+  "phony",
+  "physical",
+  "piercing",
+  "pink",
+  "pitiful",
+  "plain",
+  "plaintive",
+  "plastic",
+  "playful",
+  "pleasant",
+  "pleased",
+  "pleasing",
+  "plump",
+  "plush",
+  "polished",
+  "polite",
+  "political",
+  "pointed",
+  "pointless",
+  "poised",
+  "poor",
+  "popular",
+  "portly",
+  "posh",
+  "positive",
+  "possible",
+  "potable",
+  "powerful",
+  "powerless",
+  "practical",
+  "precious",
+  "present",
+  "prestigious",
+  "pretty",
+  "precious",
+  "previous",
+  "pricey",
+  "prickly",
+  "primary",
+  "prime",
+  "pristine",
+  "private",
+  "prize",
+  "probable",
+  "productive",
+  "profitable",
+  "profuse",
+  "proper",
+  "proud",
+  "prudent",
+  "punctual",
+  "pungent",
+  "puny",
+  "pure",
+  "purple",
+  "pushy",
+  "putrid",
+  "puzzled",
+  "puzzling",
+  "quaint",
+  "qualified",
+  "quarrelsome",
+  "quarterly",
+  "queasy",
+  "querulous",
+  "questionable",
+  "quick",
+  "quick-witted",
+  "quiet",
+  "quintessential",
+  "quirky",
+  "quixotic",
+  "quizzical",
+  "radiant",
+  "ragged",
+  "rapid",
+  "rare",
+  "rash",
+  "raw",
+  "recent",
+  "reckless",
+  "rectangular",
+  "ready",
+  "real",
+  "realistic",
+  "reasonable",
+  "red",
+  "reflecting",
+  "regal",
+  "regular",
+  "reliable",
+  "relieved",
+  "remarkable",
+  "remorseful",
+  "remote",
+  "repentant",
+  "required",
+  "respectful",
+  "responsible",
+  "repulsive",
+  "revolving",
+  "rewarding",
+  "rich",
+  "rigid",
+  "right",
+  "ringed",
+  "ripe",
+  "roasted",
+  "robust",
+  "rosy",
+  "rotating",
+  "rotten",
+  "rough",
+  "round",
+  "rowdy",
+  "royal",
+  "rubbery",
+  "rundown",
+  "ruddy",
+  "rude",
+  "runny",
+  "rural",
+  "rusty",
+  "sad",
+  "safe",
+  "salty",
+  "same",
+  "sandy",
+  "sane",
+  "sarcastic",
+  "sardonic",
+  "satisfied",
+  "scaly",
+  "scarce",
+  "scared",
+  "scary",
+  "scented",
+  "scholarly",
+  "scientific",
+  "scornful",
+  "scratchy",
+  "scrawny",
+  "second",
+  "secondary",
+  "second-hand",
+  "secret",
+  "self-assured",
+  "self-reliant",
+  "selfish",
+  "sentimental",
+  "separate",
+  "serene",
+  "serious",
+  "serpentine",
+  "several",
+  "severe",
+  "shabby",
+  "shadowy",
+  "shady",
+  "shallow",
+  "shameful",
+  "shameless",
+  "sharp",
+  "shimmering",
+  "shiny",
+  "shocked",
+  "shocking",
+  "shoddy",
+  "short",
+  "short-term",
+  "showy",
+  "shrill",
+  "shy",
+  "sick",
+  "silent",
+  "silky",
+  "silly",
+  "silver",
+  "similar",
+  "simple",
+  "simplistic",
+  "sinful",
+  "single",
+  "sizzling",
+  "skeletal",
+  "skinny",
+  "sleepy",
+  "slight",
+  "slim",
+  "slimy",
+  "slippery",
+  "slow",
+  "slushy",
+  "small",
+  "smart",
+  "smoggy",
+  "smooth",
+  "smug",
+  "snappy",
+  "snarling",
+  "sneaky",
+  "sniveling",
+  "snoopy",
+  "sociable",
+  "soft",
+  "soggy",
+  "solid",
+  "somber",
+  "some",
+  "spherical",
+  "sophisticated",
+  "sore",
+  "sorrowful",
+  "soulful",
+  "soupy",
+  "sour",
+  "Spanish",
+  "sparkling",
+  "sparse",
+  "specific",
+  "spectacular",
+  "speedy",
+  "spicy",
+  "spiffy",
+  "spirited",
+  "spiteful",
+  "splendid",
+  "spotless",
+  "spotted",
+  "spry",
+  "square",
+  "squeaky",
+  "squiggly",
+  "stable",
+  "staid",
+  "stained",
+  "stale",
+  "standard",
+  "starchy",
+  "stark",
+  "starry",
+  "steep",
+  "sticky",
+  "stiff",
+  "stimulating",
+  "stingy",
+  "stormy",
+  "straight",
+  "strange",
+  "steel",
+  "strict",
+  "strident",
+  "striking",
+  "striped",
+  "strong",
+  "studious",
+  "stunning",
+  "stupendous",
+  "stupid",
+  "sturdy",
+  "stylish",
+  "subdued",
+  "submissive",
+  "substantial",
+  "subtle",
+  "suburban",
+  "sudden",
+  "sugary",
+  "sunny",
+  "super",
+  "superb",
+  "superficial",
+  "superior",
+  "supportive",
+  "sure-footed",
+  "surprised",
+  "suspicious",
+  "svelte",
+  "sweaty",
+  "sweet",
+  "sweltering",
+  "swift",
+  "sympathetic",
+  "tall",
+  "talkative",
+  "tame",
+  "tan",
+  "tangible",
+  "tart",
+  "tasty",
+  "tattered",
+  "taut",
+  "tedious",
+  "teeming",
+  "tempting",
+  "tender",
+  "tense",
+  "tepid",
+  "terrible",
+  "terrific",
+  "testy",
+  "thankful",
+  "that",
+  "these",
+  "thick",
+  "thin",
+  "third",
+  "thirsty",
+  "this",
+  "thorough",
+  "thorny",
+  "those",
+  "thoughtful",
+  "threadbare",
+  "thrifty",
+  "thunderous",
+  "tidy",
+  "tight",
+  "timely",
+  "tinted",
+  "tiny",
+  "tired",
+  "torn",
+  "total",
+  "tough",
+  "traumatic",
+  "treasured",
+  "tremendous",
+  "tragic",
+  "trained",
+  "tremendous",
+  "triangular",
+  "tricky",
+  "trifling",
+  "trim",
+  "trivial",
+  "troubled",
+  "true",
+  "trusting",
+  "trustworthy",
+  "trusty",
+  "truthful",
+  "tubby",
+  "turbulent",
+  "twin",
+  "ugly",
+  "ultimate",
+  "unacceptable",
+  "unaware",
+  "uncomfortable",
+  "uncommon",
+  "unconscious",
+  "understated",
+  "unequaled",
+  "uneven",
+  "unfinished",
+  "unfit",
+  "unfolded",
+  "unfortunate",
+  "unhappy",
+  "unhealthy",
+  "uniform",
+  "unimportant",
+  "unique",
+  "united",
+  "unkempt",
+  "unknown",
+  "unlawful",
+  "unlined",
+  "unlucky",
+  "unnatural",
+  "unpleasant",
+  "unrealistic",
+  "unripe",
+  "unruly",
+  "unselfish",
+  "unsightly",
+  "unsteady",
+  "unsung",
+  "untidy",
+  "untimely",
+  "untried",
+  "untrue",
+  "unused",
+  "unusual",
+  "unwelcome",
+  "unwieldy",
+  "unwilling",
+  "unwitting",
+  "unwritten",
+  "upbeat",
+  "upright",
+  "upset",
+  "urban",
+  "usable",
+  "used",
+  "useful",
+  "useless",
+  "utilized",
+  "utter",
+  "vacant",
+  "vague",
+  "vain",
+  "valid",
+  "valuable",
+  "vapid",
+  "variable",
+  "vast",
+  "velvety",
+  "venerated",
+  "vengeful",
+  "verifiable",
+  "vibrant",
+  "vicious",
+  "victorious",
+  "vigilant",
+  "vigorous",
+  "villainous",
+  "violet",
+  "violent",
+  "virtual",
+  "virtuous",
+  "visible",
+  "vital",
+  "vivacious",
+  "vivid",
+  "voluminous",
+  "wan",
+  "warlike",
+  "warm",
+  "warmhearted",
+  "warped",
+  "wary",
+  "wasteful",
+  "watchful",
+  "waterlogged",
+  "watery",
+  "wavy",
+  "wealthy",
+  "weak",
+  "weary",
+  "webbed",
+  "wee",
+  "weekly",
+  "weepy",
+  "weighty",
+  "weird",
+  "welcome",
+  "well-documented",
+  "well-groomed",
+  "well-informed",
+  "well-lit",
+  "well-made",
+  "well-off",
+  "well-to-do",
+  "well-worn",
+  "wet",
+  "which",
+  "whimsical",
+  "whirlwind",
+  "whispered",
+  "white",
+  "whole",
+  "whopping",
+  "wicked",
+  "wide",
+  "wide-eyed",
+  "wiggly",
+  "wild",
+  "willing",
+  "wilted",
+  "winding",
+  "windy",
+  "winged",
+  "wiry",
+  "wise",
+  "witty",
+  "wobbly",
+  "woeful",
+  "wonderful",
+  "wooden",
+  "woozy",
+  "wordy",
+  "worldly",
+  "worn",
+  "worried",
+  "worrisome",
+  "worse",
+  "worst",
+  "worthless",
+  "worthwhile",
+  "worthy",
+  "wrathful",
+  "wretched",
+  "writhing",
+  "wrong",
+  "wry",
+  "yawning",
+  "yearly",
+  "yellow",
+  "yellowish",
+  "young",
+  "youthful",
+  "yummy",
+  "zany",
+  "zealous",
+  "zesty",
+  "zigzag",
 ]
 
-export function getRandomUsername(): string {
-    const n = Math.random() * noun.length
-    const a = Math.random() * adj.length
-    return `tmp-${a}-${n}`
+export function getRandomUsername(): { first: string, second: string } {
+  const n = Math.floor(Math.random() * noun.length)
+  const a = Math.floor(Math.random() * adj.length)
+  return {
+    first: adj[a],
+    second: noun[n]
+  }
 }
 
 export function getRandomPassword(): string {
-    return encodeCrock(getRandomBytes(16))
+  if (bankUiSettings.simplePasswordForRandomAccounts) return "123"
+  return encodeCrock(getRandomBytes(16))
 }
\ No newline at end of file
diff --git a/packages/demobank-ui/src/settings.ts b/packages/demobank-ui/src/settings.ts
index 6c78d287b..f33bf07e2 100644
--- a/packages/demobank-ui/src/settings.ts
+++ b/packages/demobank-ui/src/settings.ts
@@ -18,6 +18,8 @@ export interface BankUiSettings {
   backendBaseURL: string;
   allowRegistrations: boolean;
   showDemoNav: boolean;
+  simplePasswordForRandomAccounts: boolean;
+  allowRandomAccountCreation: boolean;
   bankName: string;
   demoSites: [string, string][];
 }
@@ -30,6 +32,8 @@ const defaultSettings: BankUiSettings = {
   allowRegistrations: true,
   bankName: "Taler Bank",
   showDemoNav: true,
+  simplePasswordForRandomAccounts: true,
+  allowRandomAccountCreation: true,
   demoSites: [
     ["Landing", "https://demo.taler.net/"],
     ["Bank", "https://bank.demo.taler.net/"],
-- 
cgit v1.2.3


From 0b2c03dc5e1060cd229aeafb84263f171b5a9788 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Mon, 25 Sep 2023 09:31:17 -0300
Subject: new libeufin api

---
 packages/demobank-ui/src/declaration.d.ts          |  9 ++---
 packages/demobank-ui/src/hooks/backend.ts          | 43 +++++-----------------
 packages/demobank-ui/src/hooks/circuit.ts          | 23 +++++++-----
 .../demobank-ui/src/hooks/useCredentialsChecker.ts | 12 +++---
 .../demobank-ui/src/pages/AccountPage/state.ts     |  4 +-
 .../demobank-ui/src/pages/AccountPage/views.tsx    | 10 ++---
 packages/demobank-ui/src/pages/BankFrame.tsx       |  6 +--
 packages/demobank-ui/src/pages/LoginForm.tsx       |  8 ++--
 .../demobank-ui/src/pages/RegistrationPage.tsx     | 12 +++++-
 packages/demobank-ui/src/pages/admin/Account.tsx   |  7 +---
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  |  4 +-
 packages/demobank-ui/src/pages/business/Home.tsx   |  7 +---
 packages/demobank-ui/src/stories.test.ts           |  3 +-
 13 files changed, 60 insertions(+), 88 deletions(-)

(limited to 'packages/demobank-ui/src/pages/admin/RemoveAccount.tsx')

diff --git a/packages/demobank-ui/src/declaration.d.ts b/packages/demobank-ui/src/declaration.d.ts
index a9573fbcd..0c083a939 100644
--- a/packages/demobank-ui/src/declaration.d.ts
+++ b/packages/demobank-ui/src/declaration.d.ts
@@ -319,11 +319,10 @@ namespace SandboxBackend {
     interface ListBankAccountsResponse {
       accounts: AccountMinimalData[];
     }
-    // interface Balance {
-    //   amount: Amount;
-    //   credit_debit_indicator: "credit" | "debit";
-    // }
-    type Balance = Amount
+    interface Balance {
+      amount: Amount;
+      credit_debit_indicator: "credit" | "debit";
+    }
     interface AccountMinimalData {
       // Username
       username: string;
diff --git a/packages/demobank-ui/src/hooks/backend.ts b/packages/demobank-ui/src/hooks/backend.ts
index f2be90f08..e6a3a1c0c 100644
--- a/packages/demobank-ui/src/hooks/backend.ts
+++ b/packages/demobank-ui/src/hooks/backend.ts
@@ -40,6 +40,7 @@ import { useCallback, useEffect, useState } from "preact/hooks";
 import { useSWRConfig } from "swr";
 import { useBackendContext } from "../context/backend.js";
 import { bankUiSettings } from "../settings.js";
+import { AccessToken } from "./useCredentialsChecker.js";
 
 /**
  * Has the information to reach and
@@ -49,7 +50,7 @@ export type BackendState = LoggedIn | LoggedOut;
 
 export interface BackendCredentials {
   username: string;
-  password: string;
+  token: AccessToken;
 }
 
 interface LoggedIn extends BackendCredentials {
@@ -64,7 +65,7 @@ export const codecForBackendStateLoggedIn = (): Codec<LoggedIn> =>
   buildCodecForObject<LoggedIn>()
     .property("status", codecForConstString("loggedIn"))
     .property("username", codecForString())
-    .property("password", codecForString())
+    .property("token", codecForString() as Codec<AccessToken>)
     .property("isUserAdministrator", codecForBoolean())
     .build("BackendState.LoggedIn");
 
@@ -255,35 +256,11 @@ interface InvalidationResult {
   error: unknown;
 }
 
-export function useCredentialsCheckerOld() {
-  const { request } = useApiContext();
-  const baseUrl = getInitialBackendBaseURL();
-  //check against account details endpoint
-  //while sandbox backend doesn't have a login endpoint
-  return async function testLogin(
-    username: string,
-    password: string,
-  ): Promise<CheckResult> {
-    try {
-      await request(baseUrl, `access-api/accounts/${username}/`, {
-        basicAuth: { username, password },
-        preventCache: true,
-      });
-      return { valid: true };
-    } catch (error) {
-      if (error instanceof RequestError) {
-        return { valid: false, requestError: true, cause: error.cause };
-      }
-      return { valid: false, requestError: false, error };
-    }
-  };
-}
-
 export function useAuthenticatedBackend(): useBackendType {
   const { state } = useBackendContext();
   const { request: requestHandler } = useApiContext();
 
-  const creds = state.status === "loggedIn" ? state : undefined;
+  const creds = state.status === "loggedIn" ? state.token : undefined;
   const baseUrl = getInitialBackendBaseURL();
 
   const request = useCallback(
@@ -291,14 +268,14 @@ export function useAuthenticatedBackend(): useBackendType {
       path: string,
       options: RequestOptions = {},
     ): Promise<HttpResponseOk<T>> {
-      return requestHandler<T>(baseUrl, path, { basicAuth: creds, ...options });
+      return requestHandler<T>(baseUrl, path, { token: creds, ...options });
     },
     [baseUrl, creds],
   );
 
   const fetcher = useCallback(
     function fetcherImpl<T>(endpoint: string): Promise<HttpResponseOk<T>> {
-      return requestHandler<T>(baseUrl, endpoint, { basicAuth: creds });
+      return requestHandler<T>(baseUrl, endpoint, { token: creds });
     },
     [baseUrl, creds],
   );
@@ -309,7 +286,7 @@ export function useAuthenticatedBackend(): useBackendType {
       number,
     ]): Promise<HttpResponseOk<T>> {
       return requestHandler<T>(baseUrl, endpoint, {
-        basicAuth: creds,
+        token: creds,
         params: { delta: size, start: size * page },
       });
     },
@@ -321,7 +298,7 @@ export function useAuthenticatedBackend(): useBackendType {
     > {
       return Promise.all(
         endpoints.map((endpoint) =>
-          requestHandler<T>(baseUrl, endpoint, { basicAuth: creds }),
+          requestHandler<T>(baseUrl, endpoint, { token: creds }),
         ),
       );
     },
@@ -335,7 +312,7 @@ export function useAuthenticatedBackend(): useBackendType {
       string,
     ]): Promise<HttpResponseOk<T>> {
       return requestHandler<T>(baseUrl, endpoint, {
-        basicAuth: creds,
+        token: creds,
         params: { page: page || 1, size },
       });
     },
@@ -347,7 +324,7 @@ export function useAuthenticatedBackend(): useBackendType {
       HttpResponseOk<T>
     > {
       return requestHandler<T>(baseUrl, endpoint, {
-        basicAuth: creds,
+        token: creds,
         params: { account },
       });
     },
diff --git a/packages/demobank-ui/src/hooks/circuit.ts b/packages/demobank-ui/src/hooks/circuit.ts
index 06557b77f..4ef80b055 100644
--- a/packages/demobank-ui/src/hooks/circuit.ts
+++ b/packages/demobank-ui/src/hooks/circuit.ts
@@ -33,6 +33,7 @@ import {
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
 import _useSWR, { SWRHook } from "swr";
 import { AmountJson, Amounts } from "@gnu-taler/taler-util";
+import { AccessToken } from "./useCredentialsChecker.js";
 const useSWR = _useSWR as unknown as SWRHook;
 
 export function useAdminAccountAPI(): AdminAccountAPI {
@@ -90,7 +91,8 @@ export function useAdminAccountAPI(): AdminAccountAPI {
       await mutateAll(/.*/);
       logIn({
         username: account,
-        password: data.new_password,
+        //FIXME: change password api
+        token: data.new_password as AccessToken,
       });
     }
     return res;
@@ -215,14 +217,15 @@ export interface CircuitAccountAPI {
 
 async function getBusinessStatus(
   request: ReturnType<typeof useApiContext>["request"],
-  basicAuth: { username: string; password: string },
+  username: string,
+  token: AccessToken,
 ): Promise<boolean> {
   try {
     const url = getInitialBackendBaseURL();
     const result = await request<SandboxBackend.Circuit.CircuitAccountData>(
       url,
-      `circuit-api/accounts/${basicAuth.username}`,
-      { basicAuth },
+      `circuit-api/accounts/${username}`,
+      { token },
     );
     return result.ok;
   } catch (error) {
@@ -264,10 +267,10 @@ type CashoutEstimators = {
 export function useEstimator(): CashoutEstimators {
   const { state } = useBackendContext();
   const { request } = useApiContext();
-  const basicAuth =
+  const creds =
     state.status === "loggedOut"
       ? undefined
-      : { username: state.username, password: state.password };
+      : state.token;
   return {
     estimateByCredit: async (amount, fee, rate) => {
       const zeroBalance = Amounts.zeroOfCurrency(fee.currency);
@@ -282,7 +285,7 @@ export function useEstimator(): CashoutEstimators {
         url,
         `circuit-api/cashouts/estimates`,
         {
-          basicAuth,
+          token: creds,
           params: {
             amount_credit: Amounts.stringify(amount),
           },
@@ -313,7 +316,7 @@ export function useEstimator(): CashoutEstimators {
         url,
         `circuit-api/cashouts/estimates`,
         {
-          basicAuth,
+          token: creds,
           params: {
             amount_debit: Amounts.stringify(amount),
           },
@@ -339,11 +342,11 @@ export function useBusinessAccountFlag(): boolean | undefined {
   const creds =
     state.status === "loggedOut"
       ? undefined
-      : { username: state.username, password: state.password };
+      : {user: state.username, token: state.token};
 
   useEffect(() => {
     if (!creds) return;
-    getBusinessStatus(request, creds)
+    getBusinessStatus(request, creds.user, creds.token)
       .then((result) => {
         setIsBusiness(result);
       })
diff --git a/packages/demobank-ui/src/hooks/useCredentialsChecker.ts b/packages/demobank-ui/src/hooks/useCredentialsChecker.ts
index 05954348f..f66a4a7c6 100644
--- a/packages/demobank-ui/src/hooks/useCredentialsChecker.ts
+++ b/packages/demobank-ui/src/hooks/useCredentialsChecker.ts
@@ -23,13 +23,13 @@ export function useCredentialsChecker() {
       const response = await request<LoginTokenSuccessResponse>(baseUrl, `accounts/${username}/token`, {
         method: "POST",
         basicAuth: {
-          username: username,
+          username,
           password,
         },
         data,
         contentType: "json"
       });
-      return { valid: true, token: response.data.token, expiration: response.data.expiration };
+      return { valid: true, token: `secret-token:${response.data.access_token}` as AccessToken, expiration: response.data.expiration };
     } catch (error) {
       if (error instanceof RequestError) {
         return { valid: false, cause: error.cause };
@@ -76,13 +76,13 @@ export function useCredentialsChecker() {
       }
     }
 
-    return requestNewLoginToken(baseUrl, token.token as AccessToken)
+    return requestNewLoginToken(baseUrl, token.token)
   }
   return { requestNewLoginToken, refreshLoginToken }
 }
 
 export interface LoginToken {
-  token: string,
+  token: AccessToken,
   expiration: Timestamp,
 }
 // token used to get loginToken
@@ -95,7 +95,7 @@ export type AccessToken = string & {
 type YesOrNo = "yes" | "no";
 export type LoginResult = {
   valid: true;
-  token: string;
+  token: AccessToken;
   expiration: Timestamp;
 } | {
   valid: false;
@@ -121,7 +121,7 @@ export interface LoginTokenSuccessResponse {
   // that are in scope for some time. Must be prefixed
   // with "Bearer " when used in the "Authorization" HTTP header.
   // Will already begin with the RFC 8959 prefix.
-  token: string;
+  access_token: AccessToken;
 
   // Scope of the token (which kinds of operations it will allow)
   scope: "readonly" | "write";
diff --git a/packages/demobank-ui/src/pages/AccountPage/state.ts b/packages/demobank-ui/src/pages/AccountPage/state.ts
index 3df463f4e..a23d3b569 100644
--- a/packages/demobank-ui/src/pages/AccountPage/state.ts
+++ b/packages/demobank-ui/src/pages/AccountPage/state.ts
@@ -63,9 +63,7 @@ export function useComponentState({ account, goToBusinessAccount, goToConfirmOpe
 
   const { data } = result;
 
-  // FIXME: balance
-  // const balance = Amounts.parseOrThrow(data.balance.amount);
-  const balance = Amounts.parseOrThrow(data.balance);
+  const balance = Amounts.parseOrThrow(data.balance.amount);
 
   const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
   const payto = parsePaytoUri(data.payto_uri);
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index b3996c5fc..32aedebf2 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -14,16 +14,14 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { Amounts, stringifyPaytoUri } from "@gnu-taler/taler-util";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
 import { Transactions } from "../../components/Transactions/index.js";
-import { PaymentOptions } from "../PaymentOptions.js";
-import { State } from "./index.js";
-import { CopyButton } from "../../components/CopyButton.js";
-import { bankUiSettings } from "../../settings.js";
 import { useBusinessAccountDetails } from "../../hooks/circuit.js";
 import { useSettings } from "../../hooks/settings.js";
+import { bankUiSettings } from "../../settings.js";
+import { PaymentOptions } from "../PaymentOptions.js";
+import { State } from "./index.js";
 
 export function InvalidIbanView({ error }: State.InvalidIban) {
   return (
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index 214aac063..39ca09f1b 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -474,11 +474,9 @@ function AccountBalance({ account }: { account: string }): VNode {
   const result = useAccountDetails(account);
   if (!result.ok) return <div />
 
-  // FIXME: balance
   return <div>
-    {Amounts.currencyOf(result.data.balance)} {Amounts.stringifyValue(result.data.balance)}
-    {/* {Amounts.currencyOf(result.data.balance.amount)}
+    {Amounts.currencyOf(result.data.balance.amount)}
     &nbsp;{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""}
-    {Amounts.stringifyValue(result.data.balance.amount)} */}
+    {Amounts.stringifyValue(result.data.balance.amount)}
   </div>
 }
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx
index cfef71b9a..f1ba439ac 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -18,13 +18,11 @@ import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
 import { ErrorType, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useEffect, useRef, useState } from "preact/hooks";
+import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
 import { useBackendContext } from "../context/backend.js";
+import { useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
 import { bankUiSettings } from "../settings.js";
 import { undefinedIfEmpty } from "../utils.js";
-import { USERNAME_REGEX } from "./RegistrationPage.js";
-import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
-import { AccessToken, useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
-import { useCredentialsCheckerOld } from "../hooks/backend.js";
 
 /**
  * Collect and submit login data.
@@ -62,7 +60,7 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
     setBusy({})
     const result = await requestNewLoginToken(username, password);
     if (result.valid) {
-      backend.logIn({ username, password });
+      backend.logIn({ username, token: result.token });
     } else {
       const { cause } = result;
       switch (cause.type) {
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index 5325f43ab..a2543f977 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -28,6 +28,7 @@ import { bankUiSettings } from "../settings.js";
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
 import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
 import { getRandomPassword, getRandomUsername } from "./rnd.js";
+import { useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
 
 const logger = new Logger("RegistrationPage");
 
@@ -58,6 +59,7 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on
   const [name, setName] = useState<string | undefined>();
   const [password, setPassword] = useState<string | undefined>();
   const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
+  const {requestNewLoginToken} = useCredentialsChecker()
 
   const { register } = useTestingAPI();
   const { i18n } = useTranslationContext();
@@ -83,8 +85,11 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on
     if (!username || !password || !name) return;
     try {
       await register({ name, username, password });
+      const resp = await requestNewLoginToken(username, password)
       setUsername(undefined);
-      backend.logIn({ username, password });
+      if (resp.valid) {
+        backend.logIn({ username, token: resp.token });
+      }
       onComplete();
     } catch (error) {
       if (error instanceof RequestError) {
@@ -125,7 +130,10 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on
       setRepeatPassword(undefined);
       const username = `_${user.first}-${user.second}_`
       await register({ username, name: `${user.first} ${user.second}`, password: pass });
-      backend.logIn({ username, password: pass });
+      const resp = await requestNewLoginToken(username, pass)
+      if (resp.valid) {
+        backend.logIn({ username, token: resp.token });
+      }
       onComplete();
     } catch (error) {
       if (error instanceof RequestError) {
diff --git a/packages/demobank-ui/src/pages/admin/Account.tsx b/packages/demobank-ui/src/pages/admin/Account.tsx
index d368c4319..8ea59cdcb 100644
--- a/packages/demobank-ui/src/pages/admin/Account.tsx
+++ b/packages/demobank-ui/src/pages/admin/Account.tsx
@@ -17,11 +17,8 @@ export function AdminAccount({ onRegister }: { onRegister: () => void }): VNode
   }
   const { data } = result;
 
-  //FIXME: libeufin does not follow the spec
-  const balance = Amounts.parseOrThrow(data.balance);
-  const balanceIsDebit = true;
-  // const balance = Amounts.parseOrThrow(data.balance.amount);
-  // const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+  const balance = Amounts.parseOrThrow(data.balance.amount);
+  const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
   
   const debitThreshold = Amounts.parseOrThrow(result.data.debit_threshold);
   const limit = balanceIsDebit
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index 63a7c79f3..1e5370afc 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -41,9 +41,7 @@ export function RemoveAccount({
     if (focus) ref.current?.focus();
   }, [focus]);
 
-  //FIXME: libeufin does not follow the spec
-  const balance = Amounts.parse(result.data.balance);
-  // const balance = Amounts.parse(result.data.balance.amount);
+  const balance = Amounts.parse(result.data.balance.amount);
   if (!balance) {
     return <div>there was an error reading the balance</div>;
   }
diff --git a/packages/demobank-ui/src/pages/business/Home.tsx b/packages/demobank-ui/src/pages/business/Home.tsx
index 427cfc656..628ae328d 100644
--- a/packages/demobank-ui/src/pages/business/Home.tsx
+++ b/packages/demobank-ui/src/pages/business/Home.tsx
@@ -236,11 +236,8 @@ function CreateCashout({
   if (!ratiosResult.ok) return onLoadNotOk(ratiosResult);
   const config = ratiosResult.data;
 
-  //FIXME: libeufin does not follow the spec
-  const balance = Amounts.parseOrThrow(result.data.balance);
-  const balanceIsDebit = true;
-  // const balance = Amounts.parseOrThrow(result.data.balance.amount);
-  // const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+  const balance = Amounts.parseOrThrow(result.data.balance.amount);
+  const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
 
   const debitThreshold = Amounts.parseOrThrow(result.data.debit_threshold);
   const zero = Amounts.zeroOfCurrency(balance.currency);
diff --git a/packages/demobank-ui/src/stories.test.ts b/packages/demobank-ui/src/stories.test.ts
index e68788f16..07db7d8cf 100644
--- a/packages/demobank-ui/src/stories.test.ts
+++ b/packages/demobank-ui/src/stories.test.ts
@@ -26,6 +26,7 @@ import * as pages from "./pages/index.stories.js";
 
 import { ComponentChildren, VNode, h as create } from "preact";
 import { BackendStateProviderTesting } from "./context/backend.js";
+import { AccessToken } from "./hooks/useCredentialsChecker.js";
 
 setupI18n("en", { en: {} });
 
@@ -56,7 +57,7 @@ function DefaultTestingContext({
     state: {
       status: "loggedIn",
       username: "test",
-      password: "pwd",
+      token: "pwd" as AccessToken,
       isUserAdministrator: false,
     },
   });
-- 
cgit v1.2.3


From 1708d49a2d5da1f325173a030695223e5a24e75c Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Fri, 29 Sep 2023 16:02:15 -0300
Subject: more ui

---
 packages/demobank-ui/dev.mjs                       |   2 +-
 packages/demobank-ui/src/components/Attention.tsx  |  59 +++++
 .../demobank-ui/src/components/ErrorLoading.tsx    |  22 +-
 .../src/components/Transactions/views.tsx          |  51 ++--
 packages/demobank-ui/src/demobank-ui-settings.js   |  21 ++
 packages/demobank-ui/src/hooks/access.ts           |   3 +-
 packages/demobank-ui/src/hooks/circuit.ts          |   2 +-
 packages/demobank-ui/src/hooks/settings.ts         |   3 +
 .../demobank-ui/src/pages/AccountPage/views.tsx    |  62 ++---
 packages/demobank-ui/src/pages/BankFrame.tsx       | 104 ++++----
 packages/demobank-ui/src/pages/HomePage.tsx        |   6 +-
 packages/demobank-ui/src/pages/LoginForm.tsx       |   8 +-
 .../demobank-ui/src/pages/OperationState/state.ts  |   4 +-
 .../demobank-ui/src/pages/OperationState/views.tsx |   5 +-
 packages/demobank-ui/src/pages/PaymentOptions.tsx  |   5 +-
 .../src/pages/PaytoWireTransferForm.tsx            | 268 ++++++++++++---------
 packages/demobank-ui/src/pages/QrCodeSection.tsx   |   1 -
 .../src/pages/UpdateAccountPassword.tsx            |   8 +-
 .../demobank-ui/src/pages/WalletWithdrawForm.tsx   | 183 +++++---------
 .../src/pages/WithdrawalConfirmationQuestion.tsx   |  14 +-
 .../demobank-ui/src/pages/WithdrawalQRCode.tsx     |  12 +-
 .../demobank-ui/src/pages/admin/AccountForm.tsx    |   8 +-
 packages/demobank-ui/src/pages/admin/Home.tsx      |   2 +
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  |  65 +----
 24 files changed, 448 insertions(+), 470 deletions(-)
 create mode 100644 packages/demobank-ui/src/components/Attention.tsx
 create mode 100644 packages/demobank-ui/src/demobank-ui-settings.js

(limited to 'packages/demobank-ui/src/pages/admin/RemoveAccount.tsx')

diff --git a/packages/demobank-ui/dev.mjs b/packages/demobank-ui/dev.mjs
index 9c09e5716..f29a05e49 100755
--- a/packages/demobank-ui/dev.mjs
+++ b/packages/demobank-ui/dev.mjs
@@ -18,7 +18,7 @@
 import { serve } from "@gnu-taler/web-util/node";
 import { initializeDev } from "@gnu-taler/web-util/build";
 
-const devEntryPoints = ["src/stories.tsx", "src/index.tsx"];
+const devEntryPoints = ["src/stories.tsx", "src/index.tsx", "src/demobank-ui-settings.js"];
 
 const build = initializeDev({
   type: "development",
diff --git a/packages/demobank-ui/src/components/Attention.tsx b/packages/demobank-ui/src/components/Attention.tsx
new file mode 100644
index 000000000..3313e5796
--- /dev/null
+++ b/packages/demobank-ui/src/components/Attention.tsx
@@ -0,0 +1,59 @@
+import { TranslatedString } from "@gnu-taler/taler-util";
+import { ComponentChildren, Fragment, VNode, h } from "preact";
+import { assertUnreachable } from "./Routing.js";
+
+interface Props { 
+  type?: "info" | "success" | "warning" | "danger", 
+  onClose?: () => void, 
+  title: TranslatedString, 
+  children?: ComponentChildren ,
+}
+export function Attention({ type = "info", title, children, onClose }: Props): VNode {
+  return <div class={`group attention-${type} mt-2`}>
+    <div class="rounded-md group-[.attention-info]:bg-blue-50 group-[.attention-warning]:bg-yellow-50 group-[.attention-danger]:bg-red-50 group-[.attention-success]:bg-green-50 p-4 shadow">
+      <div class="flex">
+        <div >
+          <svg xmlns="http://www.w3.org/2000/svg" stroke="none" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 group-[.attention-info]:text-blue-400 group-[.attention-warning]:text-yellow-400 group-[.attention-danger]:text-red-400 group-[.attention-success]:text-green-400">
+            {(() => {
+              switch (type) {
+                case "info":
+                  return <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" />
+                case "warning":
+                  return <path fill-rule="evenodd" d="M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z" />
+                case "danger":
+                  return <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z" />
+                case "success":
+                  return <path fill-rule="evenodd" d="M7.493 18.75c-.425 0-.82-.236-.975-.632A7.48 7.48 0 016 15.375c0-1.75.599-3.358 1.602-4.634.151-.192.373-.309.6-.397.473-.183.89-.514 1.212-.924a9.042 9.042 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75 2.25 2.25 0 012.25 2.25c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H14.23c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23h-.777zM2.331 10.977a11.969 11.969 0 00-.831 4.398 12 12 0 00.52 3.507c.26.85 1.084 1.368 1.973 1.368H4.9c.445 0 .72-.498.523-.898a8.963 8.963 0 01-.924-3.977c0-1.708.476-3.305 1.302-4.666.245-.403-.028-.959-.5-.959H4.25c-.832 0-1.612.453-1.918 1.227z" />
+                default:
+                  assertUnreachable(type)
+              }
+            })()}
+          </svg>
+        </div>
+        <div class="ml-3 w-full">
+          <h3 class="text-sm group-hover:text-white font-bold group-[.attention-info]:text-blue-800 group-[.attention-success]:text-green-800 group-[.attention-warning]:text-yellow-800 group-[.attention-danger]:text-red-800">
+            {title}
+          </h3>
+          <div class="mt-2 text-sm group-[.attention-info]:text-blue-700 group-[.attention-warning]:text-yellow-700 group-[.attention-danger]:text-red-700 group-[.attention-success]:text-green-700">
+            {children}
+          </div>
+        </div>
+        {onClose &&
+          <div>
+            <button type="button" class="font-semibold items-center rounded bg-transparent px-2 py-1 text-xs text-gray-900  hover:bg-gray-50"
+              onClick={(e) => {
+                e.preventDefault();
+                onClose();
+              }}
+            >
+              <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+                <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
+              </svg>
+            </button>
+          </div>
+        }
+      </div>
+    </div>
+
+  </div>
+}
diff --git a/packages/demobank-ui/src/components/ErrorLoading.tsx b/packages/demobank-ui/src/components/ErrorLoading.tsx
index f83b61234..ee62671ce 100644
--- a/packages/demobank-ui/src/components/ErrorLoading.tsx
+++ b/packages/demobank-ui/src/components/ErrorLoading.tsx
@@ -17,25 +17,13 @@
 
 import { HttpError, useTranslationContext } from "@gnu-taler/web-util/browser";
 import { h, VNode } from "preact";
+import { Attention } from "./Attention.js";
+import { TranslatedString } from "@gnu-taler/taler-util";
 
 export function ErrorLoading({ error }: { error: HttpError<SandboxBackend.SandboxError> }): VNode {
   const { i18n } = useTranslationContext()
-  return (
-    <div><div class="rounded-md bg-red-50 p-4">
-      <div class="flex">
-        <div class="flex-shrink-0">
-          <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
-          </svg>
-        </div>
-        <div class="ml-3 flex-1 md:flex md:justify-between">
-          <p class="text-sm font-medium text-red-800">{error.message}</p>
-        </div>
-      </div>
-        <div class="ml-3 flex-1 md:flex md:justify-between">
-          <p class="text-sm font-medium text-red-800">Got status "{error.info.status}" on {error.info.url}</p>
-        </div>
-    </div>
-    </div>
+  return (<Attention type="danger" title={error.message as TranslatedString}>
+    <p class="text-sm font-medium text-red-800">Got status "{error.info.status}" on {error.info.url}</p>
+  </Attention>
   );
 }
diff --git a/packages/demobank-ui/src/components/Transactions/views.tsx b/packages/demobank-ui/src/components/Transactions/views.tsx
index f8b2e3113..f92c874f3 100644
--- a/packages/demobank-ui/src/components/Transactions/views.tsx
+++ b/packages/demobank-ui/src/components/Transactions/views.tsx
@@ -19,6 +19,7 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { State } from "./index.js";
 import { format, isToday } from "date-fns";
 import { Amounts } from "@gnu-taler/taler-util";
+import { useEffect, useRef } from "preact/hooks";
 
 export function LoadingUriView({ error }: State.LoadingUriError): VNode {
   const { i18n } = useTranslationContext();
@@ -55,9 +56,9 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode
           <thead>
             <tr>
               <th scope="col" class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Date`}</th>
-              <th scope="col" class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">{i18n.str`Amount`}</th>
-              <th scope="col" class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">{i18n.str`Counterpart`}</th>
-              <th scope="col" class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">{i18n.str`Subject`}</th>
+              <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Amount`}</th>
+              <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Counterpart`}</th>
+              <th scope="col" class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Subject`}</th>
             </tr>
           </thead>
           <tbody>
@@ -69,22 +70,38 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode
                   </th>
                 </tr>
                 {txs.map(item => {
+                  const time = item.when.t_ms === "never" ? "" : format(item.when.t_ms, "HH:mm:ss")
+                  const amount = <Fragment>
+                    {item.negative ? "-" : ""}
+                    {item.amount ? (
+                      `${Amounts.stringifyValue(item.amount)} ${item.amount.currency
+                      }`
+                    ) : (
+                      <span style={{ color: "grey" }}>&lt;{i18n.str`invalid value`}&gt;</span>
+                    )}
+                  </Fragment>
                   return (<tr key={idx}>
                     <td class="relative py-2 pl-2 pr-2 text-sm ">
-                      <div class="font-medium text-gray-900">{item.when.t_ms === "never"
-                        ? ""
-                        : format(item.when.t_ms, "HH:mm:ss")}</div>
+                      <div class="font-medium text-gray-900">{time}</div>
+                      <dl class="font-normal sm:hidden">
+                        <dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt>
+                        <dd class="mt-1 truncate text-gray-700">
+                          {item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? (
+                            `${Amounts.stringifyValue(item.amount)}`
+                          ) : (
+                            <span style={{ color: "grey" }}>&lt;{i18n.str`invalid value`}&gt;</span>
+                          )}</dd>
+                        <dt class="sr-only sm:hidden"><i18n.Translate>Counterpart</i18n.Translate></dt>
+                        <dd class="mt-1 truncate text-gray-500 sm:hidden">
+                        {item.negative ? i18n.str`to` : i18n.str`from`} {item.counterpart}
+                        </dd>
+                      </dl>
                     </td>
                     <td data-negative={item.negative ? "true" : "false"}
-                      class="px-3 py-3.5 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600">
-                      {item.negative ? "-" : ""}
-                      {item.amount ? (
-                        `${Amounts.stringifyValue(item.amount)} ${item.amount.currency
-                        }`
-                      ) : (
-                        <span style={{ color: "grey" }}>&lt;{i18n.str`invalid value`}&gt;</span>
-                      )}</td>
-                    <td class="px-3 py-3.5 text-sm text-gray-500">{item.counterpart}</td>
+                      class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600">
+                      {amount}
+                    </td>
+                    <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500">{item.counterpart}</td>
                     <td class="px-3 py-3.5 text-sm text-gray-500 break-all min-w-md">{item.subject}</td>
                   </tr>)
                 })}
@@ -94,8 +111,8 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode
           </tbody>
 
         </table>
-       
-       <nav class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg" aria-label="Pagination">
+
+        <nav class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg" aria-label="Pagination">
           <div class="flex flex-1 justify-between sm:justify-end">
             <button
               class="relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
diff --git a/packages/demobank-ui/src/demobank-ui-settings.js b/packages/demobank-ui/src/demobank-ui-settings.js
new file mode 100644
index 000000000..8a0961831
--- /dev/null
+++ b/packages/demobank-ui/src/demobank-ui-settings.js
@@ -0,0 +1,21 @@
+// Values for development environment
+
+/**
+ * Global settings for the demobank UI.
+ */
+localStorage.setItem("bank-base-url", "http://bank.taler.test/");
+
+globalThis.talerDemobankSettings = {
+  backendBaseURL: "http://bank.taler.test/",
+  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/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts
index 20fd64bfa..154c43ae6 100644
--- a/packages/demobank-ui/src/hooks/access.ts
+++ b/packages/demobank-ui/src/hooks/access.ts
@@ -70,7 +70,7 @@ export function useAccessAPI(): AccessAPI {
         contentType: "json",
       },
     );
-    await mutateAll(/.*accounts\/.*\/transactions.*/);
+    await mutateAll(/.*accounts\/.*/);
     return res;
   };
   const deleteAccount = async (): Promise<HttpResponseOk<void>> => {
@@ -382,7 +382,6 @@ export function useTransactions(
     loadMore: () => {
       if (!afterData || isReachingEnd) return;
       // if (afterData.data.transactions.length < MAX_RESULT_SIZE) {
-      // console.log("load more", page)
       const l = afterData.data.transactions[afterData.data.transactions.length-1]
       setStart(String(l.row_id));
       // }
diff --git a/packages/demobank-ui/src/hooks/circuit.ts b/packages/demobank-ui/src/hooks/circuit.ts
index 82caafdf2..5dba60951 100644
--- a/packages/demobank-ui/src/hooks/circuit.ts
+++ b/packages/demobank-ui/src/hooks/circuit.ts
@@ -435,7 +435,7 @@ export function useBusinessAccounts(
     HttpResponseOk<SandboxBackend.Circuit.CircuitAccounts>,
     RequestError<SandboxBackend.SandboxError>
   >(
-    [`circuit-api/accounts`, args?.page, PAGE_SIZE, args?.account],
+    [`accounts`, args?.page, PAGE_SIZE, args?.account],
     sandboxAccountsFetcher,
     {
       refreshInterval: 0,
diff --git a/packages/demobank-ui/src/hooks/settings.ts b/packages/demobank-ui/src/hooks/settings.ts
index 5f004c6d4..ad853f9d7 100644
--- a/packages/demobank-ui/src/hooks/settings.ts
+++ b/packages/demobank-ui/src/hooks/settings.ts
@@ -33,6 +33,7 @@ interface Settings {
   showInstallWallet: boolean;
   maxWithdrawalAmount: number;
   fastWithdrawal: boolean;
+  showDebugInfo: boolean;
 }
 
 export const codecForSettings = (): Codec<Settings> =>
@@ -42,6 +43,7 @@ export const codecForSettings = (): Codec<Settings> =>
     .property("showDemoDescription", (codecForBoolean()))
     .property("showInstallWallet", (codecForBoolean()))
     .property("fastWithdrawal", (codecForBoolean()))
+    .property("showDebugInfo", (codecForBoolean()))
     .property("maxWithdrawalAmount", codecForNumber())
     .build("Settings");
 
@@ -52,6 +54,7 @@ const defaultSettings: Settings = {
   showInstallWallet: true,
   maxWithdrawalAmount: 25,
   fastWithdrawal: false,
+  showDebugInfo: false,
 };
 
 const DEMOBANK_SETTINGS_KEY = buildStorageKey(
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index 83846be90..483cb579a 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -16,10 +16,10 @@
 
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
+import { Attention } from "../../components/Attention.js";
 import { Transactions } from "../../components/Transactions/index.js";
 import { useBusinessAccountDetails } from "../../hooks/circuit.js";
 import { useSettings } from "../../hooks/settings.js";
-import { bankUiSettings } from "../../settings.js";
 import { PaymentOptions } from "../PaymentOptions.js";
 import { State } from "./index.js";
 
@@ -31,53 +31,27 @@ export function InvalidIbanView({ error }: State.InvalidIban) {
 
 const IS_PUBLIC_ACCOUNT_ENABLED = false
 
-
 function ShowDemoInfo(): VNode {
   const { i18n } = useTranslationContext();
   const [settings, updateSettings] = useSettings();
   if (!settings.showDemoDescription) return <Fragment />
-  return <div class="rounded-md bg-blue-50 p-4">
-    <div class="flex">
-      <div class="flex-shrink-0">
-        <svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-          <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
-        </svg>
-      </div>
-      <div class="ml-3">
-        <h3 class="text-sm font-bold text-blue-800">
-          <i18n.Translate>This is a demo bank!</i18n.Translate>
-        </h3>
-        <div class="mt-2 text-sm text-blue-700">
-          {IS_PUBLIC_ACCOUNT_ENABLED ? (
-            <i18n.Translate>
-              This part of the demo shows how a bank that supports Taler
-              directly would work. In addition to using your own bank
-              account, you can also see the transaction history of some{" "}
-              <a href="/public-accounts">Public Accounts</a>.
-            </i18n.Translate>
-          ) : (
-            <i18n.Translate>
-              This part of the demo shows how a bank that supports Taler
-              directly would work.
-            </i18n.Translate>
-          )}
-          <p class="mt-3 text-sm flex justify-end">
-            <button type="button" class="inline-flex font-semibold items-center rounded bg-white px-2 py-1 text-xs text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
-              onClick={(e) => {
-                e.preventDefault();
-                updateSettings("showDemoDescription", false);
-              }}
-            >
-              <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
-              </svg>
-            </button>
-          </p>
-
-        </div>
-      </div>
-    </div>
-  </div>
+  return <Attention title={i18n.str`This is a demo bank`} onClose={() => {
+    updateSettings("showDemoDescription", false);
+  }}>
+    {IS_PUBLIC_ACCOUNT_ENABLED ? (
+      <i18n.Translate>
+        This part of the demo shows how a bank that supports Taler
+        directly would work. In addition to using your own bank
+        account, you can also see the transaction history of some{" "}
+        <a href="/public-accounts">Public Accounts</a>.
+      </i18n.Translate>
+    ) : (
+      <i18n.Translate>
+        This part of the demo shows how a bank that supports Taler
+        directly would work.
+      </i18n.Translate>
+    )}
+  </Attention>
 }
 
 export function ReadyView({ account, limit, goToBusinessAccount, goToConfirmOperation }: State.Ready): VNode<{}> {
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index 15ef8a036..29334cae4 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -15,7 +15,7 @@
  */
 
 import { Amounts, Logger, PaytoUriIBAN, TranslatedString, parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
-import { notifyError, notifyException, useNotifications, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { NotificationMessage, notifyError, notifyException, useNotifications, useTranslationContext } from "@gnu-taler/web-util/browser";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
 import { StateUpdater, useEffect, useErrorBoundary, useState } from "preact/hooks";
 import { LangSelector } from "../components/LangSelector.js";
@@ -26,6 +26,7 @@ import { useSettings } from "../hooks/settings.js";
 import { CopyButton, CopyIcon } from "../components/CopyButton.js";
 import logo from "../assets/logo-2021.svg";
 import { useAccountDetails } from "../hooks/access.js";
+import { Attention } from "../components/Attention.js";
 
 const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
 const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
@@ -108,7 +109,7 @@ export function BankFrame({
                   setOpen(!open)
                 }}>
                 <span class="absolute -inset-0.5"></span>
-                <span class="sr-only">Open main menu</span>
+                <span class="sr-only">Open settings</span>
                 <svg class="block h-10 w-10" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
                   <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
                 </svg>
@@ -227,6 +228,22 @@ export function BankFrame({
                                     </button>
                                   </div>
                                 </li>
+                                <li class="mt-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">
+                                        <i18n.Translate>Show debug info</i18n.Translate>
+                                      </span>
+                                    </span>
+                                    <button type="button" data-enabled={settings.showDebugInfo} 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("showDebugInfo", !settings.showDebugInfo);
+                                      }}>
+                                      <span aria-hidden="true" data-enabled={settings.showDebugInfo} 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>
+                                </li>
                                 <li class="mt-2">
                                   <div class="flex items-center justify-between">
                                     <span class="flex flex-grow flex-col">
@@ -286,10 +303,10 @@ export function BankFrame({
       }
     </div >
 
+    <StatusBanner />
     <main class="-mt-32 flex-1">
       <div class="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8">
         <div class="rounded-lg bg-white px-5 py-6 shadow sm:px-6">
-          <StatusBanner />
           {children}
         </div>
       </div>
@@ -301,79 +318,46 @@ export function BankFrame({
   );
 }
 
+function MaybeShowDebugInfo({ info }: { info: any }): VNode {
+  const [settings] = useSettings()
+  if (settings.showDebugInfo) {
+    return <pre class="whitespace-break-spaces ">
+    {info}
+  </pre>
+  }
+  return <Fragment /> 
+}
+
 
 function StatusBanner(): VNode {
   const notifs = useNotifications()
-  return <div
-    class="fixed top-10 z-20 ml-4 mr-4"
-  > {
+  if (notifs.length === 0) return <Fragment />
+  return <div class="fixed z-20 w-full p-4"> {
       notifs.map(n => {
         switch (n.message.type) {
           case "error":
-            return <div class="rounded-md bg-red-50 p-4">
-              <div class="flex">
-                <div class="flex-shrink-0">
-                  <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
-                  </svg>
-                </div>
-                <div class="ml-3 flex-1 md:flex md:justify-between">
-                  <p class="text-sm font-medium text-red-800">{n.message.title}</p>
-                </div>
-                <div>
-                  <p class="text-sm">
-                    <button type="button" class="inline-flex font-semibold items-center rounded bg-white px-2 py-1 text-xs text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
-                      onClick={(e) => {
-                        e.preventDefault();
-                        n.remove()
-                      }}
-                    >
-                      Close
-                      <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                        <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
-                      </svg>
-                    </button>
-                  </p>
-                </div>
-              </div>
+            return <Attention type="danger" title={n.message.title} onClose={() => {
+              n.remove()
+            }}>
               {n.message.description &&
                 <div class="mt-2 text-sm text-red-700">
                   {n.message.description}
                 </div>
               }
+              <MaybeShowDebugInfo info={n.message.debug} />
+              {/* <a href="#" class="text-gray-500">
+                show debug info
+              </a>
               {n.message.debug &&
                 <div class="mt-2 text-sm text-red-700 font-mono break-all">
                   {n.message.debug}
                 </div>
-              }
-            </div>
+              } */}
+            </Attention>
           case "info":
-            return <div class="rounded-md bg-green-50 border-4 border-green-600 p-6">
-              <div class="flex">
-                <div class="flex-shrink-0">
-                  <svg class="h-8 w-8 text-green-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
-                  </svg>
-                </div>
-                <div class="ml-3 flex-1 md:flex md:justify-between">
-                  <h3 class="text-lg font-medium text-green-800">{n.message.title}</h3>
-
-                  <p class="mt-3 text-sm md:ml-6 md:mt-0">
-                    <button type="button" class="inline-flex font-semibold items-center rounded bg-white px-2 py-1 text-md text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
-                      onClick={(e) => {
-                        e.preventDefault();
-                        n.remove();
-                      }}
-                    >
-                      <svg class="h-8 w-8" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                        <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
-                      </svg>
-                    </button>
-                  </p>
-                </div>
-
-              </div>
-            </div>
+            return <Attention type="success" title={n.message.title} onClose={() => {
+              n.remove();
+            }} />
         }
       })}
   </div>
diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx
index d945d80d1..95144f086 100644
--- a/packages/demobank-ui/src/pages/HomePage.tsx
+++ b/packages/demobank-ui/src/pages/HomePage.tsx
@@ -137,8 +137,8 @@ export function handleNotOkResult(
           const errorData = result.payload;
           notify({
             type: "error",
-            title: i18n.str`Could not load due to a client error`,
-            description: errorData?.error?.description as TranslatedString,
+            title: i18n.str`Could not load due to a request error`,
+            description: i18n.str`Request to url "${result.info.url}" returned ${result.info.status}`,
             debug: JSON.stringify(result),
           });
           break;
@@ -174,7 +174,7 @@ export function handleNotOkResult(
           assertUnreachable(result);
         }
       }
-      route("/")
+      // route("/")
       return <div>error</div>;
     }
     return <div />;
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx
index 14d261622..3ea94b899 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -23,6 +23,7 @@ import { useBackendContext } from "../context/backend.js";
 import { useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
 import { bankUiSettings } from "../settings.js";
 import { undefinedIfEmpty } from "../utils.js";
+import { doAutoFocus } from "./PaytoWireTransferForm.js";
 
 
 /**
@@ -98,8 +99,8 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
               });
             } else {
               saveError({
-                title: i18n.str`Could not load due to a client error`,
-                // description: cause.payload.error.description,
+                title: i18n.str`Could not load due to a request error`,
+                description: i18n.str`Request to url "${cause.info.url}" returned ${cause.info.status}`,
                 debug: JSON.stringify(cause.payload),
               });
             }
@@ -159,8 +160,7 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
             </label>
             <div class="mt-2">
               <input
-                ref={ref}
-                autoFocus
+                ref={doAutoFocus}
                 type="text"
                 name="username"
                 id="username"
diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts b/packages/demobank-ui/src/pages/OperationState/state.ts
index 56e79f9ab..4be680377 100644
--- a/packages/demobank-ui/src/pages/OperationState/state.ts
+++ b/packages/demobank-ui/src/pages/OperationState/state.ts
@@ -118,7 +118,9 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
     try {
       setBusy({})
       await confirmWithdrawal(wid);
-      notifyInfo(i18n.str`Wire transfer completed!`)
+      if (!settings.showWithdrawalSuccess) {
+        notifyInfo(i18n.str`Wire transfer completed!`)
+      }
     } catch (error) {
       if (error instanceof RequestError) {
         notify(
diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx
index 93b3694d7..2cb7385db 100644
--- a/packages/demobank-ui/src/pages/OperationState/views.tsx
+++ b/packages/demobank-ui/src/pages/OperationState/views.tsx
@@ -267,13 +267,12 @@ export function ConfirmedView({ error, onClose }: State.Confirmed) {
         </div>
         <div class="mt-3 text-center sm:mt-5">
           <h3 class="text-base font-semibold leading-6 text-gray-900" id="modal-title">
-            <i18n.Translate>Withdrawal OK</i18n.Translate>
+            <i18n.Translate>Withdrawal confirmed</i18n.Translate>
           </h3>
           <div class="mt-2">
             <p class="text-sm text-gray-500">
               <i18n.Translate>
-                The wire transfer to the Taler exchange bank's account is completed, now the
-                exchange will send the requested amount into your GNU Taler wallet.
+                The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.
               </i18n.Translate>
             </p>
           </div>
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx
index 49419d0dc..fef272831 100644
--- a/packages/demobank-ui/src/pages/PaymentOptions.tsx
+++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx
@@ -30,7 +30,7 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ
   const { i18n } = useTranslationContext();
   const [settings] = useSettings();
 
-  const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>();
+  const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>("wire-transfer");
 
   return (
     <div class="mt-2">
@@ -82,7 +82,7 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ
                   <i18n.Translate>another bank account</i18n.Translate>
                 </span>
                 <span id="project-type-1-description-0" class="mt-1 flex items-center text-sm text-gray-500">
-                  <i18n.Translate>Make a wire transfer to an account which you know the address.</i18n.Translate>
+                  <i18n.Translate>Make a wire transfer to an account which you know the bank account number</i18n.Translate>
                 </span>
               </span>
             </span>
@@ -108,6 +108,7 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ
             limit={limit}
             onSuccess={() => {
               notifyInfo(i18n.str`Wire transfer created!`);
+              setTab(undefined)
             }}
             onCancel={() => {
               setTab(undefined)
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
index 5f5a6ce3b..785dc4264 100644
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -55,10 +55,11 @@ export function PaytoWireTransferForm({
   onCancel: (() => void) | undefined;
   limit: AmountJson;
 }): VNode {
-  const [isRawPayto, setIsRawPayto] = useState(false);
-  const [iban, setIban] = useState<string | undefined>(undefined);
-  const [subject, setSubject] = useState<string | undefined>(undefined);
-  const [amount, setAmount] = useState<string | undefined>(undefined);
+  const [isRawPayto, setIsRawPayto] = useState(true);
+  // FIXME: remove this
+  const [iban, setIban] = useState<string | undefined>("DE4745461198061");
+  const [subject, setSubject] = useState<string | undefined>("ASD");
+  const [amount, setAmount] = useState<string | undefined>("1.00001");
 
   const [rawPaytoInput, rawPaytoInputSetter] = useState<string | undefined>(
     undefined,
@@ -76,17 +77,17 @@ export function PaytoWireTransferForm({
 
   const errorsWire = undefinedIfEmpty({
     iban: !iban
-      ? i18n.str`Missing IBAN`
+      ? i18n.str`required`
       : !IBAN_REGEX.test(iban)
         ? i18n.str`IBAN should have just uppercased letters and numbers`
         : validateIBAN(iban, i18n),
-    subject: !subject ? i18n.str`Missing subject` : undefined,
+    subject: !subject ? i18n.str`required` : undefined,
     amount: !trimmedAmountStr
-      ? i18n.str`Missing amount`
+      ? i18n.str`required`
       : !parsedAmount
-        ? i18n.str`Amount is not valid`
+        ? i18n.str`not valid`
         : Amounts.isZero(parsedAmount)
-          ? i18n.str`Should be greater than 0`
+          ? i18n.str`should be greater than 0`
           : Amounts.cmp(limit, parsedAmount) === -1
             ? i18n.str`balance is not enough`
             : undefined,
@@ -101,14 +102,14 @@ export function PaytoWireTransferForm({
       ? i18n.str`required`
       : !parsed
         ? i18n.str`does not follow the pattern`
-        : !parsed.params.amount
-          ? i18n.str`use the "amount" parameter to specify the amount to be transferred`
-          : Amounts.parse(parsed.params.amount) === undefined
-            ? i18n.str`the amount is not valid`
-            : !parsed.params.message
-              ? i18n.str`use the "message" parameter to specify a reference text for the transfer`
-              : !parsed.isKnown || parsed.targetType !== "iban"
-                ? i18n.str`only "IBAN" target are supported`
+        : !parsed.isKnown || parsed.targetType !== "iban"
+          ? i18n.str`only "IBAN" target are supported`
+          : !parsed.params.amount
+            ? i18n.str`use the "amount" parameter to specify the amount to be transferred`
+            : Amounts.parse(parsed.params.amount) === undefined
+              ? i18n.str`the amount is not valid`
+              : !parsed.params.message
+                ? i18n.str`use the "message" parameter to specify a reference text for the transfer`
                 : !IBAN_REGEX.test(parsed.iban)
                   ? i18n.str`IBAN should have just uppercased letters and numbers`
                   : validateIBAN(parsed.iban, i18n),
@@ -159,6 +160,9 @@ export function PaytoWireTransferForm({
   }
 
   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">
+    {/**
+     * FIXME: Scan a qr code
+     */}
     <div class="px-4 sm:px-0">
       <h2 class="text-base font-semibold leading-7 text-gray-900">
         {title}
@@ -167,6 +171,17 @@ export function PaytoWireTransferForm({
         <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-1 sm:gap-x-4">
           <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (!isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
             <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onChange={() => {
+              if (parsed && parsed.isKnown && parsed.targetType === "iban") {
+                setIban(parsed.iban)
+                const amount = Amounts.parse(parsed.params["amount"])
+                if (amount) {
+                  setAmount(Amounts.stringifyValue(amount))
+                }
+                const subject = parsed.params["subject"]
+                if (subject) {
+                  setSubject(subject)
+                }
+              }
               setIsRawPayto(false)
             }} />
             <span class="flex flex-1">
@@ -180,12 +195,22 @@ export function PaytoWireTransferForm({
 
           <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}>
             <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onChange={() => {
+              if (iban) {
+                const payto = buildPayto("iban", iban, undefined)
+                if (parsedAmount) {
+                  payto.params["amount"] = Amounts.stringify(parsedAmount)
+                }
+                if (subject) {
+                  payto.params["message"] = subject
+                }
+                rawPaytoInputSetter(stringifyPaytoUri(payto))
+              }
               setIsRawPayto(true)
             }} />
             <span class="flex flex-1">
               <span class="flex flex-col">
                 <span class="block text-sm  font-medium text-gray-900">
-                  <i18n.Translate>using the payto:// format</i18n.Translate>
+                  <i18n.Translate>Import payto:// URI</i18n.Translate>
                 </span>
               </span>
             </span>
@@ -195,7 +220,7 @@ export function PaytoWireTransferForm({
     </div>
 
     <form
-      class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
+      class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2 w-fit mx-auto"
       autoCapitalize="none"
       autoCorrect="off"
       onSubmit={e => {
@@ -203,105 +228,106 @@ export function PaytoWireTransferForm({
       }}
     >
       <div class="px-4 py-6 sm:p-8">
-        <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
-          {!isRawPayto ?
-            <Fragment>
-
-              <div class="sm:col-span-5">
-                <label for="iban" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Account number`}</label>
-                <div class="mt-2">
-                  <input
-                    ref={ref}
-                    type="text"
-                    class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
-                    name="iban"
-                    id="iban"
-                    value={iban ?? ""}
-                    placeholder="CC0123456789"
-                    autocomplete="off"
-                    required
-                    pattern={ibanRegex}
-                    onInput={(e): void => {
-                      setIban(e.currentTarget.value);
-                    }}
-                  />
-                  <ShowInputErrorLabel
-                    message={errorsWire?.iban}
-                    isDirty={iban !== undefined}
-                  />
-                </div>
-                <p class="mt-2 text-sm text-gray-500" >the receiver of the money</p>
-              </div>
+        {!isRawPayto ?
+          <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
 
-              <div class="sm:col-span-5">
-                <label for="subject" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Transfer subject`}</label>
-                <div class="mt-2">
-                  <input
-                    type="text"
-                    class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
-                    name="subject"
-                    id="subject"
-                    autocomplete="off"
-                    placeholder="subject"
-                    value={subject ?? ""}
-                    required
-                    onInput={(e): void => {
-                      setSubject(e.currentTarget.value);
-                    }}
-                  />
-                  <ShowInputErrorLabel
-                    message={errorsWire?.subject}
-                    isDirty={subject !== undefined}
-                  />
-                </div>
-                <p class="mt-2 text-sm text-gray-500" >some text to identify the transfer</p>
+            <div class="sm:col-span-5">
+              <label for="iban" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Recipient`}</label>
+              <div class="mt-2">
+                <input
+                  ref={focus ? doAutoFocus : undefined}
+                  type="text"
+                  class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                  name="iban"
+                  id="iban"
+                  value={iban ?? ""}
+                  placeholder="CC0123456789"
+                  autocomplete="off"
+                  required
+                  pattern={ibanRegex}
+                  onInput={(e): void => {
+                    setIban(e.currentTarget.value.toUpperCase());
+                  }}
+                />
+                <ShowInputErrorLabel
+                  message={errorsWire?.iban}
+                  isDirty={iban !== undefined}
+                />
               </div>
+              <p class="mt-2 text-sm text-gray-500" >
+                <i18n.Translate>IBAN of the recipient's account</i18n.Translate>
+              </p>
+            </div>
 
-              <div class="sm:col-span-5">
-                <label for="amount" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label>
-                <Amount
-                  name="amount"
-                  currency={limit.currency}
-                  value={trimmedAmountStr}
-                  onChange={(d) => {
-                    setAmount(d)
+            <div class="sm:col-span-5">
+              <label for="subject" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Transfer subject`}</label>
+              <div class="mt-2">
+                <input
+                  type="text"
+                  class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                  name="subject"
+                  id="subject"
+                  autocomplete="off"
+                  placeholder="subject"
+                  value={subject ?? ""}
+                  required
+                  onInput={(e): void => {
+                    setSubject(e.currentTarget.value);
                   }}
                 />
                 <ShowInputErrorLabel
                   message={errorsWire?.subject}
                   isDirty={subject !== undefined}
                 />
-                <p class="mt-2 text-sm text-gray-500" >amount to transfer</p>
               </div>
+              <p class="mt-2 text-sm text-gray-500" >some text to identify the transfer</p>
+            </div>
 
-            </Fragment> :
-            <Fragment>
-              <div class="sm:col-span-6">
-                <label for="address" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`payto URI:`}</label>
-                <div class="mt-2">
-                  <input
-                    name="address"
-                    id="address"
-                    type="text"
-                    size={50}
-                    class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" ref={ref}
-                    value={rawPaytoInput ?? ""}
-                    required
-                    placeholder={i18n.str`payto://iban/[receiver-iban]?message=[subject]&amount=[${limit.currency}:X.Y]`}
-                    onInput={(e): void => {
-                      rawPaytoInputSetter(e.currentTarget.value);
-                    }}
-                  />
-                  <ShowInputErrorLabel
-                    message={errorsPayto?.rawPaytoInput}
-                    isDirty={rawPaytoInput !== undefined}
-                  />
-                </div>
-              </div>
+            <div class="sm:col-span-5">
+              <label for="amount" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label>
+              <Amount
+                name="amount"
+                left
+                currency={limit.currency}
+                value={trimmedAmountStr}
+                onChange={(d) => {
+                  setAmount(d)
+                }}
+              />
+              <ShowInputErrorLabel
+                message={errorsWire?.amount}
+                isDirty={subject !== undefined}
+              />
+              <p class="mt-2 text-sm text-gray-500" >amount to transfer</p>
+            </div>
 
-            </Fragment>
-          }
-        </div>
+          </div> :
+          <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6 w-full">
+            <div class="sm:col-span-6">
+              <label for="address" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`payto URI:`}</label>
+              <div class="mt-2">
+                <textarea
+                  ref={focus ? doAutoFocus : undefined}
+                  name="address"
+                  id="address"
+                  type="textarea"
+                  rows={3}
+                  class="block overflow-hidden w-64 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+                  value={rawPaytoInput ?? ""}
+                  required
+                  placeholder={i18n.str`payto://iban/[receiver-iban]?message=[subject]&amount=[${limit.currency}:X.Y]`}
+                  onInput={(e): void => {
+                    rawPaytoInputSetter(e.currentTarget.value);
+                  }}
+                />
+                <ShowInputErrorLabel
+                  message={errorsPayto?.rawPaytoInput}
+                  isDirty={rawPaytoInput !== undefined}
+                />
+              </div>
+            </div>
+          </div>
+        }
       </div>
       <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
         {onCancel ?
@@ -328,17 +354,37 @@ export function PaytoWireTransferForm({
   )
 
 }
+
+/**
+ * Show the element when the load ended
+ * @param element 
+ */
+export function doAutoFocus(element: HTMLElement | null) {
+  if (element) {
+    window.requestIdleCallback(() => {
+      element.focus()
+      element.scrollIntoView({
+        behavior: "smooth",
+        block: "center",
+        inline: "center"
+      })
+    })
+  }
+}
+
 export function Amount(
   {
     currency,
     name,
     value,
     error,
+    left,
     onChange,
   }: {
     error?: string;
     currency: string;
     name: string;
+    left?: boolean | undefined,
     value: string | undefined;
     onChange?: (s: string) => void;
   },
@@ -346,13 +392,16 @@ export function Amount(
 ): VNode {
   return (
     <div class="mt-2">
-      <div class="relative rounded-md shadow-sm">
-        <div class="pointer-events-none absolute inset-y-0 flex items-center pl-3">
+      <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
+        <div
+          class="pointer-events-none inset-y-0 flex items-center px-3"
+        >
           <span class="text-gray-500 sm:text-sm">{currency}</span>
         </div>
         <input
           type="number"
-          class="text-right block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+          data-left={left}
+          class="text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900  placeholder:text-gray-400  sm:text-sm sm:leading-6"
           placeholder="0.00" aria-describedby="price-currency"
           ref={ref}
           name={name}
@@ -371,3 +420,4 @@ export function Amount(
     </div>
   );
 }
+
diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx b/packages/demobank-ui/src/pages/QrCodeSection.tsx
index 0a5a386ae..6a50d4ef3 100644
--- a/packages/demobank-ui/src/pages/QrCodeSection.tsx
+++ b/packages/demobank-ui/src/pages/QrCodeSection.tsx
@@ -86,7 +86,6 @@ export function QrCodeSection({
           </h3>
           <div class="mt-4">
             <a href={talerWithdrawUri}
-              // class="text-sm font-semibold leading-6 text-gray-900 btn "
               class="inline-flex items-center  disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
             >
               <i18n.Translate>Click here to start</i18n.Translate>
diff --git a/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx
index d19c411f3..46f4fe0ef 100644
--- a/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx
+++ b/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx
@@ -5,6 +5,7 @@ import { useEffect, useRef, useState } from "preact/hooks";
 import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
 import { useAdminAccountAPI, useBusinessAccountDetails } from "../hooks/circuit.js";
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
+import { doAutoFocus } from "./PaytoWireTransferForm.js";
 
 export function UpdateAccountPassword({
   account,
@@ -27,11 +28,6 @@ export function UpdateAccountPassword({
   const [password, setPassword] = useState<string | undefined>();
   const [repeat, setRepeat] = useState<string | undefined>();
 
-  const ref = useRef<HTMLInputElement>(null);
-  useEffect(() => {
-    if (focus) ref.current?.focus();
-  }, [focus]);
-
   if (!result.ok) {
     if (result.loading || result.type === ErrorType.TIMEOUT) {
       return onLoadNotOk(result);
@@ -96,7 +92,7 @@ export function UpdateAccountPassword({
               </label>
               <div class="mt-2">
                 <input
-                  ref={ref}
+                  ref={focus ? doAutoFocus : undefined}
                   type="password"
                   class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                   name="password"
diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
index 3c5ee34fd..7357223b7 100644
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
@@ -29,14 +29,15 @@ import {
   notifyError,
   useTranslationContext,
 } from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
+import { Fragment, VNode, h } from "preact";
 import { forwardRef } from "preact/compat";
 import { useEffect, useRef, useState } from "preact/hooks";
 import { useAccessAPI } from "../hooks/access.js";
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
-import { Amount } from "./PaytoWireTransferForm.js";
+import { Amount, doAutoFocus } from "./PaytoWireTransferForm.js";
 import { useSettings } from "../hooks/settings.js";
 import { OperationState } from "./OperationState/index.js";
+import { Attention } from "../components/Attention.js";
 
 const logger = new Logger("WalletWithdrawForm");
 const RefAmount = forwardRef(Amount);
@@ -53,47 +54,13 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
 
   const { createWithdrawal } = useAccessAPI();
   const [amountStr, setAmountStr] = useState<string | undefined>(`${settings.maxWithdrawalAmount}`);
-  const ref = useRef<HTMLInputElement>(null);
-  useEffect(() => {
-    if (focus) ref.current?.focus();
-  }, [focus]);
 
   if (!!settings.currentWithdrawalOperationId) {
-    return <div>
-
-      <div class="rounded-md bg-yellow-50 ring-yellow-2 p-4">
-        <div class="flex">
-          <div class="flex-shrink-0">
-            <svg class="h-5 w-5 text-yellow-300" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-              <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
-            </svg>
-          </div>
-          <div class="ml-3">
-            <h3 class="text-sm font-bold text-yellow-800">
-              <i18n.Translate>There is an operation already</i18n.Translate>
-            </h3>
-            <div class="mt-2 text-sm text-yellow-700">
-              <p>
-                <i18n.Translate>
-                  To complete or cancel the operation click <a class="font-semibold text-yellow-700 hover:text-yellow-600" href={`#/operation/${settings.currentWithdrawalOperationId}`}>here</a>
-                </i18n.Translate>
-              </p>
-            </div>
-
-          </div>
-        </div>
-      </div >
-      <div class="flex justify-end gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8 " >
-        <button type="button" class="text-sm font-semibold leading-6 text-gray-900 bg-white p-2 rounded-sm"
-          onClick={() => {
-            updateSettings("currentWithdrawalOperationId", undefined)
-            onCancel()
-          }}
-        >
-          <i18n.Translate>Cancel</i18n.Translate>
-        </button>
-      </div>
-    </div>
+    return <Attention type="warning" title={i18n.str`There is an operation already`}>
+      <i18n.Translate>
+        To complete or cancel the operation click <a class="font-semibold text-yellow-700 hover:text-yellow-600" href={`#/operation/${settings.currentWithdrawalOperationId}`}>here</a>
+      </i18n.Translate>
+    </Attention>
   }
 
   const trimmedAmountStr = amountStr?.trim();
@@ -157,8 +124,8 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
       e.preventDefault()
     }}
   >
-    <div class="px-4 py-6 sm:p-8">
-      <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
+    <div class="px-4 py-6 ">
+      <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
         <div class="sm:col-span-5">
           <label for="withdraw-amount">{i18n.str`Amount`}</label>
           <RefAmount
@@ -169,51 +136,53 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
               setAmountStr(v);
             }}
             error={errors?.amount}
-            ref={ref}
+            ref={focus ? doAutoFocus : undefined}
           />
         </div>
-        <div class="sm:col-span-5">
-          <span class="isolate inline-flex rounded-md shadow-sm">
-            <button type="button"
-              class="relative               inline-flex px-6 py-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-              onClick={(e) => {
-                e.preventDefault();
-                setAmountStr("50.00")
-              }}
-            >
-              50.00
-            </button>
-            <button type="button"
-              class="relative -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center              bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-              onClick={(e) => {
-                e.preventDefault();
-                setAmountStr("25.00")
-              }}
-            >
+      </div>
+      <div class="mt-4">
+        <div class="sm:inline">
 
-              25.00
-            </button>
-            <button type="button"
-              class="relative -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center              bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-              onClick={(e) => {
-                e.preventDefault();
-                setAmountStr("10.00")
-              }}
-            >
-              10.00
-            </button>
-            <button type="button"
-              class="relative               inline-flex px-6 py-4 text-sm items-center rounded-r-md bg-white  text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
-              onClick={(e) => {
-                e.preventDefault();
-                setAmountStr("5.00")
-              }}
-            >
-              5.00
-            </button>
-          </span>
-        </div>
+          <button type="button"
+            class="               inline-flex px-6 py-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+            onClick={(e) => {
+              e.preventDefault();
+              setAmountStr("50.00")
+            }}
+          >
+            50.00
+          </button>
+          <button type="button"
+            class=" -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center rounded-r-md sm:rounded-none             bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+            onClick={(e) => {
+              e.preventDefault();
+              setAmountStr("25.00")
+            }}
+          >
 
+            25.00
+          </button>
+        </div>
+        <div class="mt-4 sm:inline">
+          <button type="button"
+            class=" -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center rounded-l-md sm:rounded-none             bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+            onClick={(e) => {
+              e.preventDefault();
+              setAmountStr("10.00")
+            }}
+          >
+            10.00
+          </button>
+          <button type="button"
+            class="               inline-flex px-6 py-4 text-sm items-center rounded-r-md bg-white  text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
+            onClick={(e) => {
+              e.preventDefault();
+              setAmountStr("5.00")
+            }}
+          >
+            5.00
+          </button>
+        </div>
       </div>
     </div>
     <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
@@ -255,46 +224,20 @@ export function WalletWithdrawForm({
     <div class="px-4 sm:px-0">
       <h2 class="text-base font-semibold leading-7 text-gray-900"><i18n.Translate>Prepare your wallet</i18n.Translate></h2>
       <p class="mt-1 text-sm text-gray-500">
-        <i18n.Translate>After using your wallet you will confirm or cancel the operation.</i18n.Translate>
+        <i18n.Translate>After using your wallet you will need to confirm or cancel the operation on this site.</i18n.Translate>
       </p>
     </div>
 
     <div class="col-span-2">
-      {settings.showInstallWallet && <div class="rounded-md bg-blue-50 ring-blue-2 ring-2 p-4">
-        <div class="flex">
-          <div class="flex-shrink-0">
-            <svg class="h-5 w-5 text-blue-300" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-              <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
-            </svg>
-          </div>
-          <div class="ml-3">
-            <h3 class="text-sm font-bold text-blue-800">
-              <i18n.Translate>You need a GNU Taler Wallet</i18n.Translate>
-            </h3>
-            <div class="mt-2 text-sm text-blue-700">
-              <p>
-                <i18n.Translate>
-                  If you dont have one yet you can follow the instruction <a target="_blank" rel="noreferrer noopener" class="font-semibold text-blue-700 hover:text-blue-600" href="https://taler.net/en/wallet.html">here</a>
-                </i18n.Translate>
-              </p>
-              <p class="mt-3 text-sm flex justify-end">
-                <button type="button" class="inline-flex font-semibold items-center rounded bg-white px-2 py-1 text-xs text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
-                  onClick={(e) => {
-                    e.preventDefault();
-                    updateSettings("showInstallWallet", false);
-                  }}
-                >
-                  I know
-                  <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                    <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
-                  </svg>
-                </button>
-              </p>
-
-            </div>
-          </div>
-        </div>
-      </div>}
+      {settings.showInstallWallet &&
+        <Attention title={i18n.str`You need a GNU Taler Wallet`} onClose={() => {
+          updateSettings("showInstallWallet", false);
+        }}>
+          <i18n.Translate>
+            If you don't have one yet you can follow the instruction <a target="_blank" rel="noreferrer noopener" class="font-semibold text-blue-700 hover:text-blue-600" href="https://taler.net/en/wallet.html">here</a>
+          </i18n.Translate>
+        </Attention>
+      }
 
       {!settings.fastWithdrawal ?
         <OldWithdrawalForm
diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
index d160a88b3..208d4b859 100644
--- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
@@ -37,6 +37,7 @@ import { useMemo, useState } from "preact/hooks";
 import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
 import { useAccessAnonAPI } from "../hooks/access.js";
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
+import { useSettings } from "../hooks/settings.js";
 
 const logger = new Logger("WithdrawalConfirmationQuestion");
 
@@ -59,6 +60,7 @@ export function WithdrawalConfirmationQuestion({
   withdrawUri,
 }: Props): VNode {
   const { i18n } = useTranslationContext();
+  const [settings, updateSettings] = useSettings()
 
   const captchaNumbers = useMemo(() => {
     return {
@@ -87,7 +89,9 @@ export function WithdrawalConfirmationQuestion({
       await confirmWithdrawal(
         withdrawUri.withdrawalOperationId,
       );
-      notifyInfo(i18n.str`Wire transfer completed!`)
+      if (!settings.showWithdrawalSuccess) {
+        notifyInfo(i18n.str`Wire transfer completed!`)
+      }
     } catch (error) {
       if (error instanceof RequestError) {
         notify(
@@ -203,7 +207,7 @@ export function WithdrawalConfirmationQuestion({
 
             <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">
-                <h2 class="text-base font-semibold text-gray-900"><i18n.Translate>Answer the next question to authorize the wire transfer</i18n.Translate></h2>
+                <h2 class="text-base font-semibold text-gray-900"><i18n.Translate>Answer the next question to authorize the wire transfer.</i18n.Translate></h2>
               </div>
               <form
                 class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
@@ -311,14 +315,10 @@ export function WithdrawalConfirmationQuestion({
 
                     }
                   })()}
-                  <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
-                    <dt class="text-sm font-medium leading-6 text-gray-900">Withdrawal identification</dt>
-                    <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0 break-words">{details.reserve}</dd>
-                  </div>
                   <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
                     <dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt>
                     <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
-                      {Amounts.stringifyValue(details.amount)}
+                      {Amounts.currencyOf(details.amount)} {Amounts.stringifyValue(details.amount)}
                     </dd>
                   </div>
                 </dl>
diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
index 8f4e175f6..c8efc033b 100644
--- a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
@@ -94,20 +94,12 @@ export function WithdrawalQRCode({
         </div>
         <div class="mt-3 text-center sm:mt-5">
           <h3 class="text-base font-semibold leading-6 text-gray-900" id="modal-title">
-            <i18n.Translate>Withdrawal OK</i18n.Translate>
+            <i18n.Translate>Withdrawal confirmed</i18n.Translate>
           </h3>
           <div class="mt-2">
             <p class="text-sm text-gray-500">
               <i18n.Translate>
-                The wire transfer to the Taler exchange bank's account is completed, now the
-                exchange will send the requested amount into your GNU Taler wallet.
-              </i18n.Translate>
-            </p>
-          </div>
-          <div class="mt-2">
-            <p >
-              <i18n.Translate>
-                You can close this page now or continue to the account page.
+                The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.
               </i18n.Translate>
             </p>
           </div>
diff --git a/packages/demobank-ui/src/pages/admin/AccountForm.tsx b/packages/demobank-ui/src/pages/admin/AccountForm.tsx
index 02df824a2..ed8bf610d 100644
--- a/packages/demobank-ui/src/pages/admin/AccountForm.tsx
+++ b/packages/demobank-ui/src/pages/admin/AccountForm.tsx
@@ -4,6 +4,7 @@ import { PartialButDefined, RecursivePartial, WithIntermediate, undefinedIfEmpty
 import { useEffect, useRef, useState } from "preact/hooks";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { buildPayto, parsePaytoUri } from "@gnu-taler/taler-util";
+import { doAutoFocus } from "../PaytoWireTransferForm.js";
 
 const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/;
 const EMAIL_REGEX =
@@ -37,10 +38,6 @@ export function AccountForm({
     RecursivePartial<typeof initial> | undefined
   >(undefined);
   const { i18n } = useTranslationContext();
-  const ref = useRef<HTMLInputElement>(null);
-  useEffect(() => {
-    if (focus) ref.current?.focus();
-  }, [focus]);
 
   function updateForm(newForm: typeof initial): void {
 
@@ -97,7 +94,6 @@ export function AccountForm({
       <div class="px-4 py-6 sm:p-8">
         <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
 
-
           <div class="sm:col-span-5">
             <label
               class="block text-sm font-medium leading-6 text-gray-900"
@@ -108,7 +104,7 @@ export function AccountForm({
             </label>
             <div class="mt-2">
               <input
-                ref={ref}
+                ref={focus ? doAutoFocus : undefined}
                 type="text"
                 class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                 name="username"
diff --git a/packages/demobank-ui/src/pages/admin/Home.tsx b/packages/demobank-ui/src/pages/admin/Home.tsx
index ffa559097..d50ff14b4 100644
--- a/packages/demobank-ui/src/pages/admin/Home.tsx
+++ b/packages/demobank-ui/src/pages/admin/Home.tsx
@@ -10,6 +10,7 @@ import { AdminAccount } from "./Account.js";
 import { AccountList } from "./AccountList.js";
 import { CreateNewAccount } from "./CreateNewAccount.js";
 import { RemoveAccount } from "./RemoveAccount.js";
+import { Transactions } from "../../components/Transactions/index.js";
 
 /**
  * Query account information and show QR code if there is pending withdrawal
@@ -141,6 +142,7 @@ export function AdminHome({ onRegister }: Props): VNode {
 
       <AdminAccount onRegister={onRegister} />
 
+      <Transactions account="admin"/>
     </Fragment>
   );
 }
\ No newline at end of file
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index 1e5370afc..b323b0d01 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -6,6 +6,8 @@ import { Amounts, HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util
 import { buildRequestErrorMessage, undefinedIfEmpty } from "../../utils.js";
 import { useEffect, useRef, useState } from "preact/hooks";
 import { ShowInputErrorLabel } from "../../components/ShowInputErrorLabel.js";
+import { Attention } from "../../components/Attention.js";
+import { doAutoFocus } from "../PaytoWireTransferForm.js";
 
 export function RemoveAccount({
   account,
@@ -36,47 +38,15 @@ export function RemoveAccount({
     }
     return onLoadNotOk(result);
   }
-  const ref = useRef<HTMLInputElement>(null);
-  useEffect(() => {
-    if (focus) ref.current?.focus();
-  }, [focus]);
-
   const balance = Amounts.parse(result.data.balance.amount);
   if (!balance) {
     return <div>there was an error reading the balance</div>;
   }
   const isBalanceEmpty = Amounts.isZero(balance);
   if (!isBalanceEmpty) {
-    return <div>
-      <div class="rounded-md bg-yellow-50 p-4">
-        <div class="flex">
-          <div class="flex-shrink-0">
-            <svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-              <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
-            </svg>
-          </div>
-          <div class="ml-3">
-            <h3 class="text-sm font-medium text-yellow-800">
-              <i18n.Translate>Can't delete the account</i18n.Translate>
-            </h3>
-            <div class="mt-2 text-sm text-yellow-700">
-              <p>
-                <i18n.Translate>The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.</i18n.Translate>
-              </p>
-            </div>
-          </div>
-
-        </div>
-      </div>
-      <div class="mt-2 flex justify-end">
-        <button type="button" class="rounded-md ring-1 ring-gray-400 bg-white px-3 py-2 text-sm font-semibold shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
-          onClick={() => {
-            onCancel()
-          }}>
-          <i18n.Translate>Go back</i18n.Translate>
-        </button>
-      </div>
-    </div>
+    return <Attention type="warning" title={i18n.str`Can't delete the account`} onClose={onCancel}>
+      <i18n.Translate>The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.</i18n.Translate>
+    </Attention>
   }
 
   async function doRemove() {
@@ -117,26 +87,9 @@ export function RemoveAccount({
 
   return (
     <div>
-      <div class="rounded-md bg-yellow-50 p-4">
-        <div class="flex">
-          <div class="flex-shrink-0">
-            <svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-              <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
-            </svg>
-          </div>
-          <div class="ml-3">
-            <h3 class="text-sm font-bold text-yellow-800">
-              <i18n.Translate>You are going to remove the account</i18n.Translate>
-            </h3>
-            <div class="mt-2 text-sm text-yellow-700">
-              <p>
-                <i18n.Translate>This step can't be undone.</i18n.Translate>
-              </p>
-            </div>
-          </div>
-
-        </div>
-      </div>
+      <Attention type="warning" title={i18n.str`You are going to remove the account`}>
+        <i18n.Translate>This step can't be undone.</i18n.Translate>
+      </Attention>
 
       <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">
@@ -164,7 +117,7 @@ export function RemoveAccount({
                 </label>
                 <div class="mt-2">
                   <input
-                    ref={ref}
+                    ref={focus ? doAutoFocus : undefined}
                     type="text"
                     class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                     name="password"
-- 
cgit v1.2.3

