taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 9ce574ae31377730d6edbd5b299cc1d0e85b3534
parent 600fe1a743730349724980baaca6cffc3ca742ec
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Tue, 30 Jun 2026 13:59:15 -0300

fix #11481

Diffstat:
Mpackages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx | 202++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mpackages/taler-wallet-webextension/src/wallet/Transaction.tsx | 53+++++------------------------------------------------
2 files changed, 181 insertions(+), 74 deletions(-)

diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx @@ -20,6 +20,7 @@ import { AmountString, assertUnreachable, encodeCrock, + KycAuthTransferInfo, Paytos, PaytoType, QrCodeSpec, @@ -83,9 +84,7 @@ function optionOrder(a: TransferOption, b: TransferOption) { type OptionWithAccount = TransferOption & { account: WithdrawalExchangeAccountDetails; }; -export function BankDetailsByPaytoType({ - subject, - amount, +export function BankDetailsForWithdrawal({ accounts: unsortedAccounts, }: BankDetailsProps): VNode { const { i18n } = useTranslationContext(); @@ -97,26 +96,22 @@ export function BankDetailsByPaytoType({ const accounts = unsortedAccounts.sort(accountOrder); const options = accounts.flatMap((account) => - account.transferOptions.sort(optionOrder).map( - (op): OptionWithAccount => ({ - ...op, - account, - }), - ), - ); + account.transferOptions.sort(optionOrder)) const selectedOption = options[index]; - const altCurrency = selectedOption.account.currencySpecification?.name; + // const altCurrency = selectedOption.account.currencySpecification?.name; switch (selectedOption.type) { case "ch-qr-bill": case "payto": { const payto = Result.unpack(Paytos.fromString(selectedOption.paytoUri)); + const amount = Amounts.parseOrThrow(payto.params["amount"]) + const subject = payto.params["subject"] // make sure the payto has the right params - payto.params["amount"] = altCurrency - ? selectedOption.account.transferAmount! - : Amounts.stringify(amount); - payto.params["message"] = subject; + // payto.params["amount"] = altCurrency + // ? selectedOption.account.transferAmount! + // : Amounts.stringify(amount); + // payto.params["message"] = subject; if (payto.targetType === PaytoType.Bitcoin) { const min = segwitMinAmount(amount.currency); @@ -131,7 +126,6 @@ export function BankDetailsByPaytoType({ accounts={options} updateIndex={setIndex} currentIndex={index} - defaultCurrency={amount.currency} > <p> <i18n.Translate> @@ -185,7 +179,6 @@ export function BankDetailsByPaytoType({ accounts={options} updateIndex={setIndex} currentIndex={index} - defaultCurrency={amount.currency} > <p> <i18n.Translate> @@ -221,7 +214,6 @@ export function BankDetailsByPaytoType({ accounts={options} updateIndex={setIndex} currentIndex={index} - defaultCurrency={amount.currency} > <IBANAccountInfoTable payto={payto} @@ -243,7 +235,6 @@ export function BankDetailsByPaytoType({ accounts={options} updateIndex={setIndex} currentIndex={index} - defaultCurrency={amount.currency} > <i18n.Translate> The selected option is not currently supported. URI:{" "} @@ -257,6 +248,170 @@ export function BankDetailsByPaytoType({ } } +export function BankDetailsForKycAuth({ + info +}: { info: KycAuthTransferInfo }): VNode { + const { i18n } = useTranslationContext(); + const [index, setIndex] = useState(0); + + const { transferOptions: unsortedOptions } = info + + if (!unsortedOptions.length) { + return <div>the exchange account list is empty</div>; + } + + const options = unsortedOptions.sort(optionOrder) + + const selectedOption = options[index]; + + switch (selectedOption.type) { + case "ch-qr-bill": + case "payto": { + const payto = Result.unpack(Paytos.fromString(selectedOption.paytoUri)); + const amount = Amounts.parseOrThrow(payto.params["amount"]) + const subject = payto.params["subject"] + // make sure the payto has the right params + // payto.params["amount"] = altCurrency + // ? selectedOption.account.transferAmount! + // : Amounts.stringify(amount); + // payto.params["message"] = subject; + + // if (payto.targetType === PaytoType.Bitcoin) { + // const min = segwitMinAmount(amount.currency); + // const addrs = payto.segwitAddrs.map( + // (a) => `${a} ${Amounts.stringifyValue(min)}`, + // ); + // addrs.unshift(`${payto.address} ${Amounts.stringifyValue(amount)}`); + // const copyContent = addrs.join("\n"); + // return ( + // <Frame + // title={i18n.str`Bitcoin transfer details`} + // accounts={options} + // updateIndex={setIndex} + // currentIndex={index} + // defaultCurrency={amount.currency} + // > + // <p> + // <i18n.Translate> + // The exchange need a transaction with 3 output, one output is the + // exchange account and the other two are segwit fake address for + // metadata with an minimum amount. + // </i18n.Translate> + // </p> + + // <p> + // <i18n.Translate> + // In bitcoincore wallet use &apos;Add Recipient&apos; button to + // add two additional recipient and copy addresses and amounts + // </i18n.Translate> + // </p> + // <table> + // <tr> + // <td> + // <div> + // {payto.address} <Amount value={amount} hideCurrency /> BTC + // </div> + // {payto.segwitAddrs.map((addr, i) => ( + // <div key={i}> + // {addr} <Amount value={min} hideCurrency /> BTC + // </div> + // ))} + // </td> + // <td></td> + // <td> + // <CopyButton getContent={() => copyContent} /> + // </td> + // </tr> + // </table> + // <p> + // <i18n.Translate> + // Make sure the amount show{" "} + // {Amounts.stringifyValue(Amounts.sum([amount, min, min]).amount)}{" "} + // BTC, else you have to change the base unit to BTC + // </i18n.Translate> + // </p> + // </Frame> + // ); + // } + + // if (payto.targetType === PaytoType.Ethereum) { + // const min = segwitMinAmount(amount.currency); + // const copyContent = `${payto.address} ${Amounts.stringifyValue(amount)}`; + // return ( + // <Frame + // title={i18n.str`Ethereum transfer details`} + // accounts={options} + // updateIndex={setIndex} + // currentIndex={index} + // defaultCurrency={amount.currency} + // > + // <p> + // <i18n.Translate> + // You need to wire to the service provider account. + // </i18n.Translate> + // </p> + + // <table> + // <tr> + // <td> + // <div> + // {payto.address} <Amount value={amount} hideCurrency /> ETH + // </div> + // </td> + // <td></td> + // <td> + // <CopyButton getContent={() => copyContent} /> + // </td> + // </tr> + // </table> + // <p> + // <i18n.Translate> + // Make sure the amount show {Amounts.stringifyValue(amount)} ETH + // </i18n.Translate> + // </p> + // </Frame> + // ); + // } + + return ( + <Frame + title={i18n.str`Bank transfer details`} + accounts={options} + updateIndex={setIndex} + currentIndex={index} + > + <IBANAccountInfoTable + payto={payto} + qrCodes={selectedOption.qrCodes} + refCode={ + selectedOption.type === "ch-qr-bill" + ? selectedOption.qrReferenceNumber + : undefined + } + subject={subject} + /> + </Frame> + ); + } + case "uri": { + return ( + <Frame + title={i18n.str`URI details`} + accounts={options} + updateIndex={setIndex} + currentIndex={index} + > + <i18n.Translate> + The selected option is not currently supported. URI:{" "} + {selectedOption.uri} + </i18n.Translate> + </Frame> + ); + } + default: + assertUnreachable(selectedOption); + } +} export function IBANAccountInfoTable({ payto, qrCodes, @@ -321,7 +476,6 @@ export function IBANAccountInfoTable({ ); case "spc": return <QR_SwissBank text={q.qrContent} />; - default: assertUnreachable(q.type); } @@ -621,7 +775,6 @@ function Frame({ title, children, accounts, - defaultCurrency, currentIndex, updateIndex, }: { @@ -629,8 +782,7 @@ function Frame({ children: ComponentChildren; currentIndex: number; updateIndex: (idx: number) => void; - defaultCurrency: string; - accounts: OptionWithAccount[]; + accounts: TransferOption[]; }): VNode { const { i18n } = useTranslationContext(); return ( @@ -656,8 +808,6 @@ function Frame({ {accounts.length > 1 ? ( <Fragment> {accounts.map((ac, acIdx) => { - // const accountLabel = - // ac.account.bankLabel ?? i18n.str`Option #${acIdx + 1}`; const desc = ac.type === "ch-qr-bill" ? i18n.str`Swiss Bill` : i18n.str`Wire transfer` return ( <Button @@ -667,7 +817,7 @@ function Frame({ updateIndex(acIdx); }} > - {ac.account.currencySpecification?.name ?? defaultCurrency} - {desc} + {acIdx+1}) {desc} </Button> ); })} diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -26,7 +26,6 @@ import { NotificationType, OrderShortInfo, parsePaytoUri, - Paytos, PaytoUri, Result, ScopeInfo, @@ -44,7 +43,7 @@ import { TransactionType, TransactionWithdrawal, TranslatedString, - WithdrawalType, + WithdrawalType } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { QR_Taler, useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -52,10 +51,10 @@ import { isPast } from "date-fns"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { Amount } from "../components/Amount.js"; -import { BankDetailsByPaytoType, IBANAccountInfoTable } from "../components/BankDetailsByPaytoType.js"; +import { BankDetailsForKycAuth, BankDetailsForWithdrawal } from "../components/BankDetailsByPaytoType.js"; import { AlertView, ErrorAlertView } from "../components/CurrentAlerts.js"; import { Loading } from "../components/Loading.js"; -import { Kind, Part, PartPayto } from "../components/Part.js"; +import { Kind, Part } from "../components/Part.js"; import { ShowFullContractTermPopup } from "../components/ShowFullContractTermPopup.js"; import { CenteredDialog, @@ -534,7 +533,7 @@ export function TransactionView({ </span> )} </InfoBox> - <BankDetailsByPaytoType + <BankDetailsForWithdrawal amount={raw} accounts={ transaction.withdrawalDetails.exchangeCreditAccountDetails ?? [] @@ -771,50 +770,8 @@ export function TransactionView({ > {!payto ? transaction.targetPaytoUri : <NicePayto payto={payto} />} </Header> - {/* {payto && <PartPayto payto={payto} kind="neutral" />} */} - {/* <BankDetailsByPaytoType - amount={raw} - accounts={ - transaction.kycAuthTransferInfo.exchangeCreditAccountDetails ?? [] - } - subject={transaction.kycAuthTransferInfo.accountPub} - /> */} - {/* <pre> - {JSON.stringify({ info }, undefined, 2)} - </pre> */} - {!info ? undefined : - <section - style={{ - textAlign: "left", - border: "solid 1px black", - padding: 8, - borderRadius: 4, - }} - > - <div - style={{ - display: "flex", - width: "100%", - justifyContent: "space-between", - }} - > - <p style={{ marginTop: 0 }}><i18n.Translate>Bank transfer details</i18n.Translate></p> - <div></div> - </div> - { - info.transferOptions.map(d => { - switch (d.type) { - case "payto": - return <IBANAccountInfoTable payto={Result.unpack(Paytos.fromString(d.paytoUri))} qrCodes={d.qrCodes} subject={info.accountPub} /> - case "uri": - case "ch-qr-bill": - return <i18n.Translate>Transfer option type "{d.type}"" is not supported by this wallet</i18n.Translate> - } - }) - - } - </section> + <BankDetailsForKycAuth info={info}/> } <Part title={i18n.str`Details`}