taler-typescript-core

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

commit 6c6644051423e179d2d82ef18f6fbef1b7de6ee0
parent 78484b114dba78c4c553e2d18fc95c48bed4e408
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Wed,  3 Dec 2025 13:38:21 -0300

incoming wire transfer details

Diffstat:
Mpackages/merchant-backoffice-ui/src/components/modal/index.tsx | 3+++
Mpackages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx | 7+++++--
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/ListPage.tsx | 11+++--------
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/Table.tsx | 12+++++++++++-
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx | 105++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
5 files changed, 118 insertions(+), 20 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/modal/index.tsx b/packages/merchant-backoffice-ui/src/components/modal/index.tsx @@ -616,10 +616,12 @@ export function Row({ name, value, literal, + lineBreak, }: { name: TranslatedString; value: string | VNode; literal?: boolean; + lineBreak?: boolean; }): VNode { const preRef = useRef<HTMLPreElement>(null); const tdRef = useRef<HTMLTableCellElement>(null); @@ -640,6 +642,7 @@ export function Row({ style={{ whiteSpace: "pre-wrap", wordBreak: "break-word", + lineBreak: lineBreak ? "anywhere" : undefined, padding: 4, }} > diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx @@ -153,7 +153,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { }; const create = safeFunctionHandler( async ( - token: AccessToken, + token: AccessToken | undefined, data: TalerMerchantApi.InstanceConfigurationMessage, challengeIds: string[], ) => { @@ -178,7 +178,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { } return opEmptySuccess(); }, - !session.token || hasErrors ? undefined : [session.token, data, []], + hasErrors ? undefined : [session.token, data, []], ); create.onSuccess = (success, oldtoken, data) => { if (success) { @@ -218,6 +218,9 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { return ( <div> <LocalNotificationBannerBulma notification={notification} /> + <pre> + {JSON.stringify({errors}, undefined,2)} + </pre> <section class="section is-main-section"> <div class="columns"> <div class="column" /> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/ListPage.tsx @@ -33,17 +33,14 @@ export interface Props { incomings: TalerMerchantApi.IncomingTransferDetails[]; onLoadMoreBefore?: () => void; onLoadMoreAfter?: () => void; - // onShowAll: () => void; onShowVerified: () => void; onShowUnverified: () => void; isVerifiedTransfers?: boolean; isNonVerifiedTransfers?: boolean; - // isAllTransfers?: boolean; accounts: string[]; onChangePayTo: (p?: string) => void; payTo?: string; - // onCreate: () => void; - // onDelete: (wid: TalerMerchantApi.TransferDetails) => void; + onSelectedToConfirm: (wid: TalerMerchantApi.IncomingTransferDetails) => void; } export function ListPage({ @@ -51,15 +48,12 @@ export function ListPage({ onChangePayTo, transfers, incomings, - // onCreate, - // onDelete, + onSelectedToConfirm, accounts, onLoadMoreBefore, onLoadMoreAfter, - // isAllTransfers, isNonVerifiedTransfers, isVerifiedTransfers, - // onShowAll, onShowUnverified, onShowVerified, }: Props): VNode { @@ -124,6 +118,7 @@ export function ListPage({ }))} onLoadMoreBefore={onLoadMoreBefore} onLoadMoreAfter={onLoadMoreAfter} + onSelectedToConfirm={onSelectedToConfirm} /> ) : ( <CardTableVerified diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/Table.tsx @@ -35,12 +35,14 @@ interface TablePropsIncoming { transfers: (TalerMerchantApi.IncomingTransferDetails & WithId)[]; onLoadMoreBefore?: () => void; onLoadMoreAfter?: () => void; + onSelectedToConfirm: (d: TalerMerchantApi.IncomingTransferDetails) => void; } export function CardTableIncoming({ transfers, onLoadMoreAfter, onLoadMoreBefore, + onSelectedToConfirm, }: TablePropsIncoming): VNode { const { i18n } = useTranslationContext(); const [settings] = usePreference(); @@ -93,7 +95,15 @@ export function CardTableIncoming({ <tbody> {transfers.map((i) => { return ( - <tr key={i.id}> + <tr + key={i.id} + style={{ + cursor: !i.confirmed ? "pointer" : undefined + }} + onClick={ + !i.confirmed ? () => onSelectedToConfirm(i) : undefined + } + > <td title={i.wtid}>{i.wtid.substring(0, 16)}...</td> <td>{i.expected_credit_amount}</td> <td>{i.confirmed ? i18n.str`yes` : i18n.str`no`}</td> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx @@ -24,10 +24,13 @@ import { IncomingTransferDetails, TalerError, TransferDetails, + TransferInformation, assertUnreachable, } from "@gnu-taler/taler-util"; import { - PaginatedResult + PaginatedResult, + useLocalNotificationBetter, + useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useEffect, useState } from "preact/hooks"; @@ -36,11 +39,19 @@ import { Loading } from "../../../../components/exception/loading.js"; import { useInstanceBankAccounts } from "../../../../hooks/bank.js"; import { useInstanceConfirmedTransfers, - useInstanceIncomingTransfers + useInstanceIncomingTransfers, } from "../../../../hooks/transfer.js"; import { LoginPage } from "../../../login/index.js"; import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { ListPage } from "./ListPage.js"; +import { ConfirmModal, Row } from "../../../../components/modal/index.js"; +import { Amount } from "../../../../components/Amount.js"; +import { format } from "date-fns"; +import { + datetimeFormatForSettings, + usePreference, +} from "../../../../hooks/preference.js"; +import { useSessionContext } from "../../../../context/session.js"; interface Props { // onCreate: () => void; @@ -54,19 +65,21 @@ interface Form { export default function ListTransfer({}: Props): VNode { const setFilter = (s?: boolean) => setForm({ ...form, verified: s }); - // const { i18n } = useTranslationContext(); - // const { state: session, lib } = useSessionContext(); + const { state: session, lib } = useSessionContext(); const [position, setPosition] = useState<string | undefined>(undefined); + const [settings] = usePreference(); - // const [notification, safeFunctionHandler] = useLocalNotificationBetter(); const instance = useInstanceBankAccounts(); const accounts = !instance || instance instanceof TalerError || instance.type === "fail" ? [] : instance.body.accounts.map((a) => a.payto_uri); - const [form, setForm] = useState<Form>({ payto_uri: "", verified: true }); + const [form, setForm] = useState<Form>({ payto_uri: "", verified: false }); + const [selected, setSelected] = useState<IncomingTransferDetails>(); + const { i18n } = useTranslationContext(); + const [notification, safeFunctionHandler] = useLocalNotificationBetter(); const shoulUseDefaultAccount = accounts.length === 1; useEffect(() => { @@ -75,6 +88,34 @@ export default function ListTransfer({}: Props): VNode { } }, [shoulUseDefaultAccount]); + const confirm = safeFunctionHandler( + lib.instance.informWireTransfer.bind(lib.instance), + !session.token || !selected + ? undefined + : [ + session.token, + { + credit_amount: selected.expected_credit_amount!, + exchange_url: selected.exchange_url, + payto_uri: selected.payto_uri, + wtid: selected.wtid, + }, + ], + ); + confirm.onSuccess = () => { + setSelected(undefined) + }; + confirm.onFail = (fail) => { + switch (fail.case) { + case HttpStatusCode.Unauthorized: + return i18n.str`Unauthorized.`; + case HttpStatusCode.NotFound: + return i18n.str`Not found.`; + case HttpStatusCode.Conflict: + return i18n.str`Wire transfer already confirmed.`; + } + }; + // const isVerifiedTransfers = form.verified === true; // const isNonVerifiedTransfers = form.verified === false; // const isAllTransfers = form.verified === undefined; @@ -107,7 +148,7 @@ export default function ListTransfer({}: Props): VNode { } } } - incoming = result + incoming = result; } let confirmed: PaginatedResult<TransferDetails[]>; { @@ -136,18 +177,64 @@ export default function ListTransfer({}: Props): VNode { } } } - confirmed = result + confirmed = result; } const show = form.verified ? confirmed : incoming; return ( <Fragment> {/* <LocalNotificationBannerBulma notification={notification} /> */} - + {!selected ? undefined : ( + <ConfirmModal + label={i18n.str`I have received the wire transfer`} + description={i18n.str`Confirm the wire transfer`} + active + onCancel={() => { + setSelected(undefined); + }} + confirm={confirm} + > + <p style={{ paddingTop: 0 }}> + <i18n.Translate> + The wire transfer has been sent and should be in your bank account + in any time. You can manually confirm the reception usign the + information below. + </i18n.Translate> + </p> + <div class="table-container"> + <table> + <tbody> + <Row + name={i18n.str`Amount`} + value={<Amount value={selected.expected_credit_amount!} />} + /> + {selected.execution_time && + selected.execution_time.t_s !== "never" ? ( + <Row + name={i18n.str`Time`} + value={format( + selected.execution_time.t_s * 1000, + datetimeFormatForSettings(settings), + )} + /> + ) : undefined} + <Row + name={i18n.str`Transfer ID`} + value={selected.wtid} + literal + /> + </tbody> + </table> + </div> + </ConfirmModal> + )} <ListPage accounts={accounts} transfers={confirmed.body} incomings={incoming.body} + onSelectedToConfirm={(d) => { + setSelected(d); + }} onLoadMoreBefore={show.loadFirst} onLoadMoreAfter={show.loadNext} // onShowAll={() => setFilter(undefined)}