gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (779ddae8b -> 1708d49a2)


From: gnunet
Subject: [taler-wallet-core] branch master updated (779ddae8b -> 1708d49a2)
Date: Fri, 29 Sep 2023 21:02:42 +0200

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

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

    from 779ddae8b iban country code should be always uppercased
     new c10f3f3ad notifications exposed
     new 1708d49a2 more ui

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


Summary of changes:
 packages/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 +----
 packages/web-util/src/hooks/index.ts               |  10 +-
 packages/web-util/src/hooks/useNotifications.ts    |   2 +-
 26 files changed, 450 insertions(+), 480 deletions(-)
 create mode 100644 packages/demobank-ui/src/components/Attention.tsx
 create mode 100644 packages/demobank-ui/src/demobank-ui-settings.js

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. [...]
+                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"
diff --git a/packages/web-util/src/hooks/index.ts 
b/packages/web-util/src/hooks/index.ts
index cc3267dbd..f6c74ff22 100644
--- a/packages/web-util/src/hooks/index.ts
+++ b/packages/web-util/src/hooks/index.ts
@@ -1,15 +1,7 @@
 export { useLang } from "./useLang.js";
 export { useLocalStorage, buildStorageKey } from "./useLocalStorage.js";
 export { useMemoryStorage } from "./useMemoryStorage.js";
-export {
-  useNotifications,
-  notifyError,
-  notifyException,
-  notifyInfo,
-  notify,
-  ErrorNotification,
-  InfoNotification
-} from "./useNotifications.js";
+export * from "./useNotifications.js";
 export {
   useAsyncAsHook,
   HookError,
diff --git a/packages/web-util/src/hooks/useNotifications.ts 
b/packages/web-util/src/hooks/useNotifications.ts
index 792095b06..e9e8a240b 100644
--- a/packages/web-util/src/hooks/useNotifications.ts
+++ b/packages/web-util/src/hooks/useNotifications.ts
@@ -54,7 +54,7 @@ export function notifyInfo(title: TranslatedString) {
   });
 }
 
-type Notification = {
+export type Notification = {
   message: NotificationMessage;
   remove: () => void;
 };

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



reply via email to

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