diff options
author | Sebastian <sebasjm@gmail.com> | 2024-04-09 13:21:51 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-04-09 13:21:51 -0300 |
commit | 7f3253333ebd5ac825901f2f74db690588d3ac96 (patch) | |
tree | 62882fb7cd30596a0cfe48857534e71ecd3ffa28 /packages/merchant-backoffice-ui | |
parent | 9d902ed30824f5f1bcf399e7b3a4f7b0c3726213 (diff) |
fix #8716 and pagination
Diffstat (limited to 'packages/merchant-backoffice-ui')
18 files changed, 80 insertions, 78 deletions
diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx b/packages/merchant-backoffice-ui/src/Routing.tsx index 7398aaeec..66f352118 100644 --- a/packages/merchant-backoffice-ui/src/Routing.tsx +++ b/packages/merchant-backoffice-ui/src/Routing.tsx @@ -164,7 +164,7 @@ export function Routing(_p: Props): VNode { const shouldWarnAboutMissingBankAccounts = !state.isAdmin && accounts !== undefined && - accounts.length < 1 && + accounts.accounts.length < 1 && (AbsoluteTime.isNever(preference.hideMissingAccountUntil) || AbsoluteTime.cmp(now, preference.hideMissingAccountUntil) > 1); diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts b/packages/merchant-backoffice-ui/src/hooks/bank.ts index 6555ec085..abfaecf68 100644 --- a/packages/merchant-backoffice-ui/src/hooks/bank.ts +++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts @@ -40,26 +40,27 @@ export function useInstanceBankAccounts() { const { state: session } = useSessionContext(); const { lib: { instance } } = useMerchantApiContext(); - const [offset, setOffset] = useState<string | undefined>(); + // const [offset, setOffset] = useState<string | undefined>(); async function fetcher([token, bid]: [AccessToken, string]) { return await instance.listBankAccounts(token, { - limit: PAGINATED_LIST_REQUEST, - offset: bid, - order: "dec", + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", }); } const { data, error } = useSWR< TalerMerchantManagementResultByMethod<"listBankAccounts">, TalerHttpError - >([session.token, offset, "listBankAccounts"], fetcher); + >([session.token, "offset", "listBankAccounts"], fetcher); if (error) return error; if (data === undefined) return undefined; if (data.type !== "ok") return data; - return buildPaginatedResult(data.body.accounts, offset, setOffset, (d) => d.h_wire) + // return buildPaginatedResult(data.body.accounts, offset, setOffset, (d) => d.h_wire) + return data; } export function revalidateBankAccountDetails() { diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts b/packages/merchant-backoffice-ui/src/hooks/otp.ts index 9820c5f11..8438a46b3 100644 --- a/packages/merchant-backoffice-ui/src/hooks/otp.ts +++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts @@ -16,14 +16,11 @@ import { useMerchantApiContext } from "@gnu-taler/web-util/browser"; -import { useState } from "preact/hooks"; -import { PAGINATED_LIST_REQUEST } from "../utils/constants.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util"; import _useSWR, { SWRHook, mutate } from "swr"; import { useSessionContext } from "../context/session.js"; -import { buildPaginatedResult } from "./webhooks.js"; const useSWR = _useSWR as unknown as SWRHook; export function revalidateInstanceOtpDevices() { @@ -37,26 +34,27 @@ export function useInstanceOtpDevices() { const { state: session } = useSessionContext(); const { lib: { instance } } = useMerchantApiContext(); - const [offset, setOffset] = useState<string | undefined>(); + // const [offset, setOffset] = useState<string | undefined>(); async function fetcher([token, bid]: [AccessToken, string]) { return await instance.listOtpDevices(token, { - limit: PAGINATED_LIST_REQUEST, - offset: bid, - order: "dec", + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", }); } const { data, error } = useSWR< TalerMerchantManagementResultByMethod<"listOtpDevices">, TalerHttpError - >([session.token, offset, "listOtpDevices"], fetcher); + >([session.token, "offset", "listOtpDevices"], fetcher); if (error) return error; if (data === undefined) return undefined; if (data.type !== "ok") return data; - return buildPaginatedResult(data.body.otp_devices, offset, setOffset, (d) => d.otp_device_id) + // return buildPaginatedResult(data.body.otp_devices, offset, setOffset, (d) => d.otp_device_id) + return data; } export function revalidateOtpDeviceDetails() { diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts index c5d0382e2..ff0d8b8a9 100644 --- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts +++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts @@ -39,26 +39,27 @@ export function useInstanceWebhooks() { const { state: session } = useSessionContext(); const { lib: { instance } } = useMerchantApiContext(); - const [offset, setOffset] = useState<string | undefined>(); + // const [offset, setOffset] = useState<string | undefined>(); async function fetcher([token, bid]: [AccessToken, string]) { return await instance.listWebhooks(token, { - limit: PAGINATED_LIST_REQUEST, - offset: bid, - order: "dec", + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", }); } const { data, error } = useSWR< TalerMerchantManagementResultByMethod<"listWebhooks">, TalerHttpError - >([session.token, offset, "listWebhooks"], fetcher); + >([session.token, "offset", "listWebhooks"], fetcher); if (error) return error; if (data === undefined) return undefined; if (data.type !== "ok") return data; - return buildPaginatedResult(data.body.webhooks, offset, setOffset, (d) => d.webhook_id) + // return buildPaginatedResult(data.body.webhooks, offset, setOffset, (d) => d.webhook_id) + return data; } type PaginatedResult<T> = OperationOk<T> & { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx index ccfab3c45..613cb9614 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx @@ -72,7 +72,7 @@ export default function ListOtpDevices({ return ( <Fragment> <NotificationCard notification={notif} /> - {result.body.length < 1 && + {result.body.accounts.length < 1 && <NotificationCard notification={{ type: "WARN", message: i18n.str`You need to associate a bank account to receive revenue.`, @@ -80,7 +80,7 @@ export default function ListOtpDevices({ }} /> } <ListPage - devices={result.body} + devices={result.body.accounts} // onLoadMoreBefore={ // result.isFirstPage ? undefined: result.loadFirst // } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx index cec00fe24..4aed0cc42 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx @@ -160,6 +160,10 @@ function ClaimedPage({ id: string; order: TalerMerchantApi.CheckPaymentClaimedResponse; }) { + const now = new Date(); + const refundable = + order.contract_terms.refund_deadline.t_s !== "never" && + now.getTime() < order.contract_terms.refund_deadline.t_s * 1000; const events: Event[] = []; if (order.contract_terms.timestamp.t_s !== "never") { events.push({ @@ -175,7 +179,7 @@ function ClaimedPage({ type: "deadline", }); } - if (order.contract_terms.refund_deadline.t_s !== "never") { + if (order.contract_terms.refund_deadline.t_s !== "never" && refundable) { events.push({ when: new Date(order.contract_terms.refund_deadline.t_s * 1000), description: "refund deadline", @@ -327,22 +331,13 @@ function PaidPage({ order: TalerMerchantApi.CheckPaymentPaidResponse; onRefund: (id: string) => void; }) { + const now = new Date(); + const refundable = + order.contract_terms.refund_deadline.t_s !== "never" && + now.getTime() < order.contract_terms.refund_deadline.t_s * 1000; + const events: Event[] = []; - // if (order.contract_terms.timestamp.t_s !== "never") { - // events.push({ - // when: new Date(order.contract_terms.timestamp.t_s * 1000), - // description: "order created", - // type: "start", - // }); - // } - // if (order.contract_terms.pay_deadline.t_s !== "never") { - // events.push({ - // when: new Date(order.contract_terms.pay_deadline.t_s * 1000), - // description: "pay deadline", - // type: "deadline", - // }); - // } - if (order.contract_terms.refund_deadline.t_s !== "never") { + if (order.contract_terms.refund_deadline.t_s !== "never" && refundable) { events.push({ when: new Date(order.contract_terms.refund_deadline.t_s * 1000), description: "refund deadline", @@ -430,7 +425,6 @@ function PaidPage({ } } - const now = new Date(); const nextEvent = events.find((e) => { return e.when.getTime() > now.getTime(); }); @@ -442,9 +436,6 @@ function PaidPage({ merchantBaseUrl: backendUrl.href, orderId: order.contract_terms.order_id, }); - const refundable = - order.contract_terms.refund_deadline.t_s !== "never" && - new Date().getTime() < order.contract_terms.refund_deadline.t_s * 1000; const { i18n } = useTranslationContext(); const amount = Amounts.parseOrThrow(order.contract_terms.amount); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx index 12762c3b3..408bc0c0a 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx @@ -48,8 +48,6 @@ export interface ListPageProps { orders: (TalerMerchantApi.OrderHistoryEntry & WithId)[]; onLoadMoreBefore?: () => void; - hasMoreBefore?: boolean; - hasMoreAfter?: boolean; onLoadMoreAfter?: () => void; onSelectOrder: (o: TalerMerchantApi.OrderHistoryEntry & WithId) => void; @@ -58,8 +56,6 @@ export interface ListPageProps { } export function ListPage({ - hasMoreAfter, - hasMoreBefore, onLoadMoreAfter, onLoadMoreBefore, orders, @@ -218,8 +214,6 @@ export function ListPage({ onCopyURL={onCopyURL} onSelect={onSelectOrder} onRefund={onRefundOrder} - hasMoreAfter={hasMoreAfter} - hasMoreBefore={hasMoreBefore} onLoadMoreAfter={onLoadMoreAfter} onLoadMoreBefore={onLoadMoreBefore} /> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx index 919b608c3..a9314d005 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx @@ -50,8 +50,6 @@ interface Props { onCreate: () => void; onSelect: (order: Entity) => void; onLoadMoreBefore?: () => void; - hasMoreBefore?: boolean; - hasMoreAfter?: boolean; onLoadMoreAfter?: () => void; } @@ -63,8 +61,6 @@ export function CardTable({ onSelect, onLoadMoreAfter, onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore, }: Props): VNode { const [rowSelection, rowSelectionHandler] = useState<string[]>([]); @@ -105,8 +101,6 @@ export function CardTable({ rowSelectionHandler={rowSelectionHandler} onLoadMoreAfter={onLoadMoreAfter} onLoadMoreBefore={onLoadMoreBefore} - hasMoreAfter={hasMoreAfter} - hasMoreBefore={hasMoreBefore} /> ) : ( <EmptyTable /> @@ -125,8 +119,6 @@ interface TableProps { onSelect: (id: Entity) => void; rowSelectionHandler: StateUpdater<string[]>; onLoadMoreBefore?: () => void; - hasMoreBefore?: boolean; - hasMoreAfter?: boolean; onLoadMoreAfter?: () => void; } @@ -137,14 +129,12 @@ function Table({ onCopyURL, onLoadMoreAfter, onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore, }: TableProps): VNode { const { i18n } = useTranslationContext(); const [settings] = usePreference(); return ( <div class="table-container"> - {hasMoreBefore && ( + {onLoadMoreBefore && ( <button class="button is-fullwidth" onClick={onLoadMoreBefore}> <i18n.Translate>load first page</i18n.Translate> </button> @@ -218,7 +208,7 @@ function Table({ })} </tbody> </table> - {hasMoreAfter && ( + {onLoadMoreAfter && ( <button class="button is-fullwidth" data-tooltip={i18n.str`load more orders after the last one`} onClick={onLoadMoreAfter}> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx index 217eb998a..af1ffbcc6 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx @@ -120,10 +120,8 @@ export default function OrderList({ onCreate, onSelect }: Props): VNode { <ListPage orders={result.body.map((o) => ({ ...o, id: o.order_id }))} - onLoadMoreBefore={result.loadFirst} - hasMoreBefore={!result.isFirstPage} - onLoadMoreAfter={result.loadNext} - hasMoreAfter={!result.isLastPage} + onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onSelectOrder={(order) => onSelect(order.id)} onRefundOrder={(value) => setOrderToBeRefunded(value)} isAllActive={isAllActive} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx index 324207f59..776823a95 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx @@ -77,9 +77,9 @@ export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode { <NotificationCard notification={notif} /> <ListPage - devices={result.body} - onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} - onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} + devices={result.body.otp_devices} + onLoadMoreBefore={undefined} //result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={undefined} //result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { onSelect(e.otp_device_id); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx index 292974e89..9d5701fa7 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx @@ -45,6 +45,8 @@ interface Props { ) => Promise<void>; onCreate: () => void; selected?: boolean; + onLoadMoreBefore?: () => void; + onLoadMoreAfter?: () => void; } export function CardTable({ @@ -53,6 +55,8 @@ export function CardTable({ onSelect, onUpdate, onDelete, + onLoadMoreAfter, + onLoadMoreBefore }: Props): VNode { const [rowSelection, rowSelectionHandler] = useState<string | undefined>( undefined, @@ -89,6 +93,8 @@ export function CardTable({ onSelect={onSelect} onDelete={onDelete} onUpdate={onUpdate} + onLoadMoreAfter={onLoadMoreAfter} + onLoadMoreBefore={onLoadMoreBefore} rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} /> @@ -111,6 +117,8 @@ interface TableProps { ) => Promise<void>; onDelete: (id: Entity) => void; rowSelectionHandler: StateUpdater<string | undefined>; + onLoadMoreBefore?: () => void; + onLoadMoreAfter?: () => void; } function Table({ @@ -120,11 +128,18 @@ function Table({ onSelect, onUpdate, onDelete, + onLoadMoreAfter, + onLoadMoreBefore }: TableProps): VNode { const { i18n } = useTranslationContext(); const [settings] = usePreference(); return ( <div class="table-container"> + {onLoadMoreBefore && ( + <button class="button is-fullwidth" onClick={onLoadMoreBefore}> + <i18n.Translate>load first page</i18n.Translate> + </button> + )} <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> <thead> <tr> @@ -283,7 +298,7 @@ function Table({ <FastProductUpdateForm product={i} onUpdate={(prod) => - onUpdate(i.id, prod).then((r) => + onUpdate(i.id, prod).then(() => rowSelectionHandler(undefined), ) } @@ -297,6 +312,13 @@ function Table({ })} </tbody> </table> + {onLoadMoreAfter && ( + <button class="button is-fullwidth" + data-tooltip={i18n.str`load more products after the last one`} + onClick={onLoadMoreAfter}> + <i18n.Translate>load next page</i18n.Translate> + </button> + )} </div> ); } @@ -390,7 +412,7 @@ function FastProductWithManagedStockUpdateForm({ }; const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, + (k) => (errors as Record<string,unknown>)[k] !== undefined, ); const { i18n } = useTranslationContext(); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx index dfd633150..db6cf5376 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx @@ -91,6 +91,8 @@ export default function ProductList({ <CardTable instances={result.body} + onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onUpdate={async (id, prod) => { try { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx index 90854d820..139ee7aa3 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx @@ -153,7 +153,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] - : devices.body; + : devices.body.otp_devices; const deviceMap = deviceList.reduce( (prev, cur) => { prev[cur.otp_device_id] = cur.device_description as TranslatedString; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx index 3a32409a0..a4813c8e9 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx @@ -102,7 +102,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] - : devices.body; + : devices.body.otp_devices; const deviceMap = deviceList.reduce( (prev, cur) => { prev[cur.otp_device_id] = cur.device_description as TranslatedString; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx index 4a92c1178..27eab97ed 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx @@ -47,7 +47,7 @@ export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { const accounts = !instance || instance instanceof TalerError || instance.type === "fail" ? [] - : instance.body.map((a) => a.payto_uri); + : instance.body.accounts.map((a) => a.payto_uri); return ( <> 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 index ff2bc6c23..22ad0b8d8 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/ListPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/ListPage.tsx @@ -75,6 +75,11 @@ export function ListPage({ name="payto_uri" label={i18n.str`Account URI`} values={accounts} + fromStr={(d) => { + const idx = accounts.indexOf(d) + if (idx === -1) return undefined; + return d + }} placeholder={i18n.str`Select one account`} tooltip={i18n.str`filter by account address`} /> 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 index 6c451aab8..8b4d1f3cb 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx @@ -48,7 +48,7 @@ export default function ListTransfer({ const instance = useInstanceBankAccounts(); const accounts = !instance || (instance instanceof TalerError) || instance.type === "fail" ? [] - : instance.body.map((a) => a.payto_uri); + : instance.body.accounts.map((a) => a.payto_uri); const [form, setForm] = useState<Form>({ payto_uri: "" }); const shoulUseDefaultAccount = accounts.length === 1 diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx index 6c68bc973..988a54604 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx @@ -76,9 +76,9 @@ export default function ListWebhooks({ onCreate, onSelect }: Props): VNode { <NotificationCard notification={notif} /> <ListPage - webhooks={result.body} - onLoadMoreBefore={result.isFirstPage ? undefined : result.loadFirst} - onLoadMoreAfter={result.isLastPage ? undefined : result.loadNext} + webhooks={result.body.webhooks} + onLoadMoreBefore={undefined} //result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={undefined} //result.isLastPage ? undefined : result.loadNext} onCreate={onCreate} onSelect={(e) => { onSelect(e.webhook_id); |