taler-typescript-core

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

commit 6c60ee2c41a34dec46d3cc91f401f04822c63c13
parent 8b0453c244374b6af2e2039a89650cd066e6394e
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Thu, 27 Nov 2025 13:04:01 -0300

fix incoming api

Diffstat:
Mpackages/merchant-backoffice-ui/src/hooks/transfer.ts | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/ListPage.tsx | 39+++++++++++++++++++++++++--------------
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/Table.tsx | 292++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx | 12++++++------
4 files changed, 197 insertions(+), 150 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts b/packages/merchant-backoffice-ui/src/hooks/transfer.ts @@ -88,10 +88,10 @@ export function useInstanceIncomingTransfers( if (data.type !== "ok") return data; return buildPaginatedResult( - data.body.transfers, + data.body.incoming, args?.position, updatePosition, - (d) => String(d.transfer_serial_id), + (d) => String(d.wtid), PAGINATED_LIST_REQUEST, ); } 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 @@ -24,12 +24,13 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { FormProvider } from "../../../../components/form/FormProvider.js"; import { InputSelector } from "../../../../components/form/InputSelector.js"; -import { CardTable } from "./Table.js"; +import { CardTableIncoming, CardTableVerified } from "./Table.js"; const TALER_SCREEN_ID = 71; export interface Props { transfers: TalerMerchantApi.TransferDetails[]; + incomings: TalerMerchantApi.IncomingTransferDetails[]; onLoadMoreBefore?: () => void; onLoadMoreAfter?: () => void; // onShowAll: () => void; @@ -49,6 +50,7 @@ export function ListPage({ payTo, onChangePayTo, transfers, + incomings, // onCreate, // onDelete, accounts, @@ -78,9 +80,9 @@ export function ListPage({ label={i18n.str`Bank account`} values={accounts} fromStr={(d) => { - const idx = accounts.indexOf(d) + const idx = accounts.indexOf(d); if (idx === -1) return undefined; - return d + return d; }} placeholder={i18n.str`All accounts`} tooltip={i18n.str`Filter by account address`} @@ -113,17 +115,26 @@ export function ListPage({ </li> </ul> </div> - <CardTable - transfers={transfers.map((o) => ({ - ...o, - id: String(o.transfer_serial_id), - }))} - accounts={accounts} - // onCreate={onCreate} - // onDelete={onDelete} - onLoadMoreBefore={onLoadMoreBefore} - onLoadMoreAfter={onLoadMoreAfter} - /> + + {isNonVerifiedTransfers ? ( + <CardTableIncoming + transfers={incomings.map((o) => ({ + ...o, + id: String(o.wtid), + }))} + onLoadMoreBefore={onLoadMoreBefore} + onLoadMoreAfter={onLoadMoreAfter} + /> + ) : ( + <CardTableVerified + transfers={transfers.map((o) => ({ + ...o, + id: String(o.wtid), + }))} + onLoadMoreBefore={onLoadMoreBefore} + onLoadMoreAfter={onLoadMoreAfter} + /> + )} </section> ); } 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 @@ -23,37 +23,27 @@ import { TalerMerchantApi } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { h, VNode } from "preact"; -import { StateUpdater, useState } from "preact/hooks"; +import { WithId } from "../../../../declaration.js"; import { datetimeFormatForSettings, usePreference, } from "../../../../hooks/preference.js"; -import { WithId } from "../../../../declaration.js"; const TALER_SCREEN_ID = 72; -type Entity = TalerMerchantApi.TransferDetails & WithId; - -interface Props { - transfers: Entity[]; - // onDelete: (id: Entity) => void; - // onCreate: () => void; - accounts: string[]; +interface TablePropsIncoming { + transfers: (TalerMerchantApi.IncomingTransferDetails & WithId)[]; onLoadMoreBefore?: () => void; onLoadMoreAfter?: () => void; } -export function CardTable({ +export function CardTableIncoming({ transfers, - // onCreate, - // onDelete, onLoadMoreAfter, onLoadMoreBefore, -}: Props): VNode { - const [rowSelection, rowSelectionHandler] = useState<string[]>([]); - +}: TablePropsIncoming): VNode { const { i18n } = useTranslationContext(); - + const [settings] = usePreference(); return ( <div class="card has-table"> <header class="card-header"> @@ -61,38 +51,79 @@ export function CardTable({ <span class="icon"> <i class="mdi mdi-arrow-left-right" /> </span> - <i18n.Translate>Wire transfers</i18n.Translate> + <i18n.Translate>Incoming wire transfers</i18n.Translate> </p> - {/* <div class="card-header-icon" aria-label="more options"> - <span - class="has-tooltip-left" - data-tooltip={i18n.str`Add new transfer`} - > - <button - type="button" - class="button is-info" - onClick={onCreate} - accessKey="+" - > - <span class="icon is-small"> - <i class="mdi mdi-plus mdi-36px" /> - </span> - </button> - </span> - </div> */} </header> <div class="card-content"> <div class="b-table has-pagination"> <div class="table-wrapper has-mobile-cards"> {transfers.length > 0 ? ( - <Table - instances={transfers} - // onDelete={onDelete} - rowSelection={rowSelection} - rowSelectionHandler={rowSelectionHandler} - onLoadMoreAfter={onLoadMoreAfter} - onLoadMoreBefore={onLoadMoreBefore} - /> + <div class="table-container"> + {onLoadMoreBefore && ( + <button + type="button" + class="button is-fullwidth" + data-tooltip={i18n.str`Load more wire transfers preceding the first one`} + onClick={onLoadMoreBefore} + > + <i18n.Translate>Load first page</i18n.Translate> + </button> + )} + <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> + <thead> + <tr> + <th> + <i18n.Translate>ID</i18n.Translate> + </th> + <th> + <i18n.Translate>Expected credit</i18n.Translate> + </th> + <th> + <i18n.Translate>Confirmed</i18n.Translate> + </th> + <th> + <i18n.Translate>Validated</i18n.Translate> + </th> + <th> + <i18n.Translate>Executed on</i18n.Translate> + </th> + {/* <th /> */} + </tr> + </thead> + <tbody> + {transfers.map((i) => { + return ( + <tr key={i.id}> + <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> + <td>{i.validated ? i18n.str`yes` : i18n.str`no`}</td> + <td> + {i.execution_time + ? i.execution_time.t_s == "never" + ? i18n.str`never` + : format( + i.execution_time.t_s * 1000, + datetimeFormatForSettings(settings), + ) + : i18n.str`unknown`} + </td> + </tr> + ); + })} + </tbody> + </table> + {onLoadMoreAfter && ( + <button + type="button" + class="button is-fullwidth" + data-tooltip={i18n.str`Load more transfers after the last one`} + onClick={onLoadMoreAfter} + > + <i18n.Translate>Load next page</i18n.Translate> + </button> + )} + </div> ) : ( <EmptyTable /> )} @@ -102,101 +133,106 @@ export function CardTable({ </div> ); } -interface TableProps { - rowSelection: string[]; - instances: Entity[]; - // onDelete: (id: Entity) => void; - rowSelectionHandler: StateUpdater<string[]>; + +interface TablePropsVerified { + transfers: (TalerMerchantApi.TransferDetails & WithId)[]; onLoadMoreBefore?: () => void; onLoadMoreAfter?: () => void; } -function Table({ - instances, +export function CardTableVerified({ + transfers, onLoadMoreAfter, - // onDelete, onLoadMoreBefore, -}: TableProps): VNode { +}: TablePropsVerified): VNode { const { i18n } = useTranslationContext(); const [settings] = usePreference(); return ( - <div class="table-container"> - {onLoadMoreBefore && ( - <button - type="button" - class="button is-fullwidth" - data-tooltip={i18n.str`Load more wire transfers preceding the first one`} - onClick={onLoadMoreBefore} - > - <i18n.Translate>Load first page</i18n.Translate> - </button> - )} - <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> - <thead> - <tr> - <th> - <i18n.Translate>ID</i18n.Translate> - </th> - <th> - <i18n.Translate>Credit</i18n.Translate> - </th> - <th> - <i18n.Translate>Confirmed</i18n.Translate> - </th> - <th> - <i18n.Translate>Verified</i18n.Translate> - </th> - <th> - <i18n.Translate>Executed on</i18n.Translate> - </th> - {/* <th /> */} - </tr> - </thead> - <tbody> - {instances.map((i) => { - return ( - <tr key={i.id}> - <td title={i.wtid}>{i.wtid.substring(0, 16)}...</td> - <td>{i.credit_amount}</td> - <td>{i.confirmed ? i18n.str`yes` : i18n.str`no`}</td> - <td>{i.verified ? i18n.str`yes` : i18n.str`no`}</td> - <td> - {i.execution_time - ? i.execution_time.t_s == "never" - ? i18n.str`never` - : format( - i.execution_time.t_s * 1000, - datetimeFormatForSettings(settings), - ) - : i18n.str`unknown`} - </td> - {/* <td> - {i.verified !== true ? ( - <button - type="button" - class="button is-danger is-small has-tooltip-left" - data-tooltip={i18n.str`Delete selected transfer from the database`} - onClick={() => onDelete(i)} - > - <i18n.Translate>Delete</i18n.Translate> - </button> - ) : undefined} - </td> */} - </tr> - ); - })} - </tbody> - </table> - {onLoadMoreAfter && ( - <button - type="button" - class="button is-fullwidth" - data-tooltip={i18n.str`Load more transfers after the last one`} - onClick={onLoadMoreAfter} - > - <i18n.Translate>Load next page</i18n.Translate> - </button> - )} + <div class="card has-table"> + <header class="card-header"> + <p class="card-header-title"> + <span class="icon"> + <i class="mdi mdi-arrow-left-right" /> + </span> + <i18n.Translate>Verified wire transfers</i18n.Translate> + </p> + </header> + <div class="card-content"> + <div class="b-table has-pagination"> + <div class="table-wrapper has-mobile-cards"> + {transfers.length > 0 ? ( + <div class="table-container"> + {onLoadMoreBefore && ( + <button + type="button" + class="button is-fullwidth" + data-tooltip={i18n.str`Load more wire transfers preceding the first one`} + onClick={onLoadMoreBefore} + > + <i18n.Translate>Load first page</i18n.Translate> + </button> + )} + <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> + <thead> + <tr> + <th> + <i18n.Translate>ID</i18n.Translate> + </th> + <th> + <i18n.Translate>Amount</i18n.Translate> + </th> + <th> + <i18n.Translate>Confirmed</i18n.Translate> + </th> + <th> + <i18n.Translate>Verified</i18n.Translate> + </th> + <th> + <i18n.Translate>Executed on</i18n.Translate> + </th> + {/* <th /> */} + </tr> + </thead> + <tbody> + {transfers.map((i) => { + return ( + <tr key={i.id}> + <td title={i.wtid}>{i.wtid.substring(0, 16)}...</td> + <td>{i.credit_amount}</td> + <td>{i.confirmed ? i18n.str`yes` : i18n.str`no`}</td> + <td>{i.verified ? i18n.str`yes` : i18n.str`no`}</td> + <td> + {i.execution_time + ? i.execution_time.t_s == "never" + ? i18n.str`never` + : format( + i.execution_time.t_s * 1000, + datetimeFormatForSettings(settings), + ) + : i18n.str`unknown`} + </td> + </tr> + ); + })} + </tbody> + </table> + {onLoadMoreAfter && ( + <button + type="button" + class="button is-fullwidth" + data-tooltip={i18n.str`Load more transfers after the last one`} + onClick={onLoadMoreAfter} + > + <i18n.Translate>Load next page</i18n.Translate> + </button> + )} + </div> + ) : ( + <EmptyTable /> + )} + </div> + </div> + </div> </div> ); } 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 @@ -21,14 +21,13 @@ import { HttpStatusCode, + IncomingTransferDetails, TalerError, TransferDetails, assertUnreachable, } from "@gnu-taler/taler-util"; import { - LocalNotificationBannerBulma, - PaginatedResult, - useLocalNotificationBetter, + PaginatedResult } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useEffect, useState } from "preact/hooks"; @@ -67,7 +66,7 @@ export default function ListTransfer({}: Props): VNode { !instance || instance instanceof TalerError || instance.type === "fail" ? [] : instance.body.accounts.map((a) => a.payto_uri); - const [form, setForm] = useState<Form>({ payto_uri: "" }); + const [form, setForm] = useState<Form>({ payto_uri: "", verified: true }); const shoulUseDefaultAccount = accounts.length === 1; useEffect(() => { @@ -80,7 +79,7 @@ export default function ListTransfer({}: Props): VNode { // const isNonVerifiedTransfers = form.verified === false; // const isAllTransfers = form.verified === undefined; - let incoming: PaginatedResult<TransferDetails[]>; + let incoming: PaginatedResult<IncomingTransferDetails[]>; { const result = useInstanceIncomingTransfers( { @@ -147,7 +146,8 @@ export default function ListTransfer({}: Props): VNode { <ListPage accounts={accounts} - transfers={show.body} + transfers={confirmed.body} + incomings={incoming.body} onLoadMoreBefore={show.loadFirst} onLoadMoreAfter={show.loadNext} // onShowAll={() => setFilter(undefined)}