gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (eeea47837 -> 8f0e2ca8e)


From: gnunet
Subject: [taler-wallet-core] branch master updated (eeea47837 -> 8f0e2ca8e)
Date: Mon, 23 Sep 2024 21:24:40 +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 eeea47837 harness: test getMaxPeerPushDebitAmount
     new 4f55f3f22 show instructions on how to complete kyc auth
     new 8f0e2ca8e add missing refactor

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:
 .../bank-ui/src/pages/PaytoWireTransferForm.tsx    |  28 ++-
 packages/merchant-backoffice-ui/src/Routing.tsx    |  14 +-
 .../src/components/Amount.tsx                      |   0
 .../src/components/menu/SideBar.tsx                |  16 +-
 .../src/components/modal/index.tsx                 | 251 ++++++++++++++++++++-
 packages/merchant-backoffice-ui/src/hooks/urls.ts  |  31 +--
 .../paths/instance/kyc/list/ListPage.stories.tsx   |  12 +-
 .../src/paths/instance/kyc/list/ListPage.tsx       |  92 ++++----
 .../src/paths/instance/kyc/list/index.tsx          |  66 +++++-
 .../integrationtests/test-kyc-merchant-deposit.ts  |   8 +-
 packages/taler-util/src/http-client/merchant.ts    |  60 ++++-
 packages/taler-util/src/types-taler-merchant.ts    | 116 +---------
 .../src/components/BankDetailsByPaytoType.tsx      |  85 ++++---
 13 files changed, 530 insertions(+), 249 deletions(-)
 copy packages/{taler-wallet-webextension => 
merchant-backoffice-ui}/src/components/Amount.tsx (100%)

diff --git a/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx 
b/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx
index d52961204..9cba67384 100644
--- a/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -209,7 +209,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`The request was invalid or the payto://-URI used 
unacceptable features.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -217,7 +217,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`Not enough permission to complete the 
operation.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -225,7 +225,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`Bank administrator can't be the transfer 
creditor.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -235,7 +235,7 @@ export function PaytoWireTransferForm({
               title: i18n.str`The destination account "${
                 acName ?? puri
               }" was not found.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -243,7 +243,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`The origin and the destination of the transfer 
can't be the same.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -251,7 +251,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`Your balance is not enough.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -259,7 +259,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`The origin account "${puri}" was not found.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -267,7 +267,7 @@ export function PaytoWireTransferForm({
             return notify({
               type: "error",
               title: i18n.str`Tried to create the transaction 
${check.maxTries} times with different UID but failed.`,
-              description: resp.detail?.hint as TranslatedString ,
+              description: resp.detail?.hint as TranslatedString,
               debug: resp.detail,
               when: AbsoluteTime.now(),
             });
@@ -341,7 +341,9 @@ export function PaytoWireTransferForm({
                         setAmount(Amounts.stringifyValue(amount));
                       }
                     }
-                    const subject = parsed.params["message"];
+                    const subject = !parsed.params["message"]
+                      ? parsed.params["subject"]
+                      : parsed.params["message"];
                     if (subject) {
                       setSubject(subject);
                     }
@@ -865,10 +867,12 @@ function validateRawPayto(
   result = validateAmount(amount, limit, i18n);
   if (result) return result;
 
-  if (!parsed.params.message) {
-    return i18n.str`Missing the "message" parameter to specify a reference 
text for the transfer`;
+  if (!parsed.params.message && !parsed.params.subject) {
+    return i18n.str`Missing the "message" or "subject" parameter to specify a 
reference text for the transfer`;
   }
-  const subject = parsed.params.message;
+  const subject = !parsed.params.message
+    ? parsed.params.subject
+    : parsed.params.message;
   result = validateSubject(subject, i18n);
   if (result) return result;
 
diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx 
b/packages/merchant-backoffice-ui/src/Routing.tsx
index 81e20d16d..de87db298 100644
--- a/packages/merchant-backoffice-ui/src/Routing.tsx
+++ b/packages/merchant-backoffice-ui/src/Routing.tsx
@@ -610,7 +610,13 @@ export function Routing(_p: Props): VNode {
           }}
         />
 
-        <Route path={InstancePaths.kyc} component={ListKYCPage} />
+        <Route
+          path={InstancePaths.kyc}
+          component={ListKYCPage}
+          // onSelect={(id: string) => {
+          //   route(InstancePaths.bank_update.replace(":bid", id));
+          // }}
+        />
         <Route path={InstancePaths.interface} component={Settings} />
         {/**
          * Example pages
@@ -688,8 +694,10 @@ function KycBanner(): VNode {
     kycStatus !== undefined &&
     !(kycStatus instanceof TalerError) &&
     kycStatus.type === "ok" &&
-    !!kycStatus.body;
-
+    !!kycStatus.body &&
+    kycStatus.body.kyc_data.findIndex(
+      (d) => d.payto_kycauths !== undefined || d.access_token !== undefined,
+    ) !== -1;
   const hidden = AbsoluteTime.cmp(now, prefs.hideKycUntil) < 1;
   if (hidden || !needsToBeShown) return <Fragment />;
 
diff --git a/packages/taler-wallet-webextension/src/components/Amount.tsx 
b/packages/merchant-backoffice-ui/src/components/Amount.tsx
similarity index 100%
copy from packages/taler-wallet-webextension/src/components/Amount.tsx
copy to packages/merchant-backoffice-ui/src/components/Amount.tsx
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx 
b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index febf282dc..90cf22d72 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -44,7 +44,10 @@ export function Sidebar({ mobile }: Props): VNode {
     kycStatus !== undefined &&
     !(kycStatus instanceof TalerError) &&
     kycStatus.type === "ok" &&
-    !!kycStatus.body;
+    !!kycStatus.body &&
+    kycStatus.body.kyc_data.findIndex(
+      (d) => d.payto_kycauths !== undefined || d.access_token !== undefined,
+    ) !== -1;
   const isLoggedIn = state.status === "loggedIn";
   const hasToken = isLoggedIn && state.token !== undefined;
 
@@ -143,8 +146,15 @@ export function Sidebar({ mobile }: Props): VNode {
                 </li>
               ) : undefined}
               {needKYC && (
-                <li>
-                  <a href={"/kyc"} class="has-icon">
+                <li class="is-warning">
+                  <a
+                    href={"/kyc"}
+                    class="has-icon"
+                    style={{
+                      backgroundColor: "darkorange",
+                      color: "black",
+                    }}
+                  >
                     <span class="icon">
                       <i class="mdi mdi-account-check" />
                     </span>
diff --git a/packages/merchant-backoffice-ui/src/components/modal/index.tsx 
b/packages/merchant-backoffice-ui/src/components/modal/index.tsx
index 8d2cb2831..fc06b0aca 100644
--- a/packages/merchant-backoffice-ui/src/components/modal/index.tsx
+++ b/packages/merchant-backoffice-ui/src/components/modal/index.tsx
@@ -25,16 +25,18 @@ import {
   PaytoString,
   PaytoUri,
   stringifyPaytoUri,
+  TranslatedString,
 } from "@gnu-taler/taler-util";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
-import { useState } from "preact/hooks";
+import { useEffect, useRef, useState } from "preact/hooks";
 import { useSessionContext } from "../../context/session.js";
 import { DEFAULT_REQUEST_TIMEOUT } from "../../utils/constants.js";
 import { undefinedIfEmpty } from "../../utils/table.js";
 import { Spinner } from "../exception/loading.js";
 import { FormErrors, FormProvider } from "../form/FormProvider.js";
 import { Input } from "../form/Input.js";
+import { Amount } from "../Amount.js";
 
 interface Props {
   active?: boolean;
@@ -420,6 +422,253 @@ export function CompareAccountsModal({
   );
 }
 
+interface ValidateBankAccountModalProps {
+  onCancel: () => void;
+  origin: PaytoUri;
+  targets: PaytoUri[];
+}
+export function ValidBankAccount({
+  onCancel,
+  origin,
+  targets,
+}: ValidateBankAccountModalProps): VNode {
+  const { i18n } = useTranslationContext();
+  const payto = targets[0];
+  const subject = payto.params["subject"];
+
+  const accountPart = !payto.isKnown ? (
+    <Fragment>
+      <Row name={i18n.str`Account`} value={payto.targetPath} />
+    </Fragment>
+  ) : payto.targetType === "x-taler-bank" ? (
+    <Fragment>
+      <Row name={i18n.str`Bank host`} value={payto.host} />
+      <Row name={i18n.str`Bank account`} value={payto.account} />
+    </Fragment>
+  ) : payto.targetType === "iban" ? (
+    <Fragment>
+      {payto.bic !== undefined ? (
+        <Row name={i18n.str`BIC`} value={payto.bic} />
+      ) : undefined}
+      <Row name={i18n.str`IBAN`} value={payto.iban} />
+    </Fragment>
+  ) : undefined;
+
+  const receiver =
+    payto.params["receiver-name"] || payto.params["receiver"] || undefined;
+
+  const from = !origin.isKnown
+    ? origin.targetPath
+    : origin.targetType === "iban"
+      ? origin.iban
+      : origin.targetType === "bitcoin"
+        ? `${origin.address.substring(0, 8)}...`
+        : origin.account;
+
+  return (
+    <ConfirmModal
+      label={i18n.str`Ok`}
+      description={i18n.str`Validate bank account: ${from}`}
+      active
+      onCancel={onCancel}
+      // onConfirm={onConfirm}
+    >
+      <p style={{ paddingTop: 0 }}>
+        <i18n.Translate>
+          You need to make a bank transfer with the specified subject to
+          validate that you are the owner of the account.
+        </i18n.Translate>
+      </p>
+      <div class="table-container">
+        <table>
+          <tbody>
+            <tr>
+              <td colSpan={3}>
+                <i18n.Translate>Step 1:</i18n.Translate>
+                &nbsp;
+                <i18n.Translate>
+                  Copy this code and paste it into the subject/purpose field in
+                  your banking app or bank website
+                </i18n.Translate>
+              </td>
+            </tr>
+            <Row name={i18n.str`Subject`} value={subject} literal />
+
+            <tr>
+              <td colSpan={3}>
+                <i18n.Translate>Step 2:</i18n.Translate>
+                &nbsp;
+                <i18n.Translate>
+                  Copy and paste this IBAN and the name into the receiver 
fields
+                  in your banking app or website
+                </i18n.Translate>
+              </td>
+            </tr>
+            {accountPart}
+            {receiver ? (
+              <Row name={i18n.str`Receiver name`} value={receiver} />
+            ) : undefined}
+
+            <tr>
+              <td colSpan={3}>
+                <i18n.Translate>Step 3:</i18n.Translate>
+                &nbsp;
+                <i18n.Translate>
+                  Finish the wire transfer setting smallest amount in your
+                  banking app or website.
+                </i18n.Translate>
+              </td>
+            </tr>
+            {/* <Row
+              name={i18n.str`Amount`}
+              value={
+                <Amount
+                  value={payto.params["amount"] as AmountString}
+                  hideCurrency
+                />
+              }
+            /> */}
+
+            <tr>
+              <td colSpan={3}>
+                {/* <WarningBox style={{ margin: 0 }}> */}
+                <b>
+                  <i18n.Translate>
+                    Make sure ALL data is correct, including the subject and 
you
+                    are using your selected bank account. You can use the copy
+                    buttons (<CopyIcon />) to prevent typing errors or the
+                    "payto://" URI below to copy just one value.
+                  </i18n.Translate>
+                </b>
+                {/* </WarningBox> */}
+              </td>
+            </tr>
+
+            <tr>
+              <td colSpan={2} width="100%" style={{ wordBreak: "break-all" }}>
+                <i18n.Translate>
+                  Alternative if your bank already supports PayTo URI, you can
+                  use this{" "}
+                  <a
+                    target="_bank"
+                    rel="noreferrer"
+                    title="RFC 8905 for designating targets for payments"
+                    href="https://tools.ietf.org/html/rfc8905";
+                  >
+                    PayTo URI
+                  </a>{" "}
+                  link instead
+                </i18n.Translate>
+              </td>
+              <td>
+                <CopyButton getContent={() => stringifyPaytoUri(payto)} />
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+    </ConfirmModal>
+  );
+}
+
+function Row({
+  name,
+  value,
+  literal,
+}: {
+  name: TranslatedString;
+  value: string | VNode;
+  literal?: boolean;
+}): VNode {
+  const preRef = useRef<HTMLPreElement>(null);
+  const tdRef = useRef<HTMLTableCellElement>(null);
+
+  function getContent(): string {
+    return preRef.current?.textContent || tdRef.current?.textContent || "";
+  }
+
+  return (
+    <tr>
+      <td style={{ padding: 4, width: "1%", whiteSpace: "nowrap" }}>
+        <b>{name}</b>
+      </td>
+      {literal ? (
+        <td style={{ padding: 4 }}>
+          <pre
+            ref={preRef}
+            style={{
+              whiteSpace: "pre-wrap",
+              wordBreak: "break-word",
+              padding: 4,
+            }}
+          >
+            {value}
+          </pre>
+        </td>
+      ) : (
+        <td ref={tdRef} style={{ padding: 4 }}>
+          {value}
+        </td>
+      )}
+      <td style={{ padding: 4 }}>
+        <CopyButton getContent={getContent} />
+      </td>
+    </tr>
+  );
+}
+
+function CopyButton({ getContent }: { getContent: () => string }): VNode {
+  const [copied, setCopied] = useState(false);
+  function copyText(): void {
+    navigator.clipboard.writeText(getContent() || "");
+    setCopied(true);
+  }
+  useEffect(() => {
+    if (copied) {
+      setTimeout(() => {
+        setCopied(false);
+      }, 1000);
+    }
+  }, [copied]);
+
+  if (!copied) {
+    return (
+      <button onClick={copyText}>
+        <CopyIcon />
+      </button>
+    );
+  }
+  return (
+    // <TooltipLeft content="Copied">
+    <button disabled>
+      <CopiedIcon />
+    </button>
+    // </TooltipLeft>
+  );
+}
+
+export const CopyIcon = (): VNode => (
+  <svg height="16" viewBox="0 0 16 16" width="16">
+    <path
+      fill-rule="evenodd"
+      d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 
00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 
0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"
+    />
+    <path
+      fill-rule="evenodd"
+      d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 
1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 
00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 
00-.25-.25h-7.5z"
+    />
+  </svg>
+);
+
+export const CopiedIcon = (): VNode => (
+  <svg height="16" viewBox="0 0 16 16" width="16">
+    <path
+      fill-rule="evenodd"
+      d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 
9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
+    />
+  </svg>
+);
+
 interface DeleteModalProps {
   element: { id: string; name: string };
   onCancel: () => void;
diff --git a/packages/merchant-backoffice-ui/src/hooks/urls.ts 
b/packages/merchant-backoffice-ui/src/hooks/urls.ts
index 50d592584..f24c4d49b 100644
--- a/packages/merchant-backoffice-ui/src/hooks/urls.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/urls.ts
@@ -40,10 +40,7 @@ export const API_GET_ORDER_BY_ID = (
   url: `http://backend/instances/default/private/orders/${id}`,
 });
 
-export const API_LIST_ORDERS: Query<
-  unknown,
-  TalerMerchantApi.OrderHistory
-> = {
+export const API_LIST_ORDERS: Query<unknown, TalerMerchantApi.OrderHistory> = {
   method: "GET",
   url: "http://backend/instances/default/private/orders";,
 };
@@ -76,13 +73,11 @@ export const API_DELETE_ORDER = (
 // TRANSFER
 ////////////////////
 
-export const API_LIST_TRANSFERS: Query<
-  unknown,
-  TalerMerchantApi.TransferList
-> = {
-  method: "GET",
-  url: "http://backend/instances/default/private/transfers";,
-};
+export const API_LIST_TRANSFERS: Query<unknown, TalerMerchantApi.TransferList> 
=
+  {
+    method: "GET",
+    url: "http://backend/instances/default/private/transfers";,
+  };
 
 export const API_INFORM_TRANSFERS: Query<
   TalerMerchantApi.TransferInformation,
@@ -155,7 +150,7 @@ export const API_GET_INSTANCE_BY_ID = (
 
 export const API_GET_INSTANCE_KYC_BY_ID = (
   id: string,
-): Query<unknown, TalerMerchantApi.LegacyAccountKycRedirects> => ({
+): Query<unknown, TalerMerchantApi.MerchantAccountKycRedirectsResponse> => ({
   method: "GET",
   url: `http://backend/management/instances/${id}/kyc`,
 });
@@ -170,20 +165,14 @@ export const API_LIST_INSTANCES: Query<
 
 export const API_UPDATE_INSTANCE_BY_ID = (
   id: string,
-): Query<
-  TalerMerchantApi.InstanceReconfigurationMessage,
-  unknown
-> => ({
+): Query<TalerMerchantApi.InstanceReconfigurationMessage, unknown> => ({
   method: "PATCH",
   url: `http://backend/management/instances/${id}`,
 });
 
 export const API_UPDATE_INSTANCE_AUTH_BY_ID = (
   id: string,
-): Query<
-  TalerMerchantApi.InstanceAuthConfigurationMessage,
-  unknown
-> => ({
+): Query<TalerMerchantApi.InstanceAuthConfigurationMessage, unknown> => ({
   method: "POST",
   url: `http://backend/management/instances/${id}/auth`,
 });
@@ -207,7 +196,7 @@ export const API_GET_CURRENT_INSTANCE: Query<
 
 export const API_GET_CURRENT_INSTANCE_KYC: Query<
   unknown,
-  TalerMerchantApi.LegacyAccountKycRedirects
+  TalerMerchantApi.MerchantAccountKycRedirectsResponse
 > = {
   method: "GET",
   url: `http://backend/instances/default/private/kyc`,
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.stories.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.stories.tsx
index 44fa429a4..2220b6d1e 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.stories.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.stories.tsx
@@ -34,23 +34,29 @@ export default {
 
 export const Example = tests.createExample(TestedComponent, {
   status: {
-    timeout_kycs: [],
-    pending_kycs: [
+    // timeout_kycs: [],
+    kyc_data: [
       {
         exchange_url: "http://exchange.taler";,
         payto_uri: "payto://iban/de123123123" as PaytoString,
-        kyc_url: "http://exchange.taler/kyc";,
+        // kyc_url: "http://exchange.taler/kyc";,
         exchange_http_status: 0,
+        auth_conflict: false,
+        no_keys: false,
       },
       {
         exchange_http_status: 1,
         exchange_url: "http://exchange.taler";,
         payto_uri: "payto://iban/de123123123" as PaytoString,
+        auth_conflict: false,
+        no_keys: false,
       },
       {
         exchange_http_status: 2,
         exchange_url: "http://exchange.taler";,
         payto_uri: "payto://iban/de123123123" as PaytoString,
+        auth_conflict: false,
+        no_keys: false,
       },
     ],
   },
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx
index 52c813716..4e9a708fc 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/ListPage.tsx
@@ -19,15 +19,27 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { TalerMerchantApi } from "@gnu-taler/taler-util";
+import {
+  AccessToken,
+  encodeCrock,
+  hashPaytoUri,
+  hashWire,
+  TalerMerchantApi,
+} from "@gnu-taler/taler-util";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { h, VNode } from "preact";
 
 export interface Props {
-  status: TalerMerchantApi.LegacyAccountKycRedirects;
+  status: TalerMerchantApi.MerchantAccountKycRedirectsResponse;
+  // onGetInfo: (url: string, token: AccessToken) => void;
+  onShowInstructions: (toAccounts: string[], fromAccount: string) => void;
 }
 
-export function ListPage({ status }: Props): VNode {
+export function ListPage({
+  status,
+  // onGetInfo,
+  onShowInstructions,
+}: Props): VNode {
   const { i18n } = useTranslationContext();
 
   return (
@@ -46,8 +58,12 @@ export function ListPage({ status }: Props): VNode {
         <div class="card-content">
           <div class="b-table has-pagination">
             <div class="table-wrapper has-mobile-cards">
-              {status.pending_kycs.length > 0 ? (
-                <PendingTable entries={status.pending_kycs} />
+              {status.kyc_data.length > 0 ? (
+                <PendingTable
+                  entries={status.kyc_data}
+                  // onGetInfo={onGetInfo}
+                  onShowInstructions={onShowInstructions}
+                />
               ) : (
                 <EmptyTable />
               )}
@@ -55,44 +71,24 @@ export function ListPage({ status }: Props): VNode {
           </div>
         </div>
       </div>
-
-      {status.timeout_kycs.length > 0 ? (
-        <div class="card has-table">
-          <header class="card-header">
-            <p class="card-header-title">
-              <span class="icon">
-                <i class="mdi mdi-clock" />
-              </span>
-              <i18n.Translate>Timed out</i18n.Translate>
-            </p>
-
-            <div class="card-header-icon" aria-label="more options" />
-          </header>
-          <div class="card-content">
-            <div class="b-table has-pagination">
-              <div class="table-wrapper has-mobile-cards">
-                {status.timeout_kycs.length > 0 ? (
-                  <TimedOutTable entries={status.timeout_kycs} />
-                ) : (
-                  <EmptyTable />
-                )}
-              </div>
-            </div>
-          </div>
-        </div>
-      ) : undefined}
     </section>
   );
 }
 interface PendingTableProps {
-  entries: TalerMerchantApi.LegacyMerchantAccountKycRedirect[];
+  entries: TalerMerchantApi.MerchantAccountKycRedirect[];
+  // onGetInfo: (url: string, token: AccessToken) => void;
+  onShowInstructions: (toAccounts: string[], fromAccount: string) => void;
 }
 
 interface TimedOutTableProps {
   entries: TalerMerchantApi.ExchangeKycTimeout[];
 }
 
-function PendingTable({ entries }: PendingTableProps): VNode {
+function PendingTable({
+  entries,
+  onShowInstructions,
+  // onGetInfo,
+}: PendingTableProps): VNode {
   const { i18n } = useTranslationContext();
   return (
     <div class="table-container">
@@ -103,7 +99,7 @@ function PendingTable({ entries }: PendingTableProps): VNode 
{
               <i18n.Translate>Exchange</i18n.Translate>
             </th>
             <th>
-              <i18n.Translate>Target account</i18n.Translate>
+              <i18n.Translate>Account</i18n.Translate>
             </th>
             <th>
               <i18n.Translate>Reason</i18n.Translate>
@@ -112,31 +108,37 @@ function PendingTable({ entries }: PendingTableProps): 
VNode {
         </thead>
         <tbody>
           {entries.map((e, i) => {
-            if (e.kyc_url === undefined) {
-              // blocked by AML
+            if (e.payto_kycauths === undefined) {
+              const spa = new URL(`kyc-spa/${e.access_token}`, e.exchange_url)
+                .href;
               return (
                 <tr key={i}>
                   <td>{e.exchange_url}</td>
                   <td>{e.payto_uri}</td>
                   <td>
-                    <i18n.Translate>
-                      There is an anti-money laundering process pending to
-                      complete.
-                    </i18n.Translate>
-
+                    <a href={spa} target="_black" rel="noreferrer">
+                      <i18n.Translate>
+                        Pending KYC process, click here to complete
+                      </i18n.Translate>
+                    </a>
                   </td>
                 </tr>
               );
             } else {
-              // blocked by KYC
+              const accounts = e.payto_kycauths;
               return (
                 <tr key={i}>
                   <td>{e.exchange_url}</td>
-                  <td>{e.payto_uri}</td>
+                  <td
+                    onClick={() => onShowInstructions(accounts, e.payto_uri)}
+                    style={{ cursor: "pointer" }}
+                  >
+                    {e.payto_uri}
+                  </td>
                   <td>
-                    <a href={e.kyc_url} target="_black" rel="noreferrer">
+                    <a href={e.access_token} target="_black" rel="noreferrer">
                       <i18n.Translate>
-                        Pending KYC process, click here to complete
+                        The exchange require a account verification.
                       </i18n.Translate>
                     </a>
                   </td>
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx
index ff63dc64e..9f65be0c3 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx
@@ -19,21 +19,34 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { HttpStatusCode, TalerError, assertUnreachable } from 
"@gnu-taler/taler-util";
-import { VNode, h } from "preact";
+import {
+  HttpStatusCode,
+  TalerError,
+  TalerExchangeHttpClient,
+  assertUnreachable,
+  parsePaytoUri,
+} from "@gnu-taler/taler-util";
+import { Fragment, VNode, h } from "preact";
 import { ErrorLoadingMerchant } from 
"../../../../components/ErrorLoadingMerchant.js";
 import { Loading } from "../../../../components/exception/loading.js";
 import { useInstanceKYCDetails } from "../../../../hooks/instance.js";
 import { ListPage } from "./ListPage.js";
+import { useState } from "preact/hooks";
+import { ValidBankAccount } from "../../../../components/modal/index.js";
 
 interface Props {
+  // onGetInfo: (id: string) => void;
+  // onShowInstructions: (id: string) => void;
 }
 
 export default function ListKYC(_p: Props): VNode {
   const result = useInstanceKYCDetails();
-  if (!result) return <Loading />
+  const [showingInstructions, setShowingInstructions] = useState<
+    { toAccounts: string[]; fromAccount: string } | undefined
+  >(undefined);
+  if (!result) return <Loading />;
   if (result instanceof TalerError) {
-    return <ErrorLoadingMerchant error={result} />
+    return <ErrorLoadingMerchant error={result} />;
   }
   /**
    * This component just render known kyc requirements.
@@ -42,23 +55,31 @@ export default function ListKYC(_p: Props): VNode {
   if (result.type === "fail") {
     switch (result.case) {
       case HttpStatusCode.GatewayTimeout: {
-        return <div />
+        return <div />;
       }
       case HttpStatusCode.BadGateway: {
-        return <ListPage status={result.body} />;
-
+        break;
+        // return (
+        //   <ListPage
+        //     status={result.body}
+        //     onGetInfo={_p.onGetInfo}
+        //     onShowInstructions={() => {
+        //       setShowingInstructions(true)
+        //     }}
+        //   />
+        // );
       }
       case HttpStatusCode.ServiceUnavailable: {
-        return <div />
+        return <div />;
       }
       case HttpStatusCode.Unauthorized: {
-        return <div />
+        return <div />;
       }
       case HttpStatusCode.NotFound: {
         return <div />;
       }
       default: {
-        assertUnreachable(result)
+        assertUnreachable(result);
       }
     }
   }
@@ -67,5 +88,28 @@ export default function ListKYC(_p: Props): VNode {
   if (!status) {
     return <div>no kyc required</div>;
   }
-  return <ListPage status={status} />;
+  return (
+    <Fragment>
+      {showingInstructions !== undefined ? (
+        <Fragment>
+          <ValidBankAccount
+            origin={parsePaytoUri(showingInstructions.fromAccount)!}
+            targets={showingInstructions.toAccounts.map(
+              (d) => parsePaytoUri(d)!,
+            )}
+            onCancel={() => setShowingInstructions(undefined)}
+          />
+        </Fragment>
+      ) : undefined}
+      <ListPage
+        status={status}
+        // onGetInfo={async (exchange, ac) => {
+        //   new URL()
+        // }}
+        onShowInstructions={(toAccounts, fromAccount) => {
+          setShowingInstructions({ toAccounts, fromAccount });
+        }}
+      />
+    </Fragment>
+  );
 }
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-merchant-deposit.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-merchant-deposit.ts
index f67ebe406..73449ecb7 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-merchant-deposit.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-merchant-deposit.ts
@@ -18,8 +18,8 @@
  * Imports.
  */
 import {
+  codecForAccountKycRedirects,
   codecForKycProcessClientInformation,
-  codecForMerchantAccountKycRedirectsResponse,
   codecForQueryInstancesResponse,
   Duration,
   encodeCrock,
@@ -313,7 +313,7 @@ export async function runKycMerchantDepositTest(t: 
GlobalTestState) {
     if (resp.status === 200) {
       kycRespOne = await readSuccessResponseJsonOrThrow(
         resp,
-        codecForMerchantAccountKycRedirectsResponse(),
+        codecForAccountKycRedirects(),
       );
       break;
     }
@@ -347,7 +347,7 @@ export async function runKycMerchantDepositTest(t: 
GlobalTestState) {
     t.assertDeepEqual(resp.status, 200);
     const parsedResp = await readSuccessResponseJsonOrThrow(
       resp,
-      codecForMerchantAccountKycRedirectsResponse(),
+      codecForAccountKycRedirects(),
     );
     logger.info(`kyc resp 2: ${j2s(parsedResp)}`);
     if (parsedResp.kyc_data[0].payto_kycauths == null) {
@@ -381,7 +381,7 @@ export async function runKycMerchantDepositTest(t: 
GlobalTestState) {
     t.assertDeepEqual(resp.status, 200);
     const parsedResp = await readSuccessResponseJsonOrThrow(
       resp,
-      codecForMerchantAccountKycRedirectsResponse(),
+      codecForAccountKycRedirects(),
     );
     logger.info(`kyc resp 3: ${j2s(parsedResp)}`);
     if ((parsedResp.kyc_data[0].limits?.length ?? 0) == 0) {
diff --git a/packages/taler-util/src/http-client/merchant.ts 
b/packages/taler-util/src/http-client/merchant.ts
index 81c8baee6..7f79fabac 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -29,7 +29,7 @@ import {
   TalerMerchantConfigResponse,
   codecForAbortResponse,
   codecForAccountAddResponse,
-  codecForLegacyAccountKycRedirects,
+  codecForAccountKycRedirects,
   codecForAccountsSummaryResponse,
   codecForBankAccountDetail,
   codecForCategoryListResponse,
@@ -278,7 +278,11 @@ export class TalerMerchantInstanceHttpClient {
       case HttpStatusCode.GatewayTimeout:
         return opKnownHttpFailure(resp.status, resp);
       case HttpStatusCode.UnavailableForLegalReasons:
-        return opKnownAlternativeFailure(resp, resp.status, 
codecForPaymentDeniedLegallyResponse())
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForPaymentDeniedLegallyResponse(),
+        );
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
@@ -435,7 +439,11 @@ export class TalerMerchantInstanceHttpClient {
       case HttpStatusCode.NotFound:
         return opKnownHttpFailure(resp.status, resp);
       case HttpStatusCode.UnavailableForLegalReasons:
-        return opKnownAlternativeFailure(resp, resp.status, 
codecForPaymentDeniedLegallyResponse())
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForPaymentDeniedLegallyResponse(),
+        );
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
@@ -609,8 +617,10 @@ export class TalerMerchantInstanceHttpClient {
     });
 
     switch (resp.status) {
+      case HttpStatusCode.Ok:
+        return opSuccessFromHttp(resp, codecForAccountKycRedirects());
       case HttpStatusCode.Accepted:
-        return opSuccessFromHttp(resp, codecForLegacyAccountKycRedirects());
+        return opSuccessFromHttp(resp, codecForAccountKycRedirects());
       case HttpStatusCode.NoContent:
         return opEmptySuccess(resp);
       case HttpStatusCode.Unauthorized: // FIXME: missing in docs
@@ -621,7 +631,7 @@ export class TalerMerchantInstanceHttpClient {
         return opKnownAlternativeFailure(
           resp,
           resp.status,
-          codecForLegacyAccountKycRedirects(),
+          codecForAccountKycRedirects(),
         );
       case HttpStatusCode.ServiceUnavailable:
         return opKnownHttpFailure(resp.status, resp);
@@ -1240,7 +1250,11 @@ export class TalerMerchantInstanceHttpClient {
       case HttpStatusCode.Unauthorized: // FIXME: missing in docs
         return opKnownHttpFailure(resp.status, resp);
       case HttpStatusCode.UnavailableForLegalReasons:
-        return opKnownAlternativeFailure(resp, resp.status, 
codecForPaymentDeniedLegallyResponse())
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForPaymentDeniedLegallyResponse(),
+        );
       case HttpStatusCode.Conflict:
         return opKnownHttpFailure(resp.status, resp);
       case HttpStatusCode.Gone:
@@ -1479,7 +1493,11 @@ export class TalerMerchantInstanceHttpClient {
       case HttpStatusCode.Conflict:
         return opKnownHttpFailure(resp.status, resp);
       case HttpStatusCode.UnavailableForLegalReasons:
-        return opKnownAlternativeFailure(resp, resp.status, 
codecForPaymentDeniedLegallyResponse())
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForPaymentDeniedLegallyResponse(),
+        );
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
@@ -2575,7 +2593,7 @@ export class TalerMerchantManagementHttpClient extends 
TalerMerchantInstanceHttp
     });
     switch (resp.status) {
       case HttpStatusCode.Accepted:
-        return opSuccessFromHttp(resp, codecForLegacyAccountKycRedirects());
+        return opSuccessFromHttp(resp, codecForAccountKycRedirects());
       case HttpStatusCode.NoContent:
         return opEmptySuccess(resp);
       case HttpStatusCode.NotFound:
@@ -2593,3 +2611,29 @@ export class TalerMerchantManagementHttpClient extends 
TalerMerchantInstanceHttp
     }
   }
 }
+
+// 2024-09-23T01:23:14.421Z http.ts INFO malformed error response (status 
200): {
+//   "kyc_data": [
+//     {
+//       "payto_uri": 
"payto://iban/DE1327812254798?receiver-name=the%20name%20of%20merchant",
+//       "exchange_url": "http://exchange.taler.test:1180/";,
+//       "no_keys": false,
+//       "auth_conflict": false,
+//       "exchange_http_status": 204,
+//       "limits": [],
+//       "payto_kycauths": [
+//         
"payto://iban/DE9714548806481?receiver-name=Exchanger+Normal&subject=54DR9R0CEWA1A7FK3QWABJ1PRBCD2X6S418Y5DE0P9Q1ASKTX770"
+//       ]
+//     },
+//     {
+//       "payto_uri": 
"payto://iban/DE1327812254798?receiver-name=the%20name%20of%20merchant",
+//       "exchange_url": "https://exchange.demo.taler.net/";,
+//       "no_keys": false,
+//       "auth_conflict": false,
+//       "exchange_http_status": 400,
+//       "exchange_code": 26,
+//       "access_token": 
"0000000000000000000000000000000000000000000000000000",
+//       "limits": []
+//     }
+//   ]
+// }
diff --git a/packages/taler-util/src/types-taler-merchant.ts 
b/packages/taler-util/src/types-taler-merchant.ts
index 26bd45151..a737b7994 100644
--- a/packages/taler-util/src/types-taler-merchant.ts
+++ b/packages/taler-util/src/types-taler-merchant.ts
@@ -69,6 +69,7 @@ import {
   RsaSignature,
   Timestamp,
   WireTransferIdentifierRawP,
+  codecForAccessToken,
   codecForCurrencySpecificiation,
   codecForInternationalizedString,
   codecForURLString,
@@ -1312,7 +1313,6 @@ export interface QueryInstancesResponse {
     method: "external" | "token";
   };
 }
-
 export interface MerchantAccountKycRedirectsResponse {
   // Array of KYC status information for
   // the exchanges and bank accounts selected
@@ -1350,60 +1350,7 @@ export interface MerchantAccountKycRedirect {
 
   // Access token needed to open the KYC SPA and/or
   // access the /kyc-info/ endpoint.
-  access_token?: string;
-
-  // Array with limitations that currently apply to this
-  // account and that may be increased or lifted if the
-  // KYC check is passed.
-  // Note that additional limits *may* exist and not be
-  // communicated to the client. If such limits are
-  // reached, this *may* be indicated by the account
-  // going into aml_review state. However, it is
-  // also possible that the exchange may legally have
-  // to deny operations without being allowed to provide
-  // any justification.
-  // The limits should be used by the client to
-  // possibly structure their operations (e.g. withdraw
-  // what is possible below the limit, ask the user to
-  // pass KYC checks or withdraw the rest after the time
-  // limit is passed, warn the user to not withdraw too
-  // much or even prevent the user from generating a
-  // request that would cause it to exceed hard limits).
-  limits?: AccountLimit[];
-
-  // Array of wire transfer instructions (including
-  // optional amount and subject) for a KYC auth wire
-  // transfer. Set only if this is required
-  // to get the given exchange working.
-  // Array because the exchange may have multiple
-  // bank accounts, in which case any of these
-  // accounts will do.
-  // Optional. Since protocol **v17**.
-  payto_kycauths?: string[];
-}
-
-/**
- * @deprecated
- */
-export interface LegacyAccountKycRedirects {
-  // Array of pending KYCs.
-  pending_kycs: LegacyMerchantAccountKycRedirect[];
-
-  // Array of exchanges with no reply.
-  timeout_kycs: ExchangeKycTimeout[];
-}
-
-/**
- * @deprecated
- */
-export interface LegacyMerchantAccountKycRedirect {
-  // URL that the user should open in a browser to
-  // proceed with the KYC process (as returned
-  // by the exchange's /kyc-check/ endpoint).
-  // Optional, missing if the account is blocked
-  // due to the need for a KYC auth transfer.
-  // (See payto_kycauth in that case.)
-  kyc_url?: string;
+  access_token?: AccessToken;
 
   // Array with limitations that currently apply to this
   // account and that may be increased or lifted if the
@@ -1424,23 +1371,6 @@ export interface LegacyMerchantAccountKycRedirect {
   // request that would cause it to exceed hard limits).
   limits?: AccountLimit[];
 
-  // Base URL of the exchange this is about.
-  exchange_url: string;
-
-  // Numeric error code indicating errors the exchange
-  // returned, or TALER_EC_INVALID for none.
-  // Optional (as there may not always have
-  // been an error code). Since protocol **v17**.
-  exchange_code?: number;
-
-  // HTTP status code returned by the exchange when we asked for
-  // information about the KYC status.
-  // Since protocol **v17**.
-  exchange_http_status: number;
-
-  // Our bank wire account this is about.
-  payto_uri: PaytoString;
-
   // Array of wire transfer instructions (including
   // optional amount and subject) for a KYC auth wire
   // transfer. Set only if this is required
@@ -3057,52 +2987,24 @@ export const codecForQueryInstancesResponse =
       )
       .build("TalerMerchantApi.QueryInstancesResponse");
 
-export const codecForMerchantAccountKycRedirectsResponse =
+export const codecForAccountKycRedirects =
   (): Codec<MerchantAccountKycRedirectsResponse> =>
     buildCodecForObject<MerchantAccountKycRedirectsResponse>()
       .property("kyc_data", codecForList(codecForMerchantAccountKycRedirect()))
-      .build("MerchantAccountKycRedirectsResponse");
+
+      .build("TalerMerchantApi.MerchantAccountKycRedirectsResponse");
 
 export const codecForMerchantAccountKycRedirect =
   (): Codec<MerchantAccountKycRedirect> =>
     buildCodecForObject<MerchantAccountKycRedirect>()
-      .property("limits", codecOptional(codecForList(codecForAccountLimit())))
+      .property("payto_uri", codecForPaytoString())
       .property("exchange_url", codecForURLString())
-      .property("exchange_code", codecOptional(codecForNumber()))
       .property("exchange_http_status", codecForNumber())
-      .property("payto_uri", codecForPaytoString())
-      .property("payto_kycauths", 
codecOptional(codecForList(codecForString())))
-      .property("access_token", codecOptional(codecForString()))
-      .property("auth_conflict", codecForBoolean())
       .property("no_keys", codecForBoolean())
-      .build("MerchantAccountKycRedirect");
-
-/**
- * @deprecated
- */
-export const codecForLegacyAccountKycRedirects =
-  (): Codec<LegacyAccountKycRedirects> =>
-    buildCodecForObject<LegacyAccountKycRedirects>()
-      .property(
-        "pending_kycs",
-        codecForList(codecForLegacyMerchantAccountKycRedirect()),
-      )
-      .property("timeout_kycs", codecForList(codecForExchangeKycTimeout()))
-
-      .build("TalerMerchantApi.AccountKycRedirects");
-
-/**
- * @deprecated
- */
-export const codecForLegacyMerchantAccountKycRedirect =
-  (): Codec<LegacyMerchantAccountKycRedirect> =>
-    buildCodecForObject<LegacyMerchantAccountKycRedirect>()
-      .property("kyc_url", codecOptional(codecForURLString()))
+      .property("auth_conflict", codecForBoolean())
+      .property("exchange_code", codecOptional(codecForNumber()))
+      .property("access_token", codecOptional(codecForAccessToken()))
       .property("limits", codecOptional(codecForList(codecForAccountLimit())))
-      .property("exchange_url", codecForURLString())
-      .property("exchange_code", codecForNumber())
-      .property("exchange_http_status", codecForNumber())
-      .property("payto_uri", codecForPaytoString())
       .property("payto_kycauths", 
codecOptional(codecForList(codecForString())))
       .build("TalerMerchantApi.MerchantAccountKycRedirect");
 
diff --git 
a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx 
b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
index b207ed5b5..65368fd81 100644
--- 
a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
+++ 
b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
@@ -160,8 +160,8 @@ function IBANAccountInfoTable({
 }) {
   const { i18n } = useTranslationContext();
   const api = useBackendContext();
-  const [showBanks, setShowBanks] = useState(false)
-  const [showQrs, setShowQrs] = useState(false)
+  const [showBanks, setShowBanks] = useState(false);
+  const [showQrs, setShowQrs] = useState(false);
 
   const hook = useAsyncAsHook(async () => {
     const qrs = await api.wallet.call(WalletApiOperation.GetQrCodesForPayto, {
@@ -267,7 +267,7 @@ function IBANAccountInfoTable({
         </tr>
 
         <tr>
-          <td colSpan={2} width="100%" style={{ wordBreak: "break-all" }}>
+          <td colSpan={3} width="100%" style={{ wordBreak: "break-all" }}>
             <i18n.Translate>
               Alternative if your bank already supports PayTo URI, you can use
               this{" "}
@@ -287,34 +287,57 @@ function IBANAccountInfoTable({
           </td>
         </tr>
 
-        {banksSites.length < 1 ? undefined : <Fragment>
-          <div>
-            <a href="#" onClick={(e) => {
-              setShowBanks(true);
-              e.preventDefault();
-            }}>
-              <i18n.Translate>Continue with banking app or 
website</i18n.Translate>
-            </a>
-          </div>
-
-          {showBanks ? <ShowBanksForPaytoPopup banks={banksSites} onClose={{
-            onClick: (async () => setShowBanks(false)) as SafeHandler<void>
-          }} /> : undefined}
-        </Fragment>}
-
-        {qrCodes.length < 1 ? undefined : <Fragment>
-          <div>
-            <a href="#" onClick={(e) => {
-              setShowQrs(true);
-              e.preventDefault();
-            }}>
-              <i18n.Translate>Show QR code</i18n.Translate>
-            </a>
-          </div>
-          {showQrs ? <ShowQRsForPaytoPopup qrs={qrCodes} onClose={{
-            onClick: (async () => setShowQrs(false)) as SafeHandler<void>
-          }} /> : undefined}
-        </Fragment>}
+        {banksSites.length < 1 ? undefined : (
+          <Fragment>
+            <div>
+              <a
+                href="#"
+                onClick={(e) => {
+                  setShowBanks(true);
+                  e.preventDefault();
+                }}
+              >
+                <i18n.Translate>
+                  Continue with banking app or website
+                </i18n.Translate>
+              </a>
+            </div>
+
+            {showBanks ? (
+              <ShowBanksForPaytoPopup
+                banks={banksSites}
+                onClose={{
+                  onClick: (async () =>
+                    setShowBanks(false)) as SafeHandler<void>,
+                }}
+              />
+            ) : undefined}
+          </Fragment>
+        )}
+
+        {qrCodes.length < 1 ? undefined : (
+          <Fragment>
+            <div>
+              <a
+                href="#"
+                onClick={(e) => {
+                  setShowQrs(true);
+                  e.preventDefault();
+                }}
+              >
+                <i18n.Translate>Show QR code</i18n.Translate>
+              </a>
+            </div>
+            {showQrs ? (
+              <ShowQRsForPaytoPopup
+                qrs={qrCodes}
+                onClose={{
+                  onClick: (async () => setShowQrs(false)) as 
SafeHandler<void>,
+                }}
+              />
+            ) : undefined}
+          </Fragment>
+        )}
       </tbody>
     </table>
   );

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