gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (7c33040ae -> 5ed4d5d54)


From: gnunet
Subject: [taler-wallet-core] branch master updated (7c33040ae -> 5ed4d5d54)
Date: Sun, 30 Oct 2022 00:55:17 +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 7c33040ae symmetric margins
     new fe6e9be70 manage account instead of add account
     new 5ed4d5d54 fix typo

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:
 .../src/svg/check_24px.svg                         |   1 +
 .../src/svg/warning_24px.svg                       |   1 +
 .../src/wallet/AddAccount/stories.tsx              |  29 --
 .../src/wallet/AddAccount/views.tsx                | 249 ----------
 .../src/wallet/DepositPage/index.ts                |   8 +-
 .../src/wallet/DepositPage/state.ts                |  27 +-
 .../src/wallet/DepositPage/stories.tsx             |  21 +
 .../src/wallet/DepositPage/test.ts                 |  10 +-
 .../src/wallet/DepositPage/views.tsx               |  98 ++--
 .../wallet/{AddAccount => ManageAccount}/index.ts  |  11 +-
 .../wallet/{AddAccount => ManageAccount}/state.ts  |  32 +-
 .../src/wallet/ManageAccount/stories.tsx           | 208 ++++++++
 .../wallet/{AddAccount => ManageAccount}/test.ts   |   0
 .../src/wallet/ManageAccount/views.tsx             | 534 +++++++++++++++++++++
 .../src/wallet/index.stories.tsx                   |   2 +
 15 files changed, 868 insertions(+), 363 deletions(-)
 create mode 100644 packages/taler-wallet-webextension/src/svg/check_24px.svg
 create mode 100644 packages/taler-wallet-webextension/src/svg/warning_24px.svg
 delete mode 100644 
packages/taler-wallet-webextension/src/wallet/AddAccount/stories.tsx
 delete mode 100644 
packages/taler-wallet-webextension/src/wallet/AddAccount/views.tsx
 rename packages/taler-wallet-webextension/src/wallet/{AddAccount => 
ManageAccount}/index.ts (86%)
 rename packages/taler-wallet-webextension/src/wallet/{AddAccount => 
ManageAccount}/state.ts (76%)
 create mode 100644 
packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx
 rename packages/taler-wallet-webextension/src/wallet/{AddAccount => 
ManageAccount}/test.ts (100%)
 create mode 100644 
packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx

diff --git a/packages/taler-wallet-webextension/src/svg/check_24px.svg 
b/packages/taler-wallet-webextension/src/svg/check_24px.svg
new file mode 100644
index 000000000..522695ef3
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/svg/check_24px.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; height="24" viewBox="0 0 24 24" 
width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 
1.41L9 19 21 7l-1.41-1.41z"/></svg>
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/svg/warning_24px.svg 
b/packages/taler-wallet-webextension/src/svg/warning_24px.svg
new file mode 100644
index 000000000..d27c4c6ec
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/svg/warning_24px.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; height="24" viewBox="0 0 24 24" 
width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M1 21h22L12 2 1 
21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>
\ No newline at end of file
diff --git 
a/packages/taler-wallet-webextension/src/wallet/AddAccount/stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/AddAccount/stories.tsx
deleted file mode 100644
index 696e424c4..000000000
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/stories.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { createExample } from "../../test-utils.js";
-import { ReadyView } from "./views.js";
-
-export default {
-  title: "example",
-};
-
-export const Ready = createExample(ReadyView, {});
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/AddAccount/views.tsx
deleted file mode 100644
index d6ab7e967..000000000
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/views.tsx
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-import { parsePaytoUri } from "@gnu-taler/taler-util";
-import { Fragment, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { ErrorMessage } from "../../components/ErrorMessage.js";
-import { LoadingError } from "../../components/LoadingError.js";
-import { SelectList } from "../../components/SelectList.js";
-import { Input, LightText, SubTitle } from "../../components/styled/index.js";
-import { useTranslationContext } from "../../context/translation.js";
-import { Button } from "../../mui/Button.js";
-import { TextFieldHandler } from "../../mui/handlers.js";
-import { TextField } from "../../mui/TextField.js";
-import { State } from "./index.js";
-
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
-export function ReadyView({
-  currency,
-  error,
-  accountType,
-  alias,
-  onAccountAdded,
-  onCancel,
-  uri,
-}: State.Ready): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <Fragment>
-      <section>
-        <SubTitle>
-          <i18n.Translate>Add bank account for {currency}</i18n.Translate>
-        </SubTitle>
-        <LightText>
-          <i18n.Translate>
-            Enter the URL of an exchange you trust.
-          </i18n.Translate>
-        </LightText>
-
-        {error && (
-          <ErrorMessage
-            title={<i18n.Translate>Unable add this account</i18n.Translate>}
-            description={error}
-          />
-        )}
-        <p>
-          <Input>
-            <SelectList
-              label={<i18n.Translate>Select account type</i18n.Translate>}
-              list={accountType.list}
-              name="accountType"
-              value={accountType.value}
-              onChange={accountType.onChange}
-            />
-          </Input>
-        </p>
-        {accountType.value === "" ? undefined : (
-          <Fragment>
-            <p>
-              <CustomFieldByAccountType type={accountType.value} field={uri} />
-            </p>
-            <p>
-              <TextField
-                label="Account alias"
-                variant="standard"
-                required
-                fullWidth
-                disabled={accountType.value === ""}
-                value={alias.value}
-                onChange={alias.onInput}
-              />
-            </p>
-          </Fragment>
-        )}
-      </section>
-      <footer>
-        <Button
-          variant="contained"
-          color="secondary"
-          onClick={onCancel.onClick}
-        >
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Button>
-        <Button
-          variant="contained"
-          onClick={onAccountAdded.onClick}
-          disabled={!onAccountAdded.onClick}
-        >
-          <i18n.Translate>Add</i18n.Translate>
-        </Button>
-      </footer>
-    </Fragment>
-  );
-}
-
-function BitcoinAddressAccount({ field }: { field: TextFieldHandler }): VNode {
-  const { i18n } = useTranslationContext();
-  const [value, setValue] = useState<string | undefined>(undefined);
-  const errors = undefinedIfEmpty({
-    value: !value ? i18n.str`Can't be empty` : undefined,
-  });
-  return (
-    <Fragment>
-      <TextField
-        label="Bitcoin address"
-        variant="standard"
-        fullWidth
-        value={value}
-        error={value !== undefined && !!errors?.value}
-        onChange={(v) => {
-          setValue(v);
-          if (!errors) {
-            field.onInput(`payto://bitcoin/${value}`);
-          }
-        }}
-      />
-      {value !== undefined && errors?.value && (
-        <ErrorMessage title={<span>{errors?.value}</span>} />
-      )}
-    </Fragment>
-  );
-}
-
-function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
-  return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
-    ? obj
-    : undefined;
-}
-
-function TalerBankAddressAccount({
-  field,
-}: {
-  field: TextFieldHandler;
-}): VNode {
-  const { i18n } = useTranslationContext();
-  const [host, setHost] = useState<string | undefined>(undefined);
-  const [account, setAccount] = useState<string | undefined>(undefined);
-  const errors = undefinedIfEmpty({
-    host: !host ? i18n.str`Can't be empty` : undefined,
-    account: !account ? i18n.str`Can't be empty` : undefined,
-  });
-  return (
-    <Fragment>
-      <TextField
-        label="Bank host"
-        variant="standard"
-        fullWidth
-        value={host}
-        error={host !== undefined && !!errors?.host}
-        onChange={(v) => {
-          setHost(v);
-          if (!errors) {
-            field.onInput(`payto://x-taler-bank/${host}/${account}`);
-          }
-        }}
-      />{" "}
-      {host !== undefined && errors?.host && (
-        <ErrorMessage title={<span>{errors?.host}</span>} />
-      )}
-      <TextField
-        label="Bank account"
-        variant="standard"
-        fullWidth
-        value={account}
-        error={account !== undefined && !!errors?.account}
-        onChange={(v) => {
-          setAccount(v || "");
-          if (!errors) {
-            field.onInput(`payto://x-taler-bank/${host}/${account}`);
-          }
-        }}
-      />{" "}
-      {account !== undefined && errors?.account && (
-        <ErrorMessage title={<span>{errors?.account}</span>} />
-      )}
-    </Fragment>
-  );
-}
-
-function IbanAddressAccount({ field }: { field: TextFieldHandler }): VNode {
-  const { i18n } = useTranslationContext();
-  const [value, setValue] = useState<string | undefined>(undefined);
-  const errors = undefinedIfEmpty({
-    value: !value ? i18n.str`Can't be empty` : undefined,
-  });
-  return (
-    <Fragment>
-      <TextField
-        label="IBAN number"
-        variant="standard"
-        fullWidth
-        value={value}
-        error={value !== undefined && !!errors?.value}
-        onChange={(v) => {
-          setValue(v);
-          if (!errors) {
-            field.onInput(`payto://iba/${value}`);
-          }
-        }}
-      />
-      {value !== undefined && errors?.value && (
-        <ErrorMessage title={<span>{errors?.value}</span>} />
-      )}
-    </Fragment>
-  );
-}
-
-function CustomFieldByAccountType({
-  type,
-  field,
-}: {
-  type: string;
-  field: TextFieldHandler;
-}): VNode {
-  if (type === "bitcoin") {
-    return <BitcoinAddressAccount field={field} />;
-  }
-  if (type === "x-taler-bank") {
-    return <TalerBankAddressAccount field={field} />;
-  }
-  if (type === "iban") {
-    return <IbanAddressAccount field={field} />;
-  }
-  return <Fragment />;
-}
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
index 77661fe15..85896da26 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
@@ -24,7 +24,7 @@ import {
 } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { wxApi } from "../../wxApi.js";
-import { AddAccountPage } from "../AddAccount/index.js";
+import { ManageAccountPage } from "../ManageAccount/index.js";
 import { useComponentState } from "./state.js";
 import {
   AmountOrCurrencyErrorView,
@@ -62,7 +62,7 @@ export namespace State {
   }
 
   export interface AddingAccount {
-    status: "adding-account";
+    status: "manage-account";
     error: undefined;
     currency: string;
     onAccountAdded: (p: string) => void;
@@ -94,7 +94,7 @@ export namespace State {
     error: undefined;
     currency: string;
 
-    selectedAccount: PaytoUri | undefined;
+    currentAccount: PaytoUri;
     totalFee: AmountJson;
     totalToDeposit: AmountJson;
 
@@ -112,7 +112,7 @@ const viewMapping: StateViewMap<State> = {
   "amount-or-currency-error": AmountOrCurrencyErrorView,
   "no-enough-balance": NoEnoughBalanceView,
   "no-accounts": NoAccountToDepositView,
-  "adding-account": AddAccountPage,
+  "manage-account": ManageAccountPage,
   ready: ReadyView,
 };
 
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
index b3a377040..fe692e80d 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
@@ -50,9 +50,7 @@ export function useComponentState(
   // const [accountIdx, setAccountIdx] = useState<number>(0);
   const [amount, setAmount] = useState(initialValue);
 
-  const [selectedAccount, setSelectedAccount] = useState<
-    PaytoUri | undefined
-  >();
+  const [selectedAccount, setSelectedAccount] = useState<PaytoUri>();
 
   const [fee, setFee] = useState<DepositGroupFees | undefined>(undefined);
   const [addingAccount, setAddingAccount] = useState(false);
@@ -82,7 +80,7 @@ export function useComponentState(
 
   if (addingAccount) {
     return {
-      status: "adding-account",
+      status: "manage-account",
       error: undefined,
       currency,
       onAccountAdded: (p: string) => {
@@ -92,6 +90,7 @@ export function useComponentState(
       },
       onCancel: () => {
         setAddingAccount(false);
+        hook.retry();
       },
     };
   }
@@ -122,13 +121,12 @@ export function useComponentState(
       },
     };
   }
+  const firstAccount = accounts[0].uri
+  const currentAccount = !selectedAccount ? firstAccount : selectedAccount;
 
   const accountMap = createLabelsForBankAccount(accounts);
-  accountMap[""] = "Select one account...";
 
   async function updateAccountFromList(accountStr: string): Promise<void> {
-    // const newSelected = !accountMap[accountStr] ? undefined : 
accountMap[accountStr];
-    // if (!newSelected) return;
     const uri = !accountStr ? undefined : parsePaytoUri(accountStr);
     if (uri && parsedAmount) {
       try {
@@ -136,7 +134,6 @@ export function useComponentState(
         setSelectedAccount(uri);
         setFee(result);
       } catch (e) {
-        console.error(e)
         setSelectedAccount(uri);
         setFee(undefined);
       }
@@ -145,13 +142,12 @@ export function useComponentState(
 
   async function updateAmount(numStr: string): Promise<void> {
     const parsed = Amounts.parse(`${currency}:${numStr}`);
-    if (parsed && selectedAccount) {
+    if (parsed) {
       try {
-        const result = await getFeeForAmount(selectedAccount, parsed, api);
+        const result = await getFeeForAmount(currentAccount, parsed, api);
         setAmount(numStr);
         setFee(result);
       } catch (e) {
-        console.error(e)
         setAmount(numStr);
         setFee(undefined);
       }
@@ -179,15 +175,14 @@ export function useComponentState(
 
   const unableToDeposit =
     !parsedAmount || //no amount specified
-    selectedAccount === undefined || //no account selected
     Amounts.isZero(totalToDeposit) || //deposit may be zero because of fee
     fee === undefined || //no fee calculated yet
     amountError !== undefined; //amount field may be invalid
 
   async function doSend(): Promise<void> {
-    if (!selectedAccount || !parsedAmount || !currency) return;
+    if (!parsedAmount || !currency) return;
 
-    const depositPaytoUri = 
`payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`;
+    const depositPaytoUri = 
`payto://${currentAccount.targetType}/${currentAccount.targetPath}`;
     const amount = Amounts.stringify(parsedAmount);
     await api.wallet.call(WalletApiOperation.CreateDepositGroup, {
       amount, depositPaytoUri
@@ -211,10 +206,10 @@ export function useComponentState(
     },
     account: {
       list: accountMap,
-      value: !selectedAccount ? "" : stringifyPaytoUri(selectedAccount),
+      value: stringifyPaytoUri(currentAccount),
       onChange: updateAccountFromList,
     },
-    selectedAccount,
+    currentAccount,
     cancelHandler: {
       onClick: async () => {
         onCancel(currency);
diff --git 
a/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx
index ed5945c06..64b2c91a7 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx
@@ -55,6 +55,13 @@ export const WithNoAccountForIBAN = createExample(ReadyView, 
{
       null;
     },
   },
+  currentAccount: {
+    isKnown: true,
+    targetType: "iban",
+    iban: "ABCD1234",
+    params: {},
+    targetPath: "/ABCD1234",
+  },
   currency: "USD",
   amount: {
     onInput: async () => {
@@ -83,6 +90,13 @@ export const WithIBANAccountTypeSelected = 
createExample(ReadyView, {
       null;
     },
   },
+  currentAccount: {
+    isKnown: true,
+    targetType: "iban",
+    iban: "ABCD1234",
+    params: {},
+    targetPath: "/ABCD1234",
+  },
   currency: "USD",
   amount: {
     onInput: async () => {
@@ -111,6 +125,13 @@ export const NewBitcoinAccountTypeSelected = 
createExample(ReadyView, {
       null;
     },
   },
+  currentAccount: {
+    isKnown: true,
+    targetType: "iban",
+    iban: "ABCD1234",
+    params: {},
+    targetPath: "/ABCD1234",
+  },
   onAddAccount: {},
   currency: "USD",
   amount: {
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
index 62097c3e4..4a648312e 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
@@ -172,7 +172,7 @@ describe("DepositPage states", () => {
       if (r.status !== "ready") expect.fail();
       expect(r.cancelHandler.onClick).not.undefined;
       expect(r.currency).eq(currency);
-      expect(r.account.value).eq("");
+      expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
       expect(r.amount.value).eq("0");
       expect(r.depositHandler.onClick).undefined;
     }
@@ -195,7 +195,7 @@ describe("DepositPage states", () => {
       }],
     })
     handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, 
undefined, {
-      accounts: [ibanPayto]
+      accounts: [talerBankPayto, ibanPayto]
     });
     handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, 
undefined, withoutFee())
     handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, 
undefined, withoutFee())
@@ -221,7 +221,7 @@ describe("DepositPage states", () => {
       if (r.status !== "ready") expect.fail();
       expect(r.cancelHandler.onClick).not.undefined;
       expect(r.currency).eq(currency);
-      expect(r.account.value).eq("");
+      expect(r.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
       expect(r.amount.value).eq("0");
       expect(r.depositHandler.onClick).undefined;
       expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
@@ -328,7 +328,7 @@ describe("DepositPage states", () => {
       }],
     })
     handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, 
undefined, {
-      accounts: [ibanPayto]
+      accounts: [talerBankPayto, ibanPayto]
     });
     handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, 
undefined, withSomeFee())
     handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, 
undefined, withSomeFee())
@@ -353,7 +353,7 @@ describe("DepositPage states", () => {
       if (r.status !== "ready") expect.fail();
       expect(r.cancelHandler.onClick).not.undefined;
       expect(r.currency).eq(currency);
-      expect(r.account.value).eq("");
+      expect(r.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
       expect(r.amount.value).eq("0");
       expect(r.depositHandler.onClick).undefined;
       expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
diff --git 
a/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx
index ddb23c9bb..e864c8413 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx
@@ -160,61 +160,55 @@ export function ReadyView(state: State.Ready): VNode {
             variant="text"
             style={{ marginLeft: "auto" }}
           >
-            <i18n.Translate>Add another account</i18n.Translate>
+            <i18n.Translate>Manage accounts</i18n.Translate>
           </Button>
         </div>
 
-        {state.selectedAccount && (
-          <Fragment>
-            <p>
-              <AccountDetails account={state.selectedAccount} />
-            </p>
-            <InputWithLabel invalid={!!state.amount.error}>
-              <label>
-                <i18n.Translate>Amount</i18n.Translate>
-              </label>
-              <div>
-                <span>{state.currency}</span>
-                <input
-                  type="number"
-                  value={state.amount.value}
-                  onInput={(e) => state.amount.onInput(e.currentTarget.value)}
-                />
-              </div>
-              {state.amount.error && (
-                <ErrorText>{state.amount.error}</ErrorText>
-              )}
-            </InputWithLabel>
-
-            <InputWithLabel>
-              <label>
-                <i18n.Translate>Deposit fee</i18n.Translate>
-              </label>
-              <div>
-                <span>{state.currency}</span>
-                <input
-                  type="number"
-                  disabled
-                  value={Amounts.stringifyValue(state.totalFee)}
-                />
-              </div>
-            </InputWithLabel>
-
-            <InputWithLabel>
-              <label>
-                <i18n.Translate>Total deposit</i18n.Translate>
-              </label>
-              <div>
-                <span>{state.currency}</span>
-                <input
-                  type="number"
-                  disabled
-                  value={Amounts.stringifyValue(state.totalToDeposit)}
-                />
-              </div>
-            </InputWithLabel>
-          </Fragment>
-        )}
+        <p>
+          <AccountDetails account={state.currentAccount} />
+        </p>
+        <InputWithLabel invalid={!!state.amount.error}>
+          <label>
+            <i18n.Translate>Amount</i18n.Translate>
+          </label>
+          <div>
+            <span>{state.currency}</span>
+            <input
+              type="number"
+              value={state.amount.value}
+              onInput={(e) => state.amount.onInput(e.currentTarget.value)}
+            />
+          </div>
+          {state.amount.error && <ErrorText>{state.amount.error}</ErrorText>}
+        </InputWithLabel>
+
+        <InputWithLabel>
+          <label>
+            <i18n.Translate>Deposit fee</i18n.Translate>
+          </label>
+          <div>
+            <span>{state.currency}</span>
+            <input
+              type="number"
+              disabled
+              value={Amounts.stringifyValue(state.totalFee)}
+            />
+          </div>
+        </InputWithLabel>
+
+        <InputWithLabel>
+          <label>
+            <i18n.Translate>Total deposit</i18n.Translate>
+          </label>
+          <div>
+            <span>{state.currency}</span>
+            <input
+              type="number"
+              disabled
+              value={Amounts.stringifyValue(state.totalToDeposit)}
+            />
+          </div>
+        </InputWithLabel>
       </section>
       <footer>
         <Button
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts
similarity index 86%
rename from packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
rename to packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts
index 09609a8a1..cd591be74 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts
@@ -14,6 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { KnownBankAccountsInfo } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
 import {
@@ -57,17 +58,23 @@ export namespace State {
     alias: TextFieldHandler;
     onAccountAdded: ButtonHandler;
     onCancel: ButtonHandler;
+    accountByType: AccountByType,
+    deleteAccount: (a: KnownBankAccountsInfo) => Promise<void>,
   }
 }
 
+export type AccountByType = {
+  [key: string]: KnownBankAccountsInfo[]
+};
+
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
   "loading-error": LoadingUriView,
   ready: ReadyView,
 };
 
-export const AddAccountPage = compose(
-  "AddAccount",
+export const ManageAccountPage = compose(
+  "ManageAccountPage",
   (p: Props) => useComponentState(p, wxApi),
   viewMapping,
 );
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
similarity index 76%
rename from packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
rename to packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
index 6c113d732..0dc34c326 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
@@ -14,12 +14,12 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
+import { KnownBankAccountsInfo, parsePaytoUri, stringifyPaytoUri } from 
"@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { wxApi } from "../../wxApi.js";
-import { Props, State } from "./index.js";
+import { AccountByType, Props, State } from "./index.js";
 
 export function useComponentState(
   { currency, onAccountAdded, onCancel }: Props,
@@ -45,10 +45,10 @@ export function useComponentState(
   }
 
   const accountType: Record<string, string> = {
-    "": "Choose one account",
+    "": "Choose one account type",
     iban: "IBAN",
-    bitcoin: "Bitcoin",
-    "x-taler-bank": "Taler Bank",
+    // bitcoin: "Bitcoin",
+    // "x-taler-bank": "Taler Bank",
   };
   const uri = parsePaytoUri(payto);
   const found =
@@ -71,7 +71,25 @@ export function useComponentState(
       ? "that account is already present"
       : undefined;
 
-  const unableToAdd = !type || !alias || !!paytoUriError || !uri;
+  const unableToAdd = !type || !alias || paytoUriError !== undefined || uri 
!== undefined;
+
+  const accountByType: AccountByType = {
+    iban: [],
+    bitcoin: [],
+    "x-taler-bank": [],
+  }
+
+  hook.response.accounts.forEach(acc => {
+    accountByType[acc.uri.targetType].push(acc)
+  });
+
+  async function deleteAccount(account: KnownBankAccountsInfo): Promise<void> {
+    const payto = stringifyPaytoUri(account.uri);
+    await api.wallet.call(WalletApiOperation.ForgetKnownBankAccounts, {
+      payto
+    })
+    hook?.retry()
+  }
 
   return {
     status: "ready",
@@ -97,6 +115,8 @@ export function useComponentState(
         setPayto(v);
       },
     },
+    accountByType,
+    deleteAccount,
     onAccountAdded: {
       onClick: unableToAdd ? undefined : addAccount,
     },
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx
new file mode 100644
index 000000000..c0d3a38b0
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx
@@ -0,0 +1,208 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { createExample } from "../../test-utils.js";
+import { ReadyView } from "./views.js";
+
+export default {
+  title: "wallet/manage account",
+};
+
+const nullFunction = async () => {
+  null;
+};
+
+export const JustTwoBitcoinAccounts = createExample(ReadyView, {
+  status: "ready",
+  currency: "ARS",
+  accountType: {
+    list: {
+      "": "Choose one account type",
+      iban: "IBAN",
+      // bitcoin: "Bitcoin",
+      // "x-taler-bank": "Taler Bank",
+    },
+    value: "",
+  },
+  alias: {
+    value: "",
+    onInput: nullFunction,
+  },
+  uri: {
+    value: "",
+    onInput: nullFunction,
+  },
+  accountByType: {
+    iban: [],
+    "x-taler-bank": [],
+    bitcoin: [
+      {
+        alias: "my bitcoin addr",
+        currency: "BTC",
+        kyc_completed: false,
+        uri: {
+          targetType: "bitcoin",
+          segwitAddrs: [],
+          isKnown: true,
+          targetPath: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+          params: {},
+        },
+      },
+      {
+        alias: "my other addr",
+        currency: "BTC",
+        kyc_completed: true,
+        uri: {
+          targetType: "bitcoin",
+          segwitAddrs: [],
+          isKnown: true,
+          targetPath: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+          params: {},
+        },
+      },
+    ],
+  },
+  onAccountAdded: {},
+  onCancel: {},
+});
+
+export const WithAllTypeOfAccounts = createExample(ReadyView, {
+  status: "ready",
+  currency: "ARS",
+  accountType: {
+    list: {
+      "": "Choose one account type",
+      iban: "IBAN",
+      // bitcoin: "Bitcoin",
+      // "x-taler-bank": "Taler Bank",
+    },
+    value: "",
+  },
+  alias: {
+    value: "",
+    onInput: nullFunction,
+  },
+  uri: {
+    value: "",
+    onInput: nullFunction,
+  },
+  accountByType: {
+    iban: [
+      {
+        alias: "my bank",
+        currency: "ARS",
+        kyc_completed: true,
+        uri: {
+          targetType: "iban",
+          iban: "ASDQWEQWE",
+          isKnown: true,
+          targetPath: "/ASDQWEQWE",
+          params: {},
+        },
+      },
+    ],
+    "x-taler-bank": [
+      {
+        alias: "my xtaler bank",
+        currency: "ARS",
+        kyc_completed: true,
+        uri: {
+          targetType: "x-taler-bank",
+          host: "localhost",
+          account: "123",
+          isKnown: true,
+          targetPath: "localhost/123",
+          params: {},
+        },
+      },
+    ],
+    bitcoin: [
+      {
+        alias: "my bitcoin addr",
+        currency: "BTC",
+        kyc_completed: false,
+        uri: {
+          targetType: "bitcoin",
+          segwitAddrs: [],
+          isKnown: true,
+          targetPath: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+          params: {},
+        },
+      },
+      {
+        alias: "my other addr",
+        currency: "BTC",
+        kyc_completed: true,
+        uri: {
+          targetType: "bitcoin",
+          segwitAddrs: [],
+          isKnown: true,
+          targetPath: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+          params: {},
+        },
+      },
+    ],
+  },
+  onAccountAdded: {},
+  onCancel: {},
+});
+
+export const AddingIbanAccount = createExample(ReadyView, {
+  status: "ready",
+  currency: "ARS",
+  accountType: {
+    list: {
+      "": "Choose one account type",
+      iban: "IBAN",
+      // bitcoin: "Bitcoin",
+      // "x-taler-bank": "Taler Bank",
+    },
+    value: "iban",
+  },
+  alias: {
+    value: "",
+    onInput: nullFunction,
+  },
+  uri: {
+    value: "",
+    onInput: nullFunction,
+  },
+  accountByType: {
+    iban: [
+      {
+        alias: "my bank",
+        currency: "ARS",
+        kyc_completed: true,
+        uri: {
+          targetType: "iban",
+          iban: "ASDQWEQWE",
+          isKnown: true,
+          targetPath: "/ASDQWEQWE",
+          params: {},
+        },
+      },
+    ],
+    "x-taler-bank": [],
+    bitcoin: [],
+  },
+  onAccountAdded: {},
+  onCancel: {},
+});
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/test.ts 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/test.ts
similarity index 100%
rename from packages/taler-wallet-webextension/src/wallet/AddAccount/test.ts
rename to packages/taler-wallet-webextension/src/wallet/ManageAccount/test.ts
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
new file mode 100644
index 000000000..9bb9e5814
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
@@ -0,0 +1,534 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import {
+  KnownBankAccountsInfo,
+  PaytoUriBitcoin,
+  PaytoUriIBAN,
+  PaytoUriTalerBank,
+} from "@gnu-taler/taler-util";
+import { styled } from "@linaria/react";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { ErrorMessage } from "../../components/ErrorMessage.js";
+import { LoadingError } from "../../components/LoadingError.js";
+import { SelectList } from "../../components/SelectList.js";
+import {
+  Input,
+  LightText,
+  SubTitle,
+  SvgIcon,
+  WarningText,
+} from "../../components/styled/index.js";
+import { useTranslationContext } from "../../context/translation.js";
+import { Button } from "../../mui/Button.js";
+import { TextFieldHandler } from "../../mui/handlers.js";
+import { TextField } from "../../mui/TextField.js";
+import checkIcon from "../../svg/check_24px.svg";
+import warningIcon from "../../svg/warning_24px.svg";
+import deleteIcon from "../../svg/delete_24px.svg";
+import { State } from "./index.js";
+
+type AccountType = "bitcoin" | "x-taler-bank" | "iban";
+type ComponentFormByAccountType = {
+  [type in AccountType]: (props: { field: TextFieldHandler }) => VNode;
+};
+
+type ComponentListByAccountType = {
+  [type in AccountType]: (props: {
+    list: KnownBankAccountsInfo[];
+    onDelete: (a: KnownBankAccountsInfo) => Promise<void>;
+  }) => VNode;
+};
+
+const formComponentByAccountType: ComponentFormByAccountType = {
+  iban: IbanAddressAccount,
+  bitcoin: BitcoinAddressAccount,
+  "x-taler-bank": TalerBankAddressAccount,
+};
+const tableComponentByAccountType: ComponentListByAccountType = {
+  iban: IbanTable,
+  bitcoin: BitcoinTable,
+  "x-taler-bank": TalerBankTable,
+};
+
+const AccountTable = styled.table`
+  width: 100%;
+
+  border-collapse: separate;
+  border-spacing: 0px 10px;
+  tbody tr:nth-child(odd) > td:not(.actions, .kyc) {
+    background-color: lightgrey;
+  }
+  .actions,
+  .kyc {
+    width: 10px;
+    background-color: inherit;
+  }
+`;
+
+export function LoadingUriView({ error }: State.LoadingUriError): VNode {
+  const { i18n } = useTranslationContext();
+
+  return (
+    <LoadingError
+      title={<i18n.Translate>Could not load</i18n.Translate>}
+      error={error}
+    />
+  );
+}
+
+export function ReadyView({
+  currency,
+  error,
+  accountType,
+  accountByType,
+  alias,
+  onAccountAdded,
+  deleteAccount,
+  onCancel,
+  uri,
+}: State.Ready): VNode {
+  const { i18n } = useTranslationContext();
+
+  return (
+    <Fragment>
+      <section>
+        <SubTitle>
+          <i18n.Translate>Known accounts for {currency}</i18n.Translate>
+        </SubTitle>
+        <p>
+          <i18n.Translate>
+            To add a new account first select the account type.
+          </i18n.Translate>
+        </p>
+
+        {error && (
+          <ErrorMessage
+            title={<i18n.Translate>Unable add this account</i18n.Translate>}
+            description={error}
+          />
+        )}
+        <p>
+          <Input>
+            <SelectList
+              label={<i18n.Translate>Select account type</i18n.Translate>}
+              list={accountType.list}
+              name="accountType"
+              value={accountType.value}
+              onChange={accountType.onChange}
+            />
+          </Input>
+        </p>
+        {accountType.value === "" ? undefined : (
+          <Fragment>
+            <p>
+              <CustomFieldByAccountType
+                type={accountType.value as AccountType}
+                field={uri}
+              />
+            </p>
+            <p>
+              <TextField
+                label="Account alias"
+                variant="standard"
+                required
+                fullWidth
+                disabled={accountType.value === ""}
+                value={alias.value}
+                onChange={alias.onInput}
+              />
+            </p>
+          </Fragment>
+        )}
+      </section>
+      <section>
+        <Button
+          variant="contained"
+          color="secondary"
+          onClick={onCancel.onClick}
+        >
+          <i18n.Translate>Cancel</i18n.Translate>
+        </Button>
+        <Button
+          variant="contained"
+          onClick={onAccountAdded.onClick}
+          disabled={!onAccountAdded.onClick}
+        >
+          <i18n.Translate>Add</i18n.Translate>
+        </Button>
+      </section>
+      <section>
+        {Object.entries(accountByType).map(([type, list]) => {
+          const Table = tableComponentByAccountType[type as AccountType];
+          return <Table key={type} list={list} onDelete={deleteAccount} />;
+        })}
+      </section>
+    </Fragment>
+  );
+}
+
+function IbanTable({
+  list,
+  onDelete,
+}: {
+  list: KnownBankAccountsInfo[];
+  onDelete: (ac: KnownBankAccountsInfo) => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  if (list.length === 0) return <Fragment />;
+  return (
+    <div>
+      <h1>
+        <i18n.Translate>IBAN accounts</i18n.Translate>
+      </h1>
+      <AccountTable>
+        <thead>
+          <tr>
+            <th>
+              <i18n.Translate>Alias</i18n.Translate>
+            </th>
+            <th>
+              <i18n.Translate>Int. Account Number</i18n.Translate>
+            </th>
+            <th class="kyc">
+              <i18n.Translate>KYC</i18n.Translate>
+            </th>
+            <th class="actions"></th>
+          </tr>
+        </thead>
+        <tbody>
+          {list.map((account) => {
+            const p = account.uri as PaytoUriIBAN;
+            return (
+              <tr key={account.alias}>
+                <td>{account.alias}</td>
+                <td>{p.targetPath}</td>
+                <td class="kyc">
+                  {account.kyc_completed ? (
+                    <SvgIcon
+                      title={i18n.str`KYC done`}
+                      dangerouslySetInnerHTML={{ __html: checkIcon }}
+                      color="green"
+                    />
+                  ) : (
+                    <SvgIcon
+                      title={i18n.str`KYC missing`}
+                      dangerouslySetInnerHTML={{ __html: warningIcon }}
+                      color="orange"
+                    />
+                  )}
+                </td>
+                <td class="actions">
+                  <Button
+                    variant="outlined"
+                    startIcon={deleteIcon}
+                    size="small"
+                    onClick={async () => onDelete(account)}
+                    color="error"
+                  >
+                    Forget
+                  </Button>
+                </td>
+              </tr>
+            );
+          })}
+        </tbody>
+      </AccountTable>
+    </div>
+  );
+}
+
+function TalerBankTable({
+  list,
+  onDelete,
+}: {
+  list: KnownBankAccountsInfo[];
+  onDelete: (ac: KnownBankAccountsInfo) => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  if (list.length === 0) return <Fragment />;
+  return (
+    <div>
+      <h1>
+        <i18n.Translate>Taler accounts</i18n.Translate>
+      </h1>
+      <AccountTable>
+        <thead>
+          <tr>
+            <th>
+              <i18n.Translate>Alias</i18n.Translate>
+            </th>
+            <th>
+              <i18n.Translate>Host</i18n.Translate>
+            </th>
+            <th>
+              <i18n.Translate>Account</i18n.Translate>
+            </th>
+            <th class="kyc">
+              <i18n.Translate>KYC</i18n.Translate>
+            </th>
+            <th class="actions"></th>
+          </tr>
+        </thead>
+        <tbody>
+          {list.map((account) => {
+            const p = account.uri as PaytoUriTalerBank;
+            return (
+              <tr key={account.alias}>
+                <td>{account.alias}</td>
+                <td>{p.host}</td>
+                <td>{p.account}</td>
+                <td class="kyc">
+                  {account.kyc_completed ? (
+                    <SvgIcon
+                      title={i18n.str`KYC done`}
+                      dangerouslySetInnerHTML={{ __html: checkIcon }}
+                      color="green"
+                    />
+                  ) : (
+                    <SvgIcon
+                      title={i18n.str`KYC missing`}
+                      dangerouslySetInnerHTML={{ __html: warningIcon }}
+                      color="orange"
+                    />
+                  )}
+                </td>
+                <td class="actions">
+                  <Button
+                    variant="outlined"
+                    startIcon={deleteIcon}
+                    size="small"
+                    onClick={async () => onDelete(account)}
+                    color="error"
+                  >
+                    Forget
+                  </Button>
+                </td>
+              </tr>
+            );
+          })}
+        </tbody>
+      </AccountTable>
+    </div>
+  );
+}
+
+function BitcoinTable({
+  list,
+  onDelete,
+}: {
+  list: KnownBankAccountsInfo[];
+  onDelete: (ac: KnownBankAccountsInfo) => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  if (list.length === 0) return <Fragment />;
+  return (
+    <div>
+      <h2>
+        <i18n.Translate>Bitcoin accounts</i18n.Translate>
+      </h2>
+      <AccountTable>
+        <thead>
+          <tr>
+            <th>
+              <i18n.Translate>Alias</i18n.Translate>
+            </th>
+            <th>
+              <i18n.Translate>Address</i18n.Translate>
+            </th>
+            <th class="kyc">
+              <i18n.Translate>KYC</i18n.Translate>
+            </th>
+            <th class="actions"></th>
+          </tr>
+        </thead>
+        <tbody>
+          {list.map((account) => {
+            const p = account.uri as PaytoUriBitcoin;
+            return (
+              <tr key={account.alias}>
+                <td>{account.alias}</td>
+                <td>{p.targetPath}</td>
+                <td class="kyc">
+                  {account.kyc_completed ? (
+                    <SvgIcon
+                      title={i18n.str`KYC done`}
+                      dangerouslySetInnerHTML={{ __html: checkIcon }}
+                      color="green"
+                    />
+                  ) : (
+                    <SvgIcon
+                      title={i18n.str`KYC missing`}
+                      dangerouslySetInnerHTML={{ __html: warningIcon }}
+                      color="orange"
+                    />
+                  )}
+                </td>
+                <td class="actions">
+                  <Button
+                    variant="outlined"
+                    startIcon={deleteIcon}
+                    size="small"
+                    onClick={async () => onDelete(account)}
+                    color="error"
+                  >
+                    Forget
+                  </Button>
+                </td>
+              </tr>
+            );
+          })}
+        </tbody>
+      </AccountTable>
+    </div>
+  );
+}
+
+function BitcoinAddressAccount({ field }: { field: TextFieldHandler }): VNode {
+  const { i18n } = useTranslationContext();
+  const [value, setValue] = useState<string | undefined>(undefined);
+  const errors = undefinedIfEmpty({
+    value: !value ? i18n.str`Can't be empty` : undefined,
+  });
+  return (
+    <Fragment>
+      <TextField
+        label="Bitcoin address"
+        variant="standard"
+        fullWidth
+        value={value}
+        error={value !== undefined && !!errors?.value}
+        onChange={(v) => {
+          setValue(v);
+          if (!errors) {
+            field.onInput(`payto://bitcoin/${v}`);
+          }
+        }}
+      />
+      {value !== undefined && errors?.value && (
+        <ErrorMessage title={<span>{errors?.value}</span>} />
+      )}
+    </Fragment>
+  );
+}
+
+function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
+  return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
+    ? obj
+    : undefined;
+}
+
+function TalerBankAddressAccount({
+  field,
+}: {
+  field: TextFieldHandler;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const [host, setHost] = useState<string | undefined>(undefined);
+  const [account, setAccount] = useState<string | undefined>(undefined);
+  const errors = undefinedIfEmpty({
+    host: !host ? i18n.str`Can't be empty` : undefined,
+    account: !account ? i18n.str`Can't be empty` : undefined,
+  });
+  return (
+    <Fragment>
+      <TextField
+        label="Bank host"
+        variant="standard"
+        fullWidth
+        value={host}
+        error={host !== undefined && !!errors?.host}
+        onChange={(v) => {
+          setHost(v);
+          if (!errors) {
+            field.onInput(`payto://x-taler-bank/${v}/${account}`);
+          }
+        }}
+      />{" "}
+      {host !== undefined && errors?.host && (
+        <ErrorMessage title={<span>{errors?.host}</span>} />
+      )}
+      <TextField
+        label="Bank account"
+        variant="standard"
+        fullWidth
+        value={account}
+        error={account !== undefined && !!errors?.account}
+        onChange={(v) => {
+          setAccount(v || "");
+          if (!errors) {
+            field.onInput(`payto://x-taler-bank/${host}/${v}`);
+          }
+        }}
+      />{" "}
+      {account !== undefined && errors?.account && (
+        <ErrorMessage title={<span>{errors?.account}</span>} />
+      )}
+    </Fragment>
+  );
+}
+
+function IbanAddressAccount({ field }: { field: TextFieldHandler }): VNode {
+  const { i18n } = useTranslationContext();
+  const [value, setValue] = useState<string | undefined>(undefined);
+  const errors = undefinedIfEmpty({
+    value: !value ? i18n.str`Can't be empty` : undefined,
+  });
+  return (
+    <Fragment>
+      <TextField
+        label="IBAN number"
+        variant="standard"
+        fullWidth
+        value={value}
+        error={value !== undefined && !!errors?.value}
+        onChange={(v) => {
+          setValue(v);
+          if (!errors) {
+            field.onInput(`payto://iban/${v}`);
+          }
+        }}
+      />
+      {value !== undefined && errors?.value && (
+        <ErrorMessage title={<span>{errors?.value}</span>} />
+      )}
+    </Fragment>
+  );
+}
+
+function CustomFieldByAccountType({
+  type,
+  field,
+}: {
+  type: AccountType;
+  field: TextFieldHandler;
+}): VNode {
+  const { i18n } = useTranslationContext();
+
+  const AccountForm = formComponentByAccountType[type];
+
+  return (
+    <div>
+      <WarningText>
+        <i18n.Translate>
+          We can not validate the account so make sure the value is correct.
+        </i18n.Translate>
+      </WarningText>
+      <AccountForm field={field} />
+    </div>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
index c2f0c6481..d63f25ead 100644
--- a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
@@ -37,6 +37,7 @@ import * as a16 from "./DeveloperPage.stories.js";
 import * as a17 from "./QrReader.stories.js";
 import * as a18 from "./DestinationSelection.stories.js";
 import * as a19 from "./ExchangeSelection/stories.js";
+import * as a20 from "./ManageAccount/stories.js";
 
 export default [
   a1,
@@ -57,4 +58,5 @@ export default [
   a17,
   a18,
   a19,
+  a20,
 ];

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