commit 543ce88c6a2dcfba439b4b3fd09cdf6834b58db3
parent e8cc8a123606a7127af446d147e4f429e131b3f5
Author: Sebastian <sebasjm@gmail.com>
Date: Mon, 7 Apr 2025 13:09:54 -0300
fix #9533
Diffstat:
2 files changed, 188 insertions(+), 248 deletions(-)
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/Table.tsx
@@ -24,14 +24,12 @@ import {
PaytoType,
PaytoUri,
PaytoUriBitcoin,
- PaytoUriIBAN,
- PaytoUriTalerBank,
- PaytoUriUnknown,
- TalerMerchantApi,
+ TalerMerchantApi
} from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { StateUpdater, useState } from "preact/hooks";
+import { paytoDisplayAccountName } from "../update/UpdatePage.js";
type Entity = TalerMerchantApi.BankAccountEntry;
@@ -108,6 +106,7 @@ function Table({ accounts, onDelete, onSelect }: TableProps): VNode {
PaytoType | "unknown",
{ parsed: PaytoUri; acc: Entity }[]
> = { bitcoin: [], "x-taler-bank": [], iban: [], taler: [], unknown: [] };
+
const accountsByType = accounts.reduce((prev, acc) => {
const parsed = parsePaytoUri(acc.payto_uri);
if (!parsed) return prev; //skip
@@ -131,226 +130,167 @@ function Table({ accounts, onDelete, onSelect }: TableProps): VNode {
return (
<Fragment>
- {bitcoinAccounts.length > 0 && (
- <div class="table-container">
- <p class="card-header-title">
- <i18n.Translate>Wire method: Bitcoin</i18n.Translate>
- </p>
- <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
- <thead>
- <tr>
- <th>
- <i18n.Translate>Address</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>SegWit 1</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>SegWit 2</i18n.Translate>
- </th>
- <th />
- </tr>
- </thead>
- <tbody>
- {bitcoinAccounts.map(({ parsed, acc }, idx) => {
- const ac = parsed as PaytoUriBitcoin;
- return (
- <tr key={idx}>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.targetPath}
- </td>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.segwitAddrs[0]}
- </td>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.segwitAddrs[1]}
- </td>
- <td class="is-actions-cell right-sticky">
- <div class="buttons is-right">
- <button
- class="button is-danger is-small has-tooltip-left"
- data-tooltip={i18n.str`Delete selected accounts from the database`}
- onClick={() => onDelete(acc)}
- >
- <i18n.Translate>Delete</i18n.Translate>
- </button>
- </div>
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- </div>
- )}
-
- {talerbankAccounts.length > 0 && (
- <div class="table-container">
- <p class="card-header-title">
- <i18n.Translate>Wire method: x-taler-bank</i18n.Translate>
- </p>
- <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
- <thead>
- <tr>
- <th>
- <i18n.Translate>Host</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>Account name</i18n.Translate>
- </th>
- <th />
- </tr>
- </thead>
- <tbody>
- {talerbankAccounts.map(({ parsed, acc }, idx) => {
- const ac = parsed as PaytoUriTalerBank;
- return (
- <tr key={idx}>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.host}
- </td>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.account}
- </td>
- <td class="is-actions-cell right-sticky">
- <div class="buttons is-right">
- <button
- class="button is-danger is-small has-tooltip-left"
- data-tooltip={i18n.str`Delete selected accounts from the database`}
- onClick={() => onDelete(acc)}
- >
- <i18n.Translate>Delete</i18n.Translate>
- </button>
- </div>
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- </div>
- )}
-
- {ibanAccounts.length > 0 && (
- <div class="table-container">
- <p class="card-header-title">
- <i18n.Translate>Wire method: IBAN</i18n.Translate>
- </p>
- <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
- <thead>
- <tr>
- <th>
- <i18n.Translate>Account name</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>IBAN</i18n.Translate>
- </th>
- <th />
- </tr>
- </thead>
- <tbody>
- {ibanAccounts.map(({ parsed, acc }, idx) => {
- const ac = parsed as PaytoUriIBAN;
- return (
- <tr key={idx}>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.params["receiver-name"]}
- </td>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.iban}
- </td>
- <td class="is-actions-cell right-sticky">
- <div class="buttons is-right">
- <button
- class="button is-danger is-small has-tooltip-left"
- data-tooltip={i18n.str`Delete selected accounts from the database`}
- onClick={() => onDelete(acc)}
- >
- <i18n.Translate>Delete</i18n.Translate>
- </button>
- </div>
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- </div>
- )}
-
- {unknownAccounts.length > 0 && (
- <div class="table-container">
- <p class="card-header-title">
- <i18n.Translate>Other accounts</i18n.Translate>
- </p>
- <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
- <thead>
- <tr>
- <th>
- <i18n.Translate>Type</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>Path</i18n.Translate>
- </th>
- <th />
- </tr>
- </thead>
- <tbody>
- {unknownAccounts.map(({ parsed, acc }, idx) => {
- const ac = parsed as PaytoUriUnknown;
- return (
- <tr key={idx}>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.targetType}
- </td>
- <td
- onClick={(): void => onSelect(acc)}
- style={{ cursor: "pointer" }}
- >
- {ac.targetPath}
- </td>
- <td class="is-actions-cell right-sticky">
- <div class="buttons is-right">
- <button
- class="button is-danger is-small has-tooltip-left"
- data-tooltip={i18n.str`Delete selected accounts from the database`}
- onClick={() => onDelete(acc)}
- >
- <i18n.Translate>Delete</i18n.Translate>
- </button>
- </div>
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- </div>
- )}
+ <div class="table-container">
+ <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
+ <thead>
+ <tr>
+ <th>
+ <i18n.Translate>Wire method</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>Account</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>Owner's name</i18n.Translate>
+ </th>
+ <th />
+ </tr>
+ </thead>
+ <tbody>
+ {bitcoinAccounts.map(({ parsed, acc }, idx) => {
+ return (
+ <tr key={idx}>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ Bitcoin
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {paytoDisplayAccountName(acc.payto_uri)}
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {parsed.params["receiver-name"]}
+ </td>
+ <td class="is-actions-cell right-sticky">
+ <div class="buttons is-right">
+ <button
+ class="button is-danger is-small has-tooltip-left"
+ data-tooltip={i18n.str`Delete selected accounts from the database`}
+ onClick={() => onDelete(acc)}
+ >
+ <i18n.Translate>Delete</i18n.Translate>
+ </button>
+ </div>
+ </td>
+ </tr>
+ );
+ })}
+ {talerbankAccounts.map(({ parsed, acc }, idx) => {
+ return (
+ <tr key={idx}>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ x-taler-bank
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {paytoDisplayAccountName(acc.payto_uri)}
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {parsed.params["receiver-name"]}
+ </td>
+ <td class="is-actions-cell right-sticky">
+ <div class="buttons is-right">
+ <button
+ class="button is-danger is-small has-tooltip-left"
+ data-tooltip={i18n.str`Delete selected accounts from the database`}
+ onClick={() => onDelete(acc)}
+ >
+ <i18n.Translate>Delete</i18n.Translate>
+ </button>
+ </div>
+ </td>
+ </tr>
+ );
+ })}
+ {ibanAccounts.map(({ parsed, acc }, idx) => {
+ return (
+ <tr key={idx}>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ IBAN
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {paytoDisplayAccountName(acc.payto_uri)}
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {parsed.params["receiver-name"]}
+ </td>
+ <td class="is-actions-cell right-sticky">
+ <div class="buttons is-right">
+ <button
+ class="button is-danger is-small has-tooltip-left"
+ data-tooltip={i18n.str`Delete selected accounts from the database`}
+ onClick={() => onDelete(acc)}
+ >
+ <i18n.Translate>Delete</i18n.Translate>
+ </button>
+ </div>
+ </td>
+ </tr>
+ );
+ })}
+ {unknownAccounts.map(({ parsed, acc }, idx) => {
+ return (
+ <tr key={idx}>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {parsed.targetType}
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {paytoDisplayAccountName(acc.payto_uri)}
+ </td>
+ <td
+ onClick={(): void => onSelect(acc)}
+ style={{ cursor: "pointer" }}
+ >
+ {parsed.params["receiver-name"]}
+ </td>
+ <td class="is-actions-cell right-sticky">
+ <div class="buttons is-right">
+ <button
+ class="button is-danger is-small has-tooltip-left"
+ data-tooltip={i18n.str`Delete selected accounts from the database`}
+ onClick={() => onDelete(acc)}
+ >
+ <i18n.Translate>Delete</i18n.Translate>
+ </button>
+ </div>
+ </td>
+ </tr>
+ );
+ })}
+ </tbody>
+ </table>
+ </div>
+
</Fragment>
);
}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx
@@ -259,29 +259,6 @@ export function UpdatePage({
}
}
- function stringifyPayto(account: PaytoString): string {
- const p = parsePaytoUri(account);
- if (!p) return "";
- if (!p.isKnown) return account;
- switch (p.targetType) {
- case "iban": {
- return p.iban;
- }
- case "taler": {
- return p.reservePub;
- }
- case "x-taler-bank": {
- return p.account;
- }
- case "bitcoin": {
- return p.address;
- }
- default: {
- assertUnreachable(p);
- }
- }
- }
-
return (
<Fragment>
<section class="section">
@@ -292,7 +269,7 @@ export function UpdatePage({
<div class="level-item">
<span class="is-size-4">
<i18n.Translate>Account:</i18n.Translate>{" "}
- <b>{stringifyPayto(account.payto_uri)}</b>
+ <b>{paytoDisplayAccountName(account.payto_uri)}</b>
</span>
</div>
</div>
@@ -478,3 +455,26 @@ export function safeConvertURL(s?: string): URL | undefined {
return undefined;
}
}
+
+export function paytoDisplayAccountName(account: PaytoString): string {
+ const p = parsePaytoUri(account);
+ if (!p) return "";
+ if (!p.isKnown) return account;
+ switch (p.targetType) {
+ case "iban": {
+ return p.iban;
+ }
+ case "taler": {
+ return p.reservePub;
+ }
+ case "x-taler-bank": {
+ return `${p.account}@${p.host}`;
+ }
+ case "bitcoin": {
+ return p.address;
+ }
+ default: {
+ assertUnreachable(p);
+ }
+ }
+}