summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-04-03 09:52:53 -0300
committerSebastian <sebasjm@gmail.com>2024-04-03 14:56:29 -0300
commit56da180423029a1b53d2be343eed4f073e96dc89 (patch)
treee8fd31dcc4c7bc6866b139de097c8f2c01f93597
parentc53c6b8b3c0a66f3862883ec1314c6d4bf68af32 (diff)
downloadwallet-core-56da180423029a1b53d2be343eed4f073e96dc89.tar.gz
wallet-core-56da180423029a1b53d2be343eed4f073e96dc89.tar.bz2
wallet-core-56da180423029a1b53d2be343eed4f073e96dc89.zip
wip #8655: updating paginated queries
-rw-r--r--packages/bank-ui/src/components/Transactions/state.ts22
-rw-r--r--packages/bank-ui/src/hooks/account.ts77
-rw-r--r--packages/bank-ui/src/hooks/regional.ts29
-rw-r--r--packages/bank-ui/src/pages/PublicHistoriesPage.tsx10
-rw-r--r--packages/bank-ui/src/pages/admin/AccountList.tsx8
-rw-r--r--packages/bank-ui/src/pages/admin/AdminHome.tsx5
-rw-r--r--packages/merchant-backoffice-ui/src/Routing.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/backend.ts373
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/bank.ts247
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/instance.ts60
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/order.ts307
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/otp.ts231
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/product.ts227
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/templates.ts286
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/transfer.ts192
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/webhooks.ts233
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx26
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx2
-rw-r--r--packages/taler-util/src/http-client/merchant.ts34
20 files changed, 537 insertions, 1836 deletions
diff --git a/packages/bank-ui/src/components/Transactions/state.ts b/packages/bank-ui/src/components/Transactions/state.ts
index 4e4552a82..ce6338e57 100644
--- a/packages/bank-ui/src/components/Transactions/state.ts
+++ b/packages/bank-ui/src/components/Transactions/state.ts
@@ -17,7 +17,9 @@
import {
AbsoluteTime,
Amounts,
+ HttpStatusCode,
TalerError,
+ assertUnreachable,
parsePaytoUri,
} from "@gnu-taler/taler-util";
import { useTransactions } from "../../hooks/account.js";
@@ -27,21 +29,27 @@ export function useComponentState({
account,
routeCreateWireTransfer,
}: Props): State {
- const txResult = useTransactions(account);
- if (!txResult) {
+ const result = useTransactions(account);
+ if (!result) {
return {
status: "loading",
error: undefined,
};
}
- if (txResult instanceof TalerError) {
+ if (result instanceof TalerError) {
return {
status: "loading-error",
- error: txResult,
+ error: result,
+ };
+ }
+ if (result.type === "fail") {
+ return {
+ status: "loading",
+ error: undefined,
};
}
- const transactions = txResult.result
+ const transactions = result.body
.map((tx) => {
const negative = tx.direction === "debit";
const cp = parsePaytoUri(
@@ -76,7 +84,7 @@ export function useComponentState({
error: undefined,
routeCreateWireTransfer,
transactions,
- onGoNext: txResult.isLastPage ? undefined : txResult.loadNext,
- onGoStart: txResult.isFirstPage ? undefined : txResult.loadFirst,
+ onGoNext: result.isLastPage ? undefined : result.loadNext,
+ onGoStart: result.isFirstPage ? undefined : result.loadFirst,
};
}
diff --git a/packages/bank-ui/src/hooks/account.ts b/packages/bank-ui/src/hooks/account.ts
index 24309183f..543c49aed 100644
--- a/packages/bank-ui/src/hooks/account.ts
+++ b/packages/bank-ui/src/hooks/account.ts
@@ -16,6 +16,7 @@
import {
AccessToken,
+ OperationOk,
TalerCoreBankResultByMethod,
TalerHttpError,
WithdrawalOperationStatus,
@@ -197,36 +198,44 @@ export function usePublicAccounts(
keepPreviousData: true,
});
- const isLastPage =
- data && data.type === "ok" && data.body.public_accounts.length <= PAGE_SIZE;
- const isFirstPage = !offset;
+ if (error) return error;
+ if (data === undefined) return undefined;
+ // if (data.type !== "ok") return data;
+
+ //TODO: row_id should not be optional
+ return buildPaginatedResult(data.body.public_accounts, offset, setOffset, (d) => d.row_id ?? 0)
+}
+
- const result =
- data && data.type == "ok" ? structuredClone(data.body.public_accounts) : [];
+type PaginatedResult<T> = OperationOk<T> & {
+ isLastPage: boolean;
+ isFirstPage: boolean;
+ loadNext(): void;
+ loadFirst(): void;
+}
+//TODO: consider sending this to web-util
+export function buildPaginatedResult<DataType, OffsetId>(data: DataType[], offset: OffsetId | undefined, setOffset: (o: OffsetId | undefined) => void, getId: (r: DataType) => OffsetId): PaginatedResult<DataType[]> {
+ const isLastPage = data.length <= PAGE_SIZE;
+ const isFirstPage = offset === undefined;
+
+ const result = structuredClone(data);
if (result.length == PAGE_SIZE + 1) {
result.pop();
}
- const pagination = {
- result,
+ return {
+ type: "ok",
+ body: result,
isLastPage,
isFirstPage,
loadNext: () => {
if (!result.length) return;
- setOffset(result[result.length - 1].row_id);
+ const id = getId(result[result.length - 1])
+ setOffset(id);
},
loadFirst: () => {
- setOffset(0);
+ setOffset(undefined);
},
};
-
- // const public_accountslist = data?.type !== "ok" ? [] : data.body.public_accounts;
- if (data) {
- return { ok: true, data: data.body, ...pagination };
- }
- if (error) {
- return error;
- }
- return undefined;
}
export function revalidateTransactions() {
@@ -271,34 +280,10 @@ export function useTransactions(account: string, initial?: number) {
revalidateOnFocus: false,
revalidateOnReconnect: false,
});
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
- const isLastPage =
- data && data.type === "ok" && data.body.transactions.length <= PAGE_SIZE;
- const isFirstPage = !offset;
-
- const result =
- data && data.type == "ok" ? structuredClone(data.body.transactions) : [];
- if (result.length == PAGE_SIZE + 1) {
- result.pop();
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length) return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- },
- };
+ return buildPaginatedResult(data.body.transactions, offset, setOffset, (d) => d.row_id)
- if (data) {
- return { ok: true, data, ...pagination };
- }
- if (error) {
- return error;
- }
- return undefined;
}
diff --git a/packages/bank-ui/src/hooks/regional.ts b/packages/bank-ui/src/hooks/regional.ts
index 274638f74..3e832a944 100644
--- a/packages/bank-ui/src/hooks/regional.ts
+++ b/packages/bank-ui/src/hooks/regional.ts
@@ -34,6 +34,7 @@ import {
import { useState } from "preact/hooks";
import _useSWR, { SWRHook, mutate } from "swr";
import { useBankCoreApiContext } from "@gnu-taler/web-util/browser";
+import { buildPaginatedResult } from "./account.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
const useSWR = _useSWR as unknown as SWRHook;
@@ -249,31 +250,13 @@ export function useBusinessAccounts() {
keepPreviousData: true,
});
- const isLastPage =
- data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE;
- const isFirstPage = !offset;
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
- const result =
- data && data.type == "ok" ? structuredClone(data.body.accounts) : [];
- if (result.length == PAGE_SIZE + 1) {
- result.pop();
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length) return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- },
- };
+ //TODO: row_id should not be optional
+ return buildPaginatedResult(data.body.accounts, offset, setOffset, (d) => d.row_id ?? 0)
- if (data) return { ok: true, data, ...pagination };
- if (error) return error;
- return undefined;
}
type CashoutWithId = TalerCorebankApi.CashoutStatusResponse & { id: number };
diff --git a/packages/bank-ui/src/pages/PublicHistoriesPage.tsx b/packages/bank-ui/src/pages/PublicHistoriesPage.tsx
index 554da0c3f..1810bd5dd 100644
--- a/packages/bank-ui/src/pages/PublicHistoriesPage.tsx
+++ b/packages/bank-ui/src/pages/PublicHistoriesPage.tsx
@@ -31,9 +31,9 @@ export function PublicHistoriesPage(): VNode {
const result = usePublicAccounts(undefined);
const firstAccount =
result &&
- !(result instanceof TalerError) &&
- result.data.public_accounts.length > 0
- ? result.data.public_accounts[0].username
+ !(result instanceof TalerError) &&
+ result.body.length > 0
+ ? result.body[0].username
: undefined;
const [showAccount, setShowAccount] = useState(firstAccount);
@@ -45,13 +45,13 @@ export function PublicHistoriesPage(): VNode {
return <Loading />;
}
- const { data } = result;
+ const { body: accountList } = result;
const txs: Record<string, h.JSX.Element> = {};
const accountsBar = [];
// Ask story of all the public accounts.
- for (const account of data.public_accounts) {
+ for (const account of accountList) {
const isSelected = account.username == showAccount;
accountsBar.push(
<li
diff --git a/packages/bank-ui/src/pages/admin/AccountList.tsx b/packages/bank-ui/src/pages/admin/AccountList.tsx
index c4e529f9f..6402c2bcd 100644
--- a/packages/bank-ui/src/pages/admin/AccountList.tsx
+++ b/packages/bank-ui/src/pages/admin/AccountList.tsx
@@ -51,19 +51,19 @@ export function AccountList({
if (result instanceof TalerError) {
return <ErrorLoadingWithDebug error={result} />;
}
- if (result.data.type === "fail") {
- switch (result.data.case) {
+ if (result.type === "fail") {
+ switch (result.case) {
case HttpStatusCode.Unauthorized:
return <Fragment />;
default:
- assertUnreachable(result.data.case);
+ assertUnreachable(result.case);
}
}
const onGoStart = result.isFirstPage ? undefined : result.loadFirst;
const onGoNext = result.isLastPage ? undefined : result.loadNext;
- const accounts = result.result;
+ const accounts = result.body;
return (
<Fragment>
<div class="px-4 sm:px-6 lg:px-8 mt-8">
diff --git a/packages/bank-ui/src/pages/admin/AdminHome.tsx b/packages/bank-ui/src/pages/admin/AdminHome.tsx
index 94b88dc89..4784fc73a 100644
--- a/packages/bank-ui/src/pages/admin/AdminHome.tsx
+++ b/packages/bank-ui/src/pages/admin/AdminHome.tsx
@@ -26,6 +26,7 @@ import { Attention, useTranslationContext } from "@gnu-taler/web-util/browser";
import {
format,
getDate,
+ getDaysInMonth,
getHours,
getMonth,
getYear,
@@ -127,8 +128,8 @@ export function getTimeframesForDate(
};
case TalerCorebankApi.MonitorTimeframeParam.day:
return {
- current: getDate(sub(time, { days: 1 })),
- previous: getDate(sub(time, { days: 2 })),
+ current: getDaysInMonth(sub(time, { days: 1 })),
+ previous: getDaysInMonth(sub(time, { days: 2 })),
};
case TalerCorebankApi.MonitorTimeframeParam.month:
return {
diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx b/packages/merchant-backoffice-ui/src/Routing.tsx
index 1fccc2637..9e801a233 100644
--- a/packages/merchant-backoffice-ui/src/Routing.tsx
+++ b/packages/merchant-backoffice-ui/src/Routing.tsx
@@ -158,7 +158,7 @@ export function Routing(_p: Props): VNode {
const now = AbsoluteTime.now();
const instance = useInstanceBankAccounts();
- const accounts = !instance.ok ? undefined : instance.data.accounts;
+ const accounts = !instance || instance instanceof TalerError || instance.data.type === "fail" ? undefined : instance.result;
const shouldWarnAboutMissingBankAccounts =
!state.isAdmin && accounts !== undefined && accounts.length < 1 &&
(AbsoluteTime.isNever(preference.hideMissingAccountUntil) ||
diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts
deleted file mode 100644
index 8c54f70db..000000000
--- a/packages/merchant-backoffice-ui/src/hooks/backend.ts
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import {
- TalerErrorDetail,
- TalerMerchantApi
-} from "@gnu-taler/taler-util";
-import {
- HttpResponse,
- HttpResponseOk,
- RequestError,
- RequestOptions,
- useApiContext
-} from "@gnu-taler/web-util/browser";
-import { useCallback, useEffect, useState } from "preact/hooks";
-import { useSWRConfig } from "swr";
-import { useSessionContext } from "../context/session.js";
-
-export function useMatchMutate(): (
- re?: RegExp,
- value?: unknown,
-) => Promise<any> {
- const { cache, mutate } = useSWRConfig();
-
- if (!(cache instanceof Map)) {
- throw new Error(
- "matchMutate requires the cache provider to be a Map instance",
- );
- }
-
- return function matchRegexMutate(re?: RegExp) {
- return mutate(
- (key) => {
- // evict if no key or regex === all
- if (!key || !re) return true;
- // match string
- if (typeof key === "string" && re.test(key)) return true;
- // record or object have the path at [0]
- if (typeof key === "object" && re.test(key[0])) return true;
- //key didn't match regex
- return false;
- },
- undefined,
- {
- revalidate: true,
- },
- );
- };
-}
-
-export function useBackendInstancesTestForAdmin(): HttpResponse<
- TalerMerchantApi.InstancesResponse,
- TalerErrorDetail
-> {
- const { request } = useBackendBaseRequest();
-
- type Type = TalerMerchantApi.InstancesResponse;
-
- const [result, setResult] = useState<
- HttpResponse<Type, TalerErrorDetail>
- >({ loading: true });
-
- useEffect(() => {
- request<Type>(`/management/instances`)
- .then((data) => setResult(data))
- .catch((error: RequestError<TalerErrorDetail>) =>
- setResult(error.cause),
- );
- }, [request]);
-
- return result;
-}
-
-const CHECK_CONFIG_INTERVAL_OK = 5 * 60 * 1000;
-const CHECK_CONFIG_INTERVAL_FAIL = 2 * 1000;
-
-export function useBackendConfig(): HttpResponse<
- TalerMerchantApi.VersionResponse | undefined,
- RequestError<TalerErrorDetail>
-> {
- const { request } = useBackendBaseRequest();
-
- type Type = TalerMerchantApi.VersionResponse;
- type State = {
- data: HttpResponse<Type, RequestError<TalerErrorDetail>>;
- timer: number;
- };
- const [result, setResult] = useState<State>({
- data: { loading: true },
- timer: 0,
- });
-
- useEffect(() => {
- if (result.timer) {
- clearTimeout(result.timer);
- }
- function tryConfig(): void {
- request<Type>(`/config`)
- .then((data) => {
- const timer: any = setTimeout(() => {
- tryConfig();
- }, CHECK_CONFIG_INTERVAL_OK);
- setResult({ data, timer });
- })
- .catch((error) => {
- const timer: any = setTimeout(() => {
- tryConfig();
- }, CHECK_CONFIG_INTERVAL_FAIL);
- const data = error.cause;
- setResult({ data, timer });
- });
- }
- tryConfig();
- }, [request]);
-
- return result.data;
-}
-
-interface useBackendInstanceRequestType {
- request: <T>(
- endpoint: string,
- options?: RequestOptions,
- ) => Promise<HttpResponseOk<T>>;
- fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
- multiFetcher: <T>(params: [url: string[]]) => Promise<HttpResponseOk<T>[]>;
- orderFetcher: <T>(
- params: [
- endpoint: string,
- paid?: YesOrNo,
- refunded?: YesOrNo,
- wired?: YesOrNo,
- searchDate?: Date,
- delta?: number,
- ],
- ) => Promise<HttpResponseOk<T>>;
- transferFetcher: <T>(
- params: [
- endpoint: string,
- payto_uri?: string,
- verified?: string,
- position?: string,
- delta?: number,
- ],
- ) => Promise<HttpResponseOk<T>>;
- templateFetcher: <T>(
- params: [endpoint: string, position?: string, delta?: number],
- ) => Promise<HttpResponseOk<T>>;
- webhookFetcher: <T>(
- params: [endpoint: string, position?: string, delta?: number],
- ) => Promise<HttpResponseOk<T>>;
-}
-interface useBackendBaseRequestType {
- request: <T>(
- endpoint: string,
- options?: RequestOptions,
- ) => Promise<HttpResponseOk<T>>;
-}
-
-type YesOrNo = "yes" | "no";
-
-/**
- *
- * @param root the request is intended to the base URL and no the instance URL
- * @returns request handler to
- */
-export function useBackendBaseRequest(): useBackendBaseRequestType {
- const { request: requestHandler } = useApiContext();
- const { state } = useSessionContext();
- const token = state.token;
- const baseUrl = state.backendUrl;
-
- const request = useCallback(
- function requestImpl<T>(
- endpoint: string,
- options: RequestOptions = {},
- ): Promise<HttpResponseOk<T>> {
- return requestHandler<T>(baseUrl, endpoint, { ...options, token })
- .then((res) => {
- return res;
- })
- .catch((err) => {
- throw err;
- });
- },
- [baseUrl, token],
- );
-
- return { request };
-}
-
-export function useBackendInstanceRequest(): useBackendInstanceRequestType {
- const { request: requestHandler } = useApiContext();
-
- const { state } = useSessionContext();
- const token = state.token;
- const baseUrl = state.backendUrl;
-
- const request = useCallback(
- function requestImpl<T>(
- endpoint: string,
- options: RequestOptions = {},
- ): Promise<HttpResponseOk<T>> {
- return requestHandler<T>(baseUrl, endpoint, { token, ...options });
- },
- [baseUrl, token],
- );
-
- const multiFetcher = useCallback(
- function multiFetcherImpl<T>(
- args: [endpoints: string[]],
- ): Promise<HttpResponseOk<T>[]> {
- const [endpoints] = args;
- return Promise.all(
- endpoints.map((endpoint) =>
- requestHandler<T>(baseUrl, endpoint, { token }),
- ),
- );
- },
- [baseUrl, token],
- );
-
- const fetcher = useCallback(
- function fetcherImpl<T>(endpoint: string): Promise<HttpResponseOk<T>> {
- return requestHandler<T>(baseUrl, endpoint, { token });
- },
- [baseUrl, token],
- );
-
- const orderFetcher = useCallback(
- function orderFetcherImpl<T>(
- args: [
- endpoint: string,
- paid?: YesOrNo,
- refunded?: YesOrNo,
- wired?: YesOrNo,
- searchDate?: Date,
- delta?: number,
- ],
- ): Promise<HttpResponseOk<T>> {
- const [endpoint, paid, refunded, wired, searchDate, delta] = args;
- const date_s =
- delta && delta < 0 && searchDate
- ? Math.floor(searchDate.getTime() / 1000) + 1
- : searchDate !== undefined
- ? Math.floor(searchDate.getTime() / 1000)
- : undefined;
- const params: any = {};
- if (paid !== undefined) params.paid = paid;
- if (delta !== undefined) params.delta = delta;
- if (refunded !== undefined) params.refunded = refunded;
- if (wired !== undefined) params.wired = wired;
- if (date_s !== undefined) params.date_s = date_s;
- if (delta === 0) {
- //in this case we can already assume the response
- //and avoid network
- return Promise.resolve({
- ok: true,
- data: { orders: [] } as T,
- });
- }
- return requestHandler<T>(baseUrl, endpoint, { params, token });
- },
- [baseUrl, token],
- );
-
- const transferFetcher = useCallback(
- function transferFetcherImpl<T>(
- args: [
- endpoint: string,
- payto_uri?: string,
- verified?: string,
- position?: string,
- delta?: number,
- ],
- ): Promise<HttpResponseOk<T>> {
- const [endpoint, payto_uri, verified, position, delta] = args;
- const params: any = {};
- if (payto_uri !== undefined) params.payto_uri = payto_uri;
- if (verified !== undefined) params.verified = verified;
- if (delta === 0) {
- //in this case we can already assume the response
- //and avoid network
- return Promise.resolve({
- ok: true,
- data: { transfers: [] } as T,
- });
- }
- if (delta !== undefined) {
- params.limit = delta;
- }
- if (position !== undefined) params.offset = position;
-
- return requestHandler<T>(baseUrl, endpoint, { params, token });
- },
- [baseUrl, token],
- );
-
- const templateFetcher = useCallback(
- function templateFetcherImpl<T>(
- args: [endpoint: string, position?: string, delta?: number],
- ): Promise<HttpResponseOk<T>> {
- const [endpoint, position, delta] = args;
- const params: any = {};
- if (delta === 0) {
- //in this case we can already assume the response
- //and avoid network
- return Promise.resolve({
- ok: true,
- data: { templates: [] } as T,
- });
- }
- if (delta !== undefined) {
- params.limit = delta;
- }
- if (position !== undefined) params.offset = position;
-
- return requestHandler<T>(baseUrl, endpoint, { params, token });
- },
- [baseUrl, token],
- );
-
- const webhookFetcher = useCallback(
- function webhookFetcherImpl<T>(
- args: [endpoint: string, position?: string, delta?: number],
- ): Promise<HttpResponseOk<T>> {
- const [endpoint, position, delta] = args;
- const params: any = {};
- if (delta === 0) {
- //in this case we can already assume the response
- //and avoid network
- return Promise.resolve({
- ok: true,
- data: { webhooks: [] } as T,
- });
- }
- if (delta !== undefined) {
- params.limit = delta;
- }
- if (position !== undefined) params.offset = position;
-
- return requestHandler<T>(baseUrl, endpoint, { params, token });
- },
- [baseUrl, token],
- );
-
- return {
- request,
- fetcher,
- multiFetcher,
- orderFetcher,
- transferFetcher,
- templateFetcher,
- webhookFetcher,
- };
-}
diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts b/packages/merchant-backoffice-ui/src/hooks/bank.ts
index 9ad4c3069..e1f2638ed 100644
--- a/packages/merchant-backoffice-ui/src/hooks/bank.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts
@@ -14,198 +14,97 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- HttpResponsePaginated,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
-import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
+import { useState } from "preact/hooks";
+import { PAGE_SIZE } 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 { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
+import { useSessionContext } from "../context/session.js";
+import { buildPaginatedResult } from "./webhooks.js";
const useSWR = _useSWR as unknown as SWRHook;
-// const MOCKED_ACCOUNTS: Record<string, TalerMerchantApi.AccountAddDetails> = {
-// "hwire1": {
-// h_wire: "hwire1",
-// payto_uri: "payto://fake/iban/123",
-// salt: "qwe",
-// },
-// "hwire2": {
-// h_wire: "hwire2",
-// payto_uri: "payto://fake/iban/123",
-// salt: "qwe2",
-// },
-// }
-
-// export function useBankAccountAPI(): BankAccountAPI {
-// const mutateAll = useMatchMutate();
-// const { request } = useBackendInstanceRequest();
-
-// const createBankAccount = async (
-// data: TalerMerchantApi.AccountAddDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// // MOCKED_ACCOUNTS[data.h_wire] = data
-// // return Promise.resolve({ ok: true, data: undefined });
-// const res = await request<void>(`/private/accounts`, {
-// method: "POST",
-// data,
-// });
-// await mutateAll(/.*private\/accounts.*/);
-// return res;
-// };
-
-// const updateBankAccount = async (
-// h_wire: string,
-// data: TalerMerchantApi.AccountPatchDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// // MOCKED_ACCOUNTS[h_wire].credit_facade_credentials = data.credit_facade_credentials
-// // MOCKED_ACCOUNTS[h_wire].credit_facade_url = data.credit_facade_url
-// // return Promise.resolve({ ok: true, data: undefined });
-// const res = await request<void>(`/private/accounts/${h_wire}`, {
-// method: "PATCH",
-// data,
-// });
-// await mutateAll(/.*private\/accounts.*/);
-// return res;
-// };
-
-// const deleteBankAccount = async (
-// h_wire: string,
-// ): Promise<HttpResponseOk<void>> => {
-// // delete MOCKED_ACCOUNTS[h_wire]
-// // return Promise.resolve({ ok: true, data: undefined });
-// const res = await request<void>(`/private/accounts/${h_wire}`, {
-// method: "DELETE",
-// });
-// await mutateAll(/.*private\/accounts.*/);
-// return res;
-// };
-
-// return {
-// createBankAccount,
-// updateBankAccount,
-// deleteBankAccount,
-// };
-// }
-
-// export interface BankAccountAPI {
-// createBankAccount: (
-// data: TalerMerchantApi.AccountAddDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// updateBankAccount: (
-// id: string,
-// data: TalerMerchantApi.AccountPatchDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// deleteBankAccount: (id: string) => Promise<HttpResponseOk<void>>;
-// }
-
export interface InstanceBankAccountFilter {
}
export function revalidateInstanceBankAccounts() {
- // mutate(key => key instanceof)
- return mutate((key) => Array.isArray(key) && key[key.length - 1] === "/private/accounts", undefined, { revalidate: true });
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "listBankAccounts",
+ undefined,
+ { revalidate: true },
+ );
}
-export function useInstanceBankAccounts(
- args?: InstanceBankAccountFilter,
- updatePosition?: (id: string) => void,
-): HttpResponsePaginated<
- TalerMerchantApi.AccountsSummaryResponse,
- TalerErrorDetail
-> {
-
- const { fetcher } = useBackendInstanceRequest();
-
- const [pageAfter, setPageAfter] = useState(1);
-
- const totalAfter = pageAfter * PAGE_SIZE;
- const {
- data: afterData,
- error: afterError,
- isValidating: loadingAfter,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.AccountsSummaryResponse>,
- RequestError<TalerErrorDetail>
- >([`/private/accounts`], fetcher);
-
- const [lastAfter, setLastAfter] = useState<
- HttpResponse<
- TalerMerchantApi.AccountsSummaryResponse,
- TalerErrorDetail
- >
- >({ loading: true });
- useEffect(() => {
- if (afterData) setLastAfter(afterData);
- }, [afterData /*, beforeData*/]);
-
- if (afterError) return afterError.cause;
-
- // if the query returns less that we ask, then we have reach the end or beginning
- const isReachingEnd =
- afterData && afterData.data.accounts.length < totalAfter;
- const isReachingStart = false;
+export function useInstanceBankAccounts() {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ const [offset, setOffset] = useState<string | undefined>();
+
+ async function fetcher([token, bid]: [AccessToken, string]) {
+ return await management.listBankAccounts(token, {
+ limit: 5,
+ offset: bid,
+ order: "dec",
+ });
+ }
+
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"listBankAccounts">,
+ TalerHttpError
+ >([session.token, offset, "listBankAccounts"], fetcher);
+ const isLastPage =
+ data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE;
+ const isFirstPage = !offset;
+
+ const result =
+ data && data.type == "ok" ? structuredClone(data.body.accounts) : [];
+ if (result.length == PAGE_SIZE + 1) {
+ result.pop();
+ }
const pagination = {
- isReachingEnd,
- isReachingStart,
- loadMore: () => {
- if (!afterData || isReachingEnd) return;
- if (afterData.data.accounts.length < MAX_RESULT_SIZE) {
- setPageAfter(pageAfter + 1);
- } else {
- const from = `${afterData.data.accounts[afterData.data.accounts.length - 1]
- .h_wire
- }`;
- if (from && updatePosition) updatePosition(from);
- }
+ result,
+ isLastPage,
+ isFirstPage,
+ loadNext: () => {
+ if (!result.length) return;
+ setOffset(result[result.length - 1].h_wire);
},
- loadMorePrev: () => {
+ loadFirst: () => {
+ setOffset(undefined);
},
};
- const accounts = !afterData ? [] : (afterData || lastAfter).data.accounts;
- if (loadingAfter /* || loadingBefore */)
- return { loading: true, data: { accounts } };
- if (/*beforeData &&*/ afterData) {
- return { ok: true, data: { accounts }, ...pagination };
- }
- return { loading: true };
+ 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)
+}
+
+export function revalidateBankAccountDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getBankAccountDetails",
+ undefined,
+ { revalidate: true },
+ );
}
+export function useBankAccountDetails(h_wire: string) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
-export function useBankAccountDetails(
- h_wire: string,
-): HttpResponse<
- TalerMerchantApi.BankAccountEntry,
- TalerErrorDetail
-> {
- // return {
- // ok: true,
- // data: {
- // ...MOCKED_ACCOUNTS[h_wire],
- // active: true,
- // }
- // }
- const { fetcher } = useBackendInstanceRequest();
-
- const { data, error, isValidating } = useSWR<
- HttpResponseOk<TalerMerchantApi.BankAccountEntry>,
- RequestError<TalerErrorDetail>
- >([`/private/accounts/${h_wire}`], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
-
- if (isValidating) return { loading: true, data: data?.data };
- if (data) {
- return data;
+ async function fetcher([token, wireId]: [AccessToken, string]) {
+ return await management.getBankAccountDetails(token, wireId);
}
- if (error) return error.cause;
- return { loading: true };
+
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"getBankAccountDetails">,
+ TalerHttpError
+ >([session.token, h_wire, "getBankAccountDetails"], fetcher);
+
+ if (data) return data;
+ if (error) return error;
+ return undefined;
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts
index e8a431ae5..cc907bd8f 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -14,18 +14,11 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- RequestError,
useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import {
- useBackendBaseRequest,
- useBackendInstanceRequest
-} from "./backend.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { AccessToken, TalerErrorDetail, TalerHttpError, TalerMerchantApi, TalerMerchantInstanceResultByMethod, TalerMerchantManagementResultByMethod, TalerMerchantResultByMethod } from "@gnu-taler/taler-util";
+import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util";
import _useSWR, { SWRHook, mutate } from "swr";
import { useSessionContext } from "../context/session.js";
const useSWR = _useSWR as unknown as SWRHook;
@@ -39,28 +32,6 @@ export function revalidateInstanceDetails() {
);
}
export function useInstanceDetails() {
- // const { fetcher } = useBackendInstanceRequest();
-
- // const { data, error, isValidating } = useSWR<
- // HttpResponseOk<TalerMerchantApi.QueryInstancesResponse>,
- // RequestError<TalerErrorDetail>
- // >([`/private/`], fetcher, {
- // refreshInterval: 0,
- // refreshWhenHidden: false,
- // revalidateOnFocus: false,
- // revalidateOnReconnect: false,
- // refreshWhenOffline: false,
- // revalidateIfStale: false,
- // errorRetryCount: 0,
- // errorRetryInterval: 1,
- // shouldRetryOnError: false,
- // });
-
- // if (isValidating) return { loading: true, data: data?.data };
- // if (data) return data;
- // if (error) return error.cause;
- // return { loading: true };
-
const { state: session } = useSessionContext();
const { lib: { management } } = useMerchantApiContext();
@@ -78,9 +49,6 @@ export function useInstanceDetails() {
return undefined;
}
-// type KYCStatus =
-// | { type: "ok" }
-// | { type: "redirect"; status: TalerMerchantApi.AccountKycRedirects };
export function revalidateInstanceKYCDetails() {
return mutate(
(key) => Array.isArray(key) && key[key.length - 1] === "getCurrentIntanceKycStatus",
@@ -89,32 +57,6 @@ export function revalidateInstanceKYCDetails() {
);
}
export function useInstanceKYCDetails() {
- // const { fetcher } = useBackendInstanceRequest();
-
- // const { data, error } = useSWR<
- // HttpResponseOk<TalerMerchantApi.AccountKycRedirects>,
- // RequestError<TalerErrorDetail>
- // >([`/private/kyc`], fetcher, {
- // refreshInterval: 60 * 1000,
- // refreshWhenHidden: false,
- // revalidateOnFocus: false,
- // revalidateIfStale: false,
- // revalidateOnMount: false,
- // revalidateOnReconnect: false,
- // refreshWhenOffline: false,
- // errorRetryCount: 0,
- // errorRetryInterval: 1,
- // shouldRetryOnError: false,
- // });
-
- // if (data) {
- // if (data.info?.status === 202)
- // return { ok: true, data: { type: "redirect", status: data.data } };
- // return { ok: true, data: { type: "ok" } };
- // }
- // if (error) return error.cause;
- // return { loading: true };
-
const { state: session } = useSessionContext();
const { lib: { management } } = useMerchantApiContext();
diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts b/packages/merchant-backoffice-ui/src/hooks/order.ts
index 40932ac62..47ddf1c38 100644
--- a/packages/merchant-backoffice-ui/src/hooks/order.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/order.ts
@@ -14,276 +14,81 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- HttpResponsePaginated,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
-import { useBackendInstanceRequest } from "./backend.js";
+import { PAGE_SIZE } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook } from "swr";
+import { AbsoluteTime, 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 interface OrderAPI {
-// //FIXME: add OutOfStockResponse on 410
-// createOrder: (
-// data: TalerMerchantApi.PostOrderRequest,
-// ) => Promise<HttpResponseOk<TalerMerchantApi.PostOrderResponse>>;
-// forgetOrder: (
-// id: string,
-// data: TalerMerchantApi.ForgetRequest,
-// ) => Promise<HttpResponseOk<void>>;
-// refundOrder: (
-// id: string,
-// data: TalerMerchantApi.RefundRequest,
-// ) => Promise<HttpResponseOk<TalerMerchantApi.MerchantRefundResponse>>;
-// deleteOrder: (id: string) => Promise<HttpResponseOk<void>>;
-// getPaymentURL: (id: string) => Promise<HttpResponseOk<string>>;
-// }
-type YesOrNo = "yes" | "no";
-// export function useOrderAPI(): OrderAPI {
-// const mutateAll = useMatchMutate();
-// const { request } = useBackendInstanceRequest();
-
-// const createOrder = async (
-// data: TalerMerchantApi.PostOrderRequest,
-// ): Promise<HttpResponseOk<TalerMerchantApi.PostOrderResponse>> => {
-// const res = await request<TalerMerchantApi.PostOrderResponse>(
-// `/private/orders`,
-// {
-// method: "POST",
-// data,
-// },
-// );
-// await mutateAll(/.*private\/orders.*/);
-// // mutate('')
-// return res;
-// };
-// const refundOrder = async (
-// orderId: string,
-// data: TalerMerchantApi.RefundRequest,
-// ): Promise<HttpResponseOk<TalerMerchantApi.MerchantRefundResponse>> => {
-// mutateAll(/@"\/private\/orders"@/);
-// const res = request<TalerMerchantApi.MerchantRefundResponse>(
-// `/private/orders/${orderId}/refund`,
-// {
-// method: "POST",
-// data,
-// },
-// );
-
-// // order list returns refundable information, so we must evict everything
-// await mutateAll(/.*private\/orders.*/);
-// return res;
-// };
-
-// const forgetOrder = async (
-// orderId: string,
-// data: TalerMerchantApi.ForgetRequest,
-// ): Promise<HttpResponseOk<void>> => {
-// mutateAll(/@"\/private\/orders"@/);
-// const res = request<void>(`/private/orders/${orderId}/forget`, {
-// method: "PATCH",
-// data,
-// });
-// // we may be forgetting some fields that are pare of the listing, so we must evict everything
-// await mutateAll(/.*private\/orders.*/);
-// return res;
-// };
-// const deleteOrder = async (
-// orderId: string,
-// ): Promise<HttpResponseOk<void>> => {
-// mutateAll(/@"\/private\/orders"@/);
-// const res = request<void>(`/private/orders/${orderId}`, {
-// method: "DELETE",
-// });
-// await mutateAll(/.*private\/orders.*/);
-// return res;
-// };
-
-// const getPaymentURL = async (
-// orderId: string,
-// ): Promise<HttpResponseOk<string>> => {
-// return request<TalerMerchantApi.MerchantOrderStatusResponse>(
-// `/private/orders/${orderId}`,
-// {
-// method: "GET",
-// },
-// ).then((res) => {
-// const url =
-// res.data.order_status === "unpaid"
-// ? res.data.taler_pay_uri
-// : res.data.contract_terms.fulfillment_url;
-// const response: HttpResponseOk<string> = res as any;
-// response.data = url || "";
-// return response;
-// });
-// };
-
-// return { createOrder, forgetOrder, deleteOrder, refundOrder, getPaymentURL };
-// }
+export function revalidateOrderDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getOrderDetails",
+ undefined,
+ { revalidate: true },
+ );
+}
+export function useOrderDetails(oderId: string) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
-export function useOrderDetails(
- oderId: string,
-): HttpResponse<
- TalerMerchantApi.MerchantOrderStatusResponse,
- TalerErrorDetail
-> {
- const { fetcher } = useBackendInstanceRequest();
+ async function fetcher([dId, token]: [string, AccessToken]) {
+ return await management.getOrderDetails(token, dId);
+ }
- const { data, error, isValidating } = useSWR<
- HttpResponseOk<TalerMerchantApi.MerchantOrderStatusResponse>,
- RequestError<TalerErrorDetail>
- >([`/private/orders/${oderId}`], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"getOrderDetails">,
+ TalerHttpError
+ >([oderId, session.token, "getOrderDetails"], fetcher);
- if (isValidating) return { loading: true, data: data?.data };
if (data) return data;
- if (error) return error.cause;
- return { loading: true };
+ if (error) return error;
+ return undefined;
}
export interface InstanceOrderFilter {
- paid?: YesOrNo;
- refunded?: YesOrNo;
- wired?: YesOrNo;
- date?: Date;
+ paid?: boolean;
+ refunded?: boolean;
+ wired?: boolean;
+ date?: AbsoluteTime;
+ position?: string;
}
export function useInstanceOrders(
args?: InstanceOrderFilter,
- updateFilter?: (d: Date) => void,
-): HttpResponsePaginated<
- TalerMerchantApi.OrderHistory,
- TalerErrorDetail
-> {
- const { orderFetcher } = useBackendInstanceRequest();
-
- const [pageBefore, setPageBefore] = useState(1);
- const [pageAfter, setPageAfter] = useState(1);
-
- const totalAfter = pageAfter * PAGE_SIZE;
- const totalBefore = args?.date ? pageBefore * PAGE_SIZE : 0;
-
- /**
- * FIXME: this can be cleaned up a little
- *
- * the logic of double query should be inside the orderFetch so from the hook perspective and cache
- * is just one query and one error status
- */
- const {
- data: beforeData,
- error: beforeError,
- isValidating: loadingBefore,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.OrderHistory>,
- RequestError<TalerErrorDetail>
- >(
- [
- `/private/orders`,
- args?.paid,
- args?.refunded,
- args?.wired,
- args?.date,
- totalBefore,
- ],
- orderFetcher,
- );
- const {
- data: afterData,
- error: afterError,
- isValidating: loadingAfter,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.OrderHistory>,
- RequestError<TalerErrorDetail>
- >(
- [
- `/private/orders`,
- args?.paid,
- args?.refunded,
- args?.wired,
- args?.date,
- -totalAfter,
- ],
- orderFetcher,
- );
-
- //this will save last result
- const [lastBefore, setLastBefore] = useState<
- HttpResponse<
- TalerMerchantApi.OrderHistory,
- TalerErrorDetail
- >
- >({ loading: true });
- const [lastAfter, setLastAfter] = useState<
- HttpResponse<
- TalerMerchantApi.OrderHistory,
- TalerErrorDetail
- >
- >({ loading: true });
- useEffect(() => {
- if (afterData) setLastAfter(afterData);
- if (beforeData) setLastBefore(beforeData);
- }, [afterData, beforeData]);
-
- if (beforeError) return beforeError.cause;
- if (afterError) return afterError.cause;
+ updatePosition: (d: string | undefined) => void = () => { },
+) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ // const [offset, setOffset] = useState<string | undefined>(args?.position);
+
+ async function fetcher([token, o, p, r, w, d]: [AccessToken, string, boolean, boolean, boolean, AbsoluteTime]) {
+ return await management.listOrders(token, {
+ limit: PAGE_SIZE,
+ offset: o,
+ order: "dec",
+ paid: p,
+ refunded: r,
+ wired: w,
+ date: d,
+ });
+ }
- // if the query returns less that we ask, then we have reach the end or beginning
- const isReachingEnd = afterData && afterData.data.orders.length < totalAfter;
- const isReachingStart =
- args?.date === undefined ||
- (beforeData && beforeData.data.orders.length < totalBefore);
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"listOrders">,
+ TalerHttpError
+ >([session.token, args?.position, args?.paid, args?.refunded, args?.wired, args?.date, "listOrders"], fetcher);
- const pagination = {
- isReachingEnd,
- isReachingStart,
- loadMore: () => {
- if (!afterData || isReachingEnd) return;
- if (afterData.data.orders.length < MAX_RESULT_SIZE) {
- setPageAfter(pageAfter + 1);
- } else {
- const from =
- afterData.data.orders[afterData.data.orders.length - 1].timestamp.t_s;
- if (from && from !== "never" && updateFilter)
- updateFilter(new Date(from * 1000));
- }
- },
- loadMorePrev: () => {
- if (!beforeData || isReachingStart) return;
- if (beforeData.data.orders.length < MAX_RESULT_SIZE) {
- setPageBefore(pageBefore + 1);
- } else if (beforeData) {
- const from =
- beforeData.data.orders[beforeData.data.orders.length - 1].timestamp
- .t_s;
- if (from && from !== "never" && updateFilter)
- updateFilter(new Date(from * 1000));
- }
- },
- };
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
- const orders =
- !beforeData || !afterData
- ? []
- : (beforeData || lastBefore).data.orders
- .slice()
- .reverse()
- .concat((afterData || lastAfter).data.orders);
- if (loadingAfter || loadingBefore) return { loading: true, data: { orders } };
- if (beforeData && afterData) {
- return { ok: true, data: { orders }, ...pagination };
- }
- return { loading: true };
+ return buildPaginatedResult(data.body.orders, args?.position, updatePosition, (d) => String(d.row_id))
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts b/packages/merchant-backoffice-ui/src/hooks/otp.ts
index 36db2ea90..69e4a0f4f 100644
--- a/packages/merchant-backoffice-ui/src/hooks/otp.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts
@@ -14,195 +14,72 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- HttpResponsePaginated,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
-import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
+import { useState } from "preact/hooks";
+import { PAGE_SIZE } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook } from "swr";
+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 useOtpDeviceAPI(): OtpDeviceAPI {
-// const mutateAll = useMatchMutate();
-// const { request } = useBackendInstanceRequest();
-
-// const createOtpDevice = async (
-// data: TalerMerchantApi.OtpDeviceAddDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// // MOCKED_DEVICES[data.otp_device_id] = data
-// // return Promise.resolve({ ok: true, data: undefined });
-// const res = await request<void>(`/private/otp-devices`, {
-// method: "POST",
-// data,
-// });
-// await mutateAll(/.*private\/otp-devices.*/);
-// return res;
-// };
-
-// const updateOtpDevice = async (
-// deviceId: string,
-// data: TalerMerchantApi.OtpDevicePatchDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// // MOCKED_DEVICES[deviceId].otp_algorithm = data.otp_algorithm
-// // MOCKED_DEVICES[deviceId].otp_ctr = data.otp_ctr
-// // MOCKED_DEVICES[deviceId].otp_device_description = data.otp_device_description
-// // MOCKED_DEVICES[deviceId].otp_key = data.otp_key
-// // return Promise.resolve({ ok: true, data: undefined });
-// const res = await request<void>(`/private/otp-devices/${deviceId}`, {
-// method: "PATCH",
-// data,
-// });
-// await mutateAll(/.*private\/otp-devices.*/);
-// return res;
-// };
-
-// const deleteOtpDevice = async (
-// deviceId: string,
-// ): Promise<HttpResponseOk<void>> => {
-// // delete MOCKED_DEVICES[deviceId]
-// // return Promise.resolve({ ok: true, data: undefined });
-// const res = await request<void>(`/private/otp-devices/${deviceId}`, {
-// method: "DELETE",
-// });
-// await mutateAll(/.*private\/otp-devices.*/);
-// return res;
-// };
-
-// return {
-// createOtpDevice,
-// updateOtpDevice,
-// deleteOtpDevice,
-// };
-// }
-
-// export interface OtpDeviceAPI {
-// createOtpDevice: (
-// data: TalerMerchantApi.OtpDeviceAddDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// updateOtpDevice: (
-// id: string,
-// data: TalerMerchantApi.OtpDevicePatchDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// deleteOtpDevice: (id: string) => Promise<HttpResponseOk<void>>;
-// }
-
-export interface InstanceOtpDeviceFilter {
+export function revalidateInstanceOtpDevices() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "listOtpDevices",
+ undefined,
+ { revalidate: true },
+ );
}
+export function useInstanceOtpDevices() {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ const [offset, setOffset] = useState<string | undefined>();
+
+ async function fetcher([token, bid]: [AccessToken, string]) {
+ return await management.listOtpDevices(token, {
+ limit: PAGE_SIZE,
+ offset: bid,
+ order: "dec",
+ });
+ }
-export function useInstanceOtpDevices(
- args?: InstanceOtpDeviceFilter,
- updatePosition?: (id: string) => void,
-): HttpResponsePaginated<
- TalerMerchantApi.OtpDeviceSummaryResponse,
- TalerErrorDetail
-> {
- // return {
- // ok: true,
- // loadMore: () => { },
- // loadMorePrev: () => { },
- // data: {
- // otp_devices: Object.values(MOCKED_DEVICES).map(d => ({
- // device_description: d.otp_device_description,
- // otp_device_id: d.otp_device_id
- // }))
- // }
- // }
-
- const { fetcher } = useBackendInstanceRequest();
-
- const [pageAfter, setPageAfter] = useState(1);
-
- const totalAfter = pageAfter * PAGE_SIZE;
- const {
- data: afterData,
- error: afterError,
- isValidating: loadingAfter,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.OtpDeviceSummaryResponse>,
- RequestError<TalerErrorDetail>
- >([`/private/otp-devices`], fetcher);
-
- const [lastAfter, setLastAfter] = useState<
- HttpResponse<
- TalerMerchantApi.OtpDeviceSummaryResponse,
- TalerErrorDetail
- >
- >({ loading: true });
- useEffect(() => {
- if (afterData) setLastAfter(afterData);
- }, [afterData /*, beforeData*/]);
-
- if (afterError) return afterError.cause;
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"listOtpDevices">,
+ TalerHttpError
+ >([session.token, offset, "listOtpDevices"], fetcher);
- // if the query returns less that we ask, then we have reach the end or beginning
- const isReachingEnd =
- afterData && afterData.data.otp_devices.length < totalAfter;
- const isReachingStart = true;
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
- const pagination = {
- isReachingEnd,
- isReachingStart,
- loadMore: () => {
- if (!afterData || isReachingEnd) return;
- if (afterData.data.otp_devices.length < MAX_RESULT_SIZE) {
- setPageAfter(pageAfter + 1);
- } else {
- const from = `${afterData.data.otp_devices[afterData.data.otp_devices.length - 1]
- .otp_device_id
- }`;
- if (from && updatePosition) updatePosition(from);
- }
- },
- loadMorePrev: () => {
- },
- };
+ return buildPaginatedResult(data.body.otp_devices, offset, setOffset, (d) => d.otp_device_id)
+}
- const otp_devices = !afterData ? [] : (afterData || lastAfter).data.otp_devices;
- if (loadingAfter /* || loadingBefore */)
- return { loading: true, data: { otp_devices } };
- if (/*beforeData &&*/ afterData) {
- return { ok: true, data: { otp_devices }, ...pagination };
- }
- return { loading: true };
+export function revalidateOtpDeviceDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getOtpDeviceDetails",
+ undefined,
+ { revalidate: true },
+ );
}
+export function useOtpDeviceDetails(deviceId: string) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
-export function useOtpDeviceDetails(
- deviceId: string,
-): HttpResponse<
- TalerMerchantApi.OtpDeviceDetails,
- TalerErrorDetail
-> {
- // return {
- // ok: true,
- // data: {
- // device_description: MOCKED_DEVICES[deviceId].otp_device_description,
- // otp_algorithm: MOCKED_DEVICES[deviceId].otp_algorithm,
- // otp_ctr: MOCKED_DEVICES[deviceId].otp_ctr
- // }
- // }
- const { fetcher } = useBackendInstanceRequest();
+ async function fetcher([dId, token]: [string, AccessToken]) {
+ return await management.getOtpDeviceDetails(token, dId);
+ }
- const { data, error, isValidating } = useSWR<
- HttpResponseOk<TalerMerchantApi.OtpDeviceDetails>,
- RequestError<TalerErrorDetail>
- >([`/private/otp-devices/${deviceId}`], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"getOtpDeviceDetails">,
+ TalerHttpError
+ >([deviceId, session.token, "getOtpDeviceDetails"], fetcher);
- if (isValidating) return { loading: true, data: data?.data };
- if (data) {
- return data;
- }
- if (error) return error.cause;
- return { loading: true };
+ if (data) return data;
+ if (error) return error;
+ return undefined;
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts b/packages/merchant-backoffice-ui/src/hooks/product.ts
index 0eb54f717..6721136a5 100644
--- a/packages/merchant-backoffice-ui/src/hooks/product.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/product.ts
@@ -14,164 +14,93 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import _useSWR, { SWRHook, useSWRConfig } from "swr";
-import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
+import { AccessToken, OperationOk, TalerHttpError, TalerMerchantApi, TalerMerchantManagementErrorsByMethod, TalerMerchantManagementResultByMethod, opFixedSuccess } from "@gnu-taler/taler-util";
+import { useState } from "preact/hooks";
+import _useSWR, { SWRHook, mutate } from "swr";
+import { useSessionContext } from "../context/session.js";
+import { PAGE_SIZE } from "../utils/constants.js";
+import { buildPaginatedResult } from "./webhooks.js";
const useSWR = _useSWR as unknown as SWRHook;
-// export interface ProductAPI {
-// getProduct: (
-// id: string,
-// ) => Promise<void>;
-// createProduct: (
-// data: TalerMerchantApi.ProductAddDetail,
-// ) => Promise<void>;
-// updateProduct: (
-// id: string,
-// data: TalerMerchantApi.ProductPatchDetail,
-// ) => Promise<void>;
-// deleteProduct: (id: string) => Promise<void>;
-// lockProduct: (
-// id: string,
-// data: TalerMerchantApi.LockRequest,
-// ) => Promise<void>;
-// }
-
-// export function useProductAPI(): ProductAPI {
-// const mutateAll = useMatchMutate();
-// const { mutate } = useSWRConfig();
-
-// const { request } = useBackendInstanceRequest();
-
-// const createProduct = async (
-// data: TalerMerchantApi.ProductAddDetail,
-// ): Promise<void> => {
-// const res = await request(`/private/products`, {
-// method: "POST",
-// data,
-// });
-
-// return await mutateAll(/.*\/private\/products.*/);
-// };
-
-// const updateProduct = async (
-// productId: string,
-// data: TalerMerchantApi.ProductPatchDetail,
-// ): Promise<void> => {
-// const r = await request(`/private/products/${productId}`, {
-// method: "PATCH",
-// data,
-// });
-
-// return await mutateAll(/.*\/private\/products.*/);
-// };
-
-// const deleteProduct = async (productId: string): Promise<void> => {
-// await request(`/private/products/${productId}`, {
-// method: "DELETE",
-// });
-// await mutate([`/private/products`]);
-// };
-
-// const lockProduct = async (
-// productId: string,
-// data: TalerMerchantApi.LockRequest,
-// ): Promise<void> => {
-// await request(`/private/products/${productId}/lock`, {
-// method: "POST",
-// data,
-// });
-
-// return await mutateAll(/.*"\/private\/products.*/);
-// };
-
-// const getProduct = async (
-// productId: string,
-// ): Promise<void> => {
-// await request(`/private/products/${productId}`, {
-// method: "GET",
-// });
-
-// return
-// };
-
-// return { createProduct, updateProduct, deleteProduct, lockProduct, getProduct };
-// }
-
-export function useInstanceProducts(): HttpResponse<
- (TalerMerchantApi.ProductDetail & WithId)[],
- TalerErrorDetail
-> {
- const { fetcher, multiFetcher } = useBackendInstanceRequest();
-
- const { data: list, error: listError } = useSWR<
- HttpResponseOk<TalerMerchantApi.InventorySummaryResponse>,
- RequestError<TalerErrorDetail>
- >([`/private/products`], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
-
- const paths = (list?.data.products || []).map(
- (p) => `/private/products/${p.product_id}`,
+type ProductWithId = TalerMerchantApi.ProductDetail & { id: string, serial: number };
+function notUndefined(c: ProductWithId | undefined): c is ProductWithId {
+ return c !== undefined;
+}
+
+export function revalidateInstanceProducts() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "listProductsWithId",
+ undefined,
+ { revalidate: true },
);
- const { data: products, error: productError } = useSWR<
- HttpResponseOk<TalerMerchantApi.ProductDetail>[],
- RequestError<TalerErrorDetail>
- >([paths], multiFetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
-
- if (listError) return listError.cause;
- if (productError) return productError.cause;
-
- if (products) {
- const dataWithId = products.map((d) => {
- //take the id from the queried url
- return {
- ...d.data,
- id: d.info?.url.replace(/.*\/private\/products\//, "") || "",
- };
+}
+export function useInstanceProducts() {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ const [offset, setOffset] = useState<number | undefined>();
+
+ async function fetcher([token, bid]: [AccessToken, number]) {
+ const list = await management.listProducts(token, {
+ limit: PAGE_SIZE,
+ offset: String(bid),
+ order: "dec",
});
- return { ok: true, data: dataWithId };
+ if (list.type !== "ok") {
+ return list;
+ }
+ const all: Array<ProductWithId | undefined> = await Promise.all(
+ list.body.products.map(async (c) => {
+ const r = await management.getProductDetails(token, c.product_id);
+ if (r.type === "fail") {
+ return undefined;
+ }
+ return { ...r.body, id: c.product_id, serial: c.product_serial };
+ }),
+ );
+ const products = all.filter(notUndefined);
+
+ return opFixedSuccess({ products });
}
- return { loading: true };
+
+ const { data, error } = useSWR<
+ OperationOk<{ products: ProductWithId[] }> |
+ TalerMerchantManagementErrorsByMethod<"listProducts">,
+ TalerHttpError
+ >([session.token, offset, "listProductsWithId"], fetcher);
+
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
+
+ return buildPaginatedResult(data.body.products, offset, setOffset, (d) => d.serial)
+}
+
+export function revalidateProductDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getProductDetails",
+ undefined,
+ { revalidate: true },
+ );
}
+export function useProductDetails(productId: string) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ async function fetcher([pid, token]: [string, AccessToken]) {
+ return await management.getProductDetails(token, pid);
+ }
+
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"getProductDetails">,
+ TalerHttpError
+ >([productId, session.token, "getProductDetails"], fetcher);
-export function useProductDetails(
- productId: string,
-): HttpResponse<
- TalerMerchantApi.ProductDetail,
- TalerErrorDetail
-> {
- const { fetcher } = useBackendInstanceRequest();
-
- const { data, error, isValidating } = useSWR<
- HttpResponseOk<TalerMerchantApi.ProductDetail>,
- RequestError<TalerErrorDetail>
- >([`/private/products/${productId}`], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
-
- if (isValidating) return { loading: true, data: data?.data };
if (data) return data;
- if (error) return error.cause;
- return { loading: true };
+ if (error) return error;
+ return undefined;
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts b/packages/merchant-backoffice-ui/src/hooks/templates.ts
index ff0461a67..10e480b01 100644
--- a/packages/merchant-backoffice-ui/src/hooks/templates.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts
@@ -14,253 +14,77 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- HttpResponsePaginated,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
-import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
+import { useState } from "preact/hooks";
+import { PAGE_SIZE } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook } from "swr";
+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 useTemplateAPI(): TemplateAPI {
-// const mutateAll = useMatchMutate();
-// const { request } = useBackendInstanceRequest();
-
-// const createTemplate = async (
-// data: TalerMerchantApi.TemplateAddDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/templates`, {
-// method: "POST",
-// data,
-// });
-// await mutateAll(/.*private\/templates.*/);
-// return res;
-// };
-
-// const updateTemplate = async (
-// templateId: string,
-// data: TalerMerchantApi.TemplatePatchDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/templates/${templateId}`, {
-// method: "PATCH",
-// data,
-// });
-// await mutateAll(/.*private\/templates.*/);
-// return res;
-// };
-
-// const deleteTemplate = async (
-// templateId: string,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/templates/${templateId}`, {
-// method: "DELETE",
-// });
-// await mutateAll(/.*private\/templates.*/);
-// return res;
-// };
-
-// const createOrderFromTemplate = async (
-// templateId: string,
-// data: TalerMerchantApi.UsingTemplateDetails,
-// ): Promise<
-// HttpResponseOk<TalerMerchantApi.PostOrderResponse>
-// > => {
-// const res = await request<TalerMerchantApi.PostOrderResponse>(
-// `/templates/${templateId}`,
-// {
-// method: "POST",
-// data,
-// },
-// );
-// await mutateAll(/.*private\/templates.*/);
-// return res;
-// };
-
-// const testTemplateExist = async (
-// templateId: string,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/templates/${templateId}`, { method: "GET", });
-// return res;
-// };
-
-
-// return {
-// createTemplate,
-// updateTemplate,
-// deleteTemplate,
-// testTemplateExist,
-// createOrderFromTemplate,
-// };
-// }
-
-// export interface TemplateAPI {
-// createTemplate: (
-// data: TalerMerchantApi.TemplateAddDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// updateTemplate: (
-// id: string,
-// data: TalerMerchantApi.TemplatePatchDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// testTemplateExist: (
-// id: string
-// ) => Promise<HttpResponseOk<void>>;
-// deleteTemplate: (id: string) => Promise<HttpResponseOk<void>>;
-// createOrderFromTemplate: (
-// id: string,
-// data: TalerMerchantApi.UsingTemplateDetails,
-// ) => Promise<HttpResponseOk<TalerMerchantApi.PostOrderResponse>>;
-// }
export interface InstanceTemplateFilter {
- //FIXME: add filter to the template list
- position?: string;
}
-export function useInstanceTemplates(
- args?: InstanceTemplateFilter,
- updatePosition?: (id: string) => void,
-): HttpResponsePaginated<
- TalerMerchantApi.TemplateSummaryResponse,
- TalerErrorDetail
-> {
- const { templateFetcher } = useBackendInstanceRequest();
-
- const [pageBefore, setPageBefore] = useState(1);
- const [pageAfter, setPageAfter] = useState(1);
-
- const totalAfter = pageAfter * PAGE_SIZE;
- const totalBefore = args?.position ? pageBefore * PAGE_SIZE : 0;
-
- /**
- * FIXME: this can be cleaned up a little
- *
- * the logic of double query should be inside the orderFetch so from the hook perspective and cache
- * is just one query and one error status
- */
- const {
- data: beforeData,
- error: beforeError,
- isValidating: loadingBefore,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.TemplateSummaryResponse>,
- RequestError<TalerErrorDetail>>(
- [
- `/private/templates`,
- args?.position,
- totalBefore,
- ],
- templateFetcher,
- );
- const {
- data: afterData,
- error: afterError,
- isValidating: loadingAfter,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.TemplateSummaryResponse>,
- RequestError<TalerErrorDetail>
- >([`/private/templates`, args?.position, -totalAfter], templateFetcher);
-
- //this will save last result
- const [lastBefore, setLastBefore] = useState<
- HttpResponse<
- TalerMerchantApi.TemplateSummaryResponse,
- TalerErrorDetail
- >
- >({ loading: true });
+export function revalidateInstanceTemplates() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "listTemplates",
+ undefined,
+ { revalidate: true },
+ );
+}
+export function useInstanceTemplates() {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ const [offset, setOffset] = useState<string | undefined>();
+
+ async function fetcher([token, bid]: [AccessToken, string]) {
+ return await management.listTemplates(token, {
+ limit: PAGE_SIZE,
+ offset: bid,
+ order: "dec",
+ });
+ }
- const [lastAfter, setLastAfter] = useState<
- HttpResponse<
- TalerMerchantApi.TemplateSummaryResponse,
- TalerErrorDetail
- >
- >({ loading: true });
- useEffect(() => {
- if (afterData) setLastAfter(afterData);
- if (beforeData) setLastBefore(beforeData);
- }, [afterData, beforeData]);
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"listTemplates">,
+ TalerHttpError
+ >([session.token, offset, "listTemplates"], fetcher);
- if (beforeError) return beforeError.cause;
- if (afterError) return afterError.cause;
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
- // if the query returns less that we ask, then we have reach the end or beginning
- const isReachingEnd =
- afterData && afterData.data.templates.length < totalAfter;
- const isReachingStart = args?.position === undefined
- ||
- (beforeData && beforeData.data.templates.length < totalBefore);
+ return buildPaginatedResult(data.body.templates, offset, setOffset, (d) => d.template_id)
- const pagination = {
- isReachingEnd,
- isReachingStart,
- loadMore: () => {
- if (!afterData || isReachingEnd) return;
- if (afterData.data.templates.length < MAX_RESULT_SIZE) {
- setPageAfter(pageAfter + 1);
- } else {
- const from = `${afterData.data.templates[afterData.data.templates.length - 1]
- .template_id
- }`;
- if (from && updatePosition) updatePosition(from);
- }
- },
- loadMorePrev: () => {
- if (!beforeData || isReachingStart) return;
- if (beforeData.data.templates.length < MAX_RESULT_SIZE) {
- setPageBefore(pageBefore + 1);
- } else if (beforeData) {
- const from = `${beforeData.data.templates[beforeData.data.templates.length - 1]
- .template_id
- }`;
- if (from && updatePosition) updatePosition(from);
- }
- },
- };
+}
- // const templates = !afterData ? [] : (afterData || lastAfter).data.templates;
- const templates =
- !beforeData || !afterData
- ? []
- : (beforeData || lastBefore).data.templates
- .slice()
- .reverse()
- .concat((afterData || lastAfter).data.templates);
- if (loadingAfter || loadingBefore)
- return { loading: true, data: { templates } };
- if (beforeData && afterData) {
- return { ok: true, data: { templates }, ...pagination };
- }
- return { loading: true };
+export function revalidateProductDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getTemplateDetails",
+ undefined,
+ { revalidate: true },
+ );
}
+export function useTemplateDetails(templateId: string) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
-export function useTemplateDetails(
- templateId: string,
-): HttpResponse<
- TalerMerchantApi.TemplateDetails,
- TalerErrorDetail
-> {
- const { templateFetcher } = useBackendInstanceRequest();
+ async function fetcher([tid, token]: [string, AccessToken]) {
+ return await management.getTemplateDetails(token, tid);
+ }
- const { data, error, isValidating } = useSWR<
- HttpResponseOk<TalerMerchantApi.TemplateDetails>,
- RequestError<TalerErrorDetail>
- >([`/private/templates/${templateId}`], templateFetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"getTemplateDetails">,
+ TalerHttpError
+ >([templateId, session.token, "getTemplateDetails"], fetcher);
- if (isValidating) return { loading: true, data: data?.data };
- if (data) {
- return data;
- }
- if (error) return error.cause;
- return { loading: true };
+ if (data) return data;
+ if (error) return error;
+ return undefined;
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
index af62af0fa..afabf775c 100644
--- a/packages/merchant-backoffice-ui/src/hooks/transfer.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
@@ -14,173 +14,59 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- HttpResponsePaginated,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
-import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
+import { PAGE_SIZE } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook } from "swr";
+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";
+import { useState } from "preact/hooks";
const useSWR = _useSWR as unknown as SWRHook;
-// export function useTransferAPI(): TransferAPI {
-// const mutateAll = useMatchMutate();
-// const { request } = useBackendInstanceRequest();
-
-// const informTransfer = async (
-// data: TalerMerchantApi.TransferInformation,
-// ): Promise<HttpResponseOk<{}>> => {
-// const res = await request<{}>(`/private/transfers`, {
-// method: "POST",
-// data,
-// });
-
-// await mutateAll(/.*private\/transfers.*/);
-// return res;
-// };
-
-// return { informTransfer };
-// }
-
-// export interface TransferAPI {
-// informTransfer: (
-// data: TalerMerchantApi.TransferInformation,
-// ) => Promise<HttpResponseOk<{}>>;
-// }
-
export interface InstanceTransferFilter {
payto_uri?: string;
- verified?: "yes" | "no";
+ verified?: boolean;
position?: string;
}
+export function revalidateInstanceTransfers() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "listWireTransfers",
+ undefined,
+ { revalidate: true },
+ );
+}
export function useInstanceTransfers(
args?: InstanceTransferFilter,
- updatePosition?: (id: string) => void,
-): HttpResponsePaginated<
- TalerMerchantApi.TransferList,
- TalerErrorDetail
-> {
- const { transferFetcher } = useBackendInstanceRequest();
-
- const [pageBefore, setPageBefore] = useState(1);
- const [pageAfter, setPageAfter] = useState(1);
-
- const totalAfter = pageAfter * PAGE_SIZE;
- const totalBefore = args?.position !== undefined ? pageBefore * PAGE_SIZE : 0;
-
- /**
- * FIXME: this can be cleaned up a little
- *
- * the logic of double query should be inside the orderFetch so from the hook perspective and cache
- * is just one query and one error status
- */
- const {
- data: beforeData,
- error: beforeError,
- isValidating: loadingBefore,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.TransferList>,
- RequestError<TalerErrorDetail>
- >(
- [
- `/private/transfers`,
- args?.payto_uri,
- args?.verified,
- args?.position,
- totalBefore,
- ],
- transferFetcher,
- );
- const {
- data: afterData,
- error: afterError,
- isValidating: loadingAfter,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.TransferList>,
- RequestError<TalerErrorDetail>
- >(
- [
- `/private/transfers`,
- args?.payto_uri,
- args?.verified,
- args?.position,
- -totalAfter,
- ],
- transferFetcher,
- );
-
- //this will save last result
- const [lastBefore, setLastBefore] = useState<
- HttpResponse<
- TalerMerchantApi.TransferList,
- TalerErrorDetail
- >
- >({ loading: true });
- const [lastAfter, setLastAfter] = useState<
- HttpResponse<
- TalerMerchantApi.TransferList,
- TalerErrorDetail
- >
- >({ loading: true });
- useEffect(() => {
- if (afterData) setLastAfter(afterData);
- if (beforeData) setLastBefore(beforeData);
- }, [afterData, beforeData]);
+ updatePosition: (id: string | undefined) => void = (() => { }),
+) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ // const [offset, setOffset] = useState<string | undefined>(args?.position);
+
+ async function fetcher([token, o, p, v]: [AccessToken, string, string, boolean]) {
+ return await management.listWireTransfers(token, {
+ paytoURI: p,
+ verified: v,
+ limit: PAGE_SIZE,
+ offset: o,
+ order: "dec",
+ });
+ }
- if (beforeError) return beforeError.cause;
- if (afterError) return afterError.cause;
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"listWireTransfers">,
+ TalerHttpError
+ >([session.token, args?.position, args?.payto_uri, args?.verified, "listWireTransfers"], fetcher);
- // if the query returns less that we ask, then we have reach the end or beginning
- const isReachingEnd =
- afterData && afterData.data.transfers.length < totalAfter;
- const isReachingStart =
- args?.position === undefined ||
- (beforeData && beforeData.data.transfers.length < totalBefore);
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
- const pagination = {
- isReachingEnd,
- isReachingStart,
- loadMore: () => {
- if (!afterData || isReachingEnd) return;
- if (afterData.data.transfers.length < MAX_RESULT_SIZE) {
- setPageAfter(pageAfter + 1);
- } else {
- const from = `${afterData.data.transfers[afterData.data.transfers.length - 1]
- .transfer_serial_id
- }`;
- if (from && updatePosition) updatePosition(from);
- }
- },
- loadMorePrev: () => {
- if (!beforeData || isReachingStart) return;
- if (beforeData.data.transfers.length < MAX_RESULT_SIZE) {
- setPageBefore(pageBefore + 1);
- } else if (beforeData) {
- const from = `${beforeData.data.transfers[beforeData.data.transfers.length - 1]
- .transfer_serial_id
- }`;
- if (from && updatePosition) updatePosition(from);
- }
- },
- };
+ return buildPaginatedResult(data.body.transfers, args?.position, updatePosition, (d) => String(d.transfer_serial_id))
- const transfers =
- !beforeData || !afterData
- ? []
- : (beforeData || lastBefore).data.transfers
- .slice()
- .reverse()
- .concat((afterData || lastAfter).data.transfers);
- if (loadingAfter || loadingBefore)
- return { loading: true, data: { transfers } };
- if (beforeData && afterData) {
- return { ok: true, data: { transfers }, ...pagination };
- }
- return { loading: true };
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
index cc817b84e..5e2e08bcc 100644
--- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
@@ -14,165 +14,108 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- HttpResponse,
- HttpResponseOk,
- HttpResponsePaginated,
- RequestError,
+ useMerchantApiContext
} from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
-import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
+import { useState } from "preact/hooks";
+import { PAGE_SIZE } from "../utils/constants.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook } from "swr";
+import { AccessToken, OperationOk, TalerHttpError, TalerMerchantManagementResultByMethod } from "@gnu-taler/taler-util";
+import _useSWR, { SWRHook, mutate } from "swr";
+import { useSessionContext } from "../context/session.js";
const useSWR = _useSWR as unknown as SWRHook;
-// export function useWebhookAPI(): WebhookAPI {
-// const mutateAll = useMatchMutate();
-// const { request } = useBackendInstanceRequest();
-
-// const createWebhook = async (
-// data: TalerMerchantApi.WebhookAddDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/webhooks`, {
-// method: "POST",
-// data,
-// });
-// await mutateAll(/.*private\/webhooks.*/);
-// return res;
-// };
-
-// const updateWebhook = async (
-// webhookId: string,
-// data: TalerMerchantApi.WebhookPatchDetails,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/webhooks/${webhookId}`, {
-// method: "PATCH",
-// data,
-// });
-// await mutateAll(/.*private\/webhooks.*/);
-// return res;
-// };
-
-// const deleteWebhook = async (
-// webhookId: string,
-// ): Promise<HttpResponseOk<void>> => {
-// const res = await request<void>(`/private/webhooks/${webhookId}`, {
-// method: "DELETE",
-// });
-// await mutateAll(/.*private\/webhooks.*/);
-// return res;
-// };
-
-// return { createWebhook, updateWebhook, deleteWebhook };
-// }
-
-// export interface WebhookAPI {
-// createWebhook: (
-// data: TalerMerchantApi.WebhookAddDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// updateWebhook: (
-// id: string,
-// data: TalerMerchantApi.WebhookPatchDetails,
-// ) => Promise<HttpResponseOk<void>>;
-// deleteWebhook: (id: string) => Promise<HttpResponseOk<void>>;
-// }
-
export interface InstanceWebhookFilter {
- //FIXME: add filter to the webhook list
- position?: string;
}
-export function useInstanceWebhooks(
- args?: InstanceWebhookFilter,
- updatePosition?: (id: string) => void,
-): HttpResponsePaginated<
- TalerMerchantApi.WebhookSummaryResponse,
- TalerErrorDetail
-> {
- const { webhookFetcher } = useBackendInstanceRequest();
-
- const [pageBefore, setPageBefore] = useState(1);
- const [pageAfter, setPageAfter] = useState(1);
-
- const totalAfter = pageAfter * PAGE_SIZE;
- const totalBefore = args?.position ? pageBefore * PAGE_SIZE : 0;
-
- const {
- data: afterData,
- error: afterError,
- isValidating: loadingAfter,
- } = useSWR<
- HttpResponseOk<TalerMerchantApi.WebhookSummaryResponse>,
- RequestError<TalerErrorDetail>
-
- >([`/private/webhooks`, args?.position, -totalAfter], webhookFetcher);
-
- const [lastAfter, setLastAfter] = useState<
- HttpResponse<
- TalerMerchantApi.WebhookSummaryResponse,
- TalerErrorDetail
- >
- >({ loading: true });
- useEffect(() => {
- if (afterData) setLastAfter(afterData);
- }, [afterData]);
-
- if (afterError) return afterError.cause;
-
- const isReachingEnd =
- afterData && afterData.data.webhooks.length < totalAfter;
- const isReachingStart = true;
-
- const pagination = {
- isReachingEnd,
- isReachingStart,
- loadMore: () => {
- if (!afterData || isReachingEnd) return;
- if (afterData.data.webhooks.length < MAX_RESULT_SIZE) {
- setPageAfter(pageAfter + 1);
- } else {
- const from = `${afterData.data.webhooks[afterData.data.webhooks.length - 1].webhook_id
- }`;
- if (from && updatePosition) updatePosition(from);
- }
+export function revalidateInstanceWebhooks() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "listWebhooks",
+ undefined,
+ { revalidate: true },
+ );
+}
+export function useInstanceWebhooks() {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ const [offset, setOffset] = useState<string | undefined>();
+
+ async function fetcher([token, bid]: [AccessToken, string]) {
+ return await management.listWebhooks(token, {
+ limit: 5,
+ offset: bid,
+ order: "dec",
+ });
+ }
+
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"listWebhooks">,
+ TalerHttpError
+ >([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)
+}
+
+type PaginatedResult<T> = OperationOk<T> & {
+ isLastPage: boolean;
+ isFirstPage: boolean;
+ loadNext(): void;
+ loadFirst(): void;
+}
+
+//TODO: consider sending this to web-util
+export function buildPaginatedResult<R, OffId>(data: R[], offset: OffId | undefined, setOffset: (o: OffId | undefined) => void, getId: (r: R) => OffId): PaginatedResult<R[]> {
+
+ const isLastPage = data.length <= PAGE_SIZE;
+ const isFirstPage = offset === undefined;
+
+ const result = structuredClone(data);
+ if (result.length == PAGE_SIZE + 1) {
+ result.pop();
+ }
+ return {
+ type: "ok",
+ body: result,
+ isLastPage,
+ isFirstPage,
+ loadNext: () => {
+ if (!result.length) return;
+ const id = getId(result[result.length - 1])
+ setOffset(id);
},
- loadMorePrev: () => {
- return;
+ loadFirst: () => {
+ setOffset(undefined);
},
};
+}
- const webhooks = !afterData ? [] : (afterData || lastAfter).data.webhooks;
- if (loadingAfter) return { loading: true, data: { webhooks } };
- if (afterData) {
- return { ok: true, data: { webhooks }, ...pagination };
- }
- return { loading: true };
+export function revalidateWebhookDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getWebhookDetails",
+ undefined,
+ { revalidate: true },
+ );
}
+export function useWebhookDetails(webhookId: string) {
+ const { state: session } = useSessionContext();
+ const { lib: { management } } = useMerchantApiContext();
+
+ async function fetcher([hookId, token]: [string, AccessToken]) {
+ return await management.getWebhookDetails(token, hookId);
+ }
+
+ const { data, error } = useSWR<
+ TalerMerchantManagementResultByMethod<"getWebhookDetails">,
+ TalerHttpError
+ >([webhookId, session.token, "getWebhookDetails"], fetcher);
-export function useWebhookDetails(
- webhookId: string,
-): HttpResponse<
- TalerMerchantApi.WebhookDetails,
- TalerErrorDetail
-> {
- const { webhookFetcher } = useBackendInstanceRequest();
-
- const { data, error, isValidating } = useSWR<
- HttpResponseOk<TalerMerchantApi.WebhookDetails>,
- RequestError<TalerErrorDetail>
- >([`/private/webhooks/${webhookId}`], webhookFetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- });
-
- if (isValidating) return { loading: true, data: data?.data };
if (data) return data;
- if (error) return error.cause;
- return { loading: true };
+ if (error) return error;
+ return undefined;
}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
index 35c9e6624..0ce126b76 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
@@ -46,7 +46,7 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode {
<CreatePage
onBack={onBack}
onCreate={(request: Entity) => {
- return api.management.addAccount(state.token, request)
+ return api.management.addBankAccount(state.token, request)
.then(() => {
onConfirm()
})
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 8de6c763e..ab63d0d5f 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
@@ -19,7 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
+import { HttpStatusCode, TalerError, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
import {
ErrorType,
HttpError,
@@ -34,6 +34,7 @@ import { useInstanceBankAccounts } from "../../../../hooks/bank.js";
import { Notification } from "../../../../utils/types.js";
import { ListPage } from "./ListPage.js";
import { useSessionContext } from "../../../../context/session.js";
+import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js";
interface Props {
onUnauthorized: () => VNode;
@@ -50,32 +51,21 @@ export default function ListOtpDevices({
onSelect,
onNotFound,
}: Props): VNode {
- const [position, setPosition] = useState<string | undefined>(undefined);
const { i18n } = useTranslationContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { lib: api } = useMerchantApiContext();
const { state } = useSessionContext();
- const result = useInstanceBankAccounts({ position }, (id) => setPosition(id));
+ const result = useInstanceBankAccounts();
- if (result.loading) return <Loading />;
- if (!result.ok) {
- if (
- result.type === ErrorType.CLIENT &&
- result.status === HttpStatusCode.Unauthorized
- )
- return onUnauthorized();
- if (
- result.type === ErrorType.CLIENT &&
- result.status === HttpStatusCode.NotFound
- )
- return onNotFound();
- return onLoadError(result);
+ if (!result) return <Loading />
+ if (result instanceof TalerError) {
+ return <ErrorLoadingMerchant error={result} />
}
return (
<Fragment>
<NotificationCard notification={notif} />
- {result.data.accounts.length < 1 &&
+ {result.result.length < 1 &&
<NotificationCard notification={{
type: "WARN",
message: i18n.str`You need to associate a bank account to receive revenue.`,
@@ -83,7 +73,7 @@ export default function ListOtpDevices({
}} />
}
<ListPage
- devices={result.data.accounts}
+ devices={result.result}
onLoadMoreBefore={
result.isReachingStart ? result.loadMorePrev : undefined
}
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 dc2e08d91..ff54c487a 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
@@ -83,7 +83,7 @@ export default function ProductList({
<JumpToElementById
testIfExist={async (id) => {
- const resp = await lib.management.getProduct(state.token, id);
+ const resp = await lib.management.getProductDetails(state.token, id);
return resp.type === "ok";
}}
onSelect={onSelect}
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
index 5fd001555..c223b0a16 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -512,7 +512,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-accounts
*/
- async addAccount(token: AccessToken | undefined, body: TalerMerchantApi.AccountAddDetails) {
+ async addBankAccount(token: AccessToken | undefined, body: TalerMerchantApi.AccountAddDetails) {
const url = new URL(`private/accounts`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -540,7 +540,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-accounts-$H_WIRE
*/
- async updateAccount(
+ async updateBankAccount(
token: AccessToken | undefined,
wireAccount: string,
body: TalerMerchantApi.AccountPatchDetails,
@@ -569,9 +569,11 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts
*/
- async listAccounts(token: AccessToken) {
+ async listBankAccounts(token: AccessToken, params?: PaginationParams) {
const url = new URL(`private/accounts`, this.baseUrl);
+ // addMerchantPaginationParams(url, params);
+
const headers: Record<string, string> = {}
if (token) {
headers.Authorization = makeBearerTokenAuthHeader(token)
@@ -594,7 +596,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts-$H_WIRE
*/
- async getAccount(token: AccessToken | undefined, wireAccount: string) {
+ async getBankAccountDetails(token: AccessToken | undefined, wireAccount: string) {
const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -619,7 +621,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-accounts-$H_WIRE
*/
- async deleteAccount(token: AccessToken | undefined, wireAccount: string) {
+ async deleteBankAccount(token: AccessToken | undefined, wireAccount: string) {
const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -733,7 +735,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products-$PRODUCT_ID
*/
- async getProduct(token: AccessToken | undefined, productId: string) {
+ async getProductDetails(token: AccessToken | undefined, productId: string) {
const url = new URL(`private/products/${productId}`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -902,7 +904,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-orders-$ORDER_ID
*/
- async getOrder(
+ async getOrderDetails(
token: AccessToken | undefined,
orderId: string,
params: TalerMerchantApi.GetOrderRequestParams = {},
@@ -1207,7 +1209,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices
*/
- async listOtpDevices(token: AccessToken | undefined,) {
+ async listOtpDevices(token: AccessToken | undefined, params?: PaginationParams) {
const url = new URL(`private/otp-devices`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1231,7 +1233,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID
*/
- async getOtpDevice(
+ async getOtpDeviceDetails(
token: AccessToken | undefined,
deviceId: string,
params: TalerMerchantApi.GetOtpDeviceRequestParams = {},
@@ -1350,7 +1352,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#inspecting-template
*/
- async listTemplates(token: AccessToken | undefined,) {
+ async listTemplates(token: AccessToken | undefined, params?: PaginationParams) {
const url = new URL(`private/templates`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1374,7 +1376,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID
*/
- async getTemplate(token: AccessToken | undefined, templateId: string) {
+ async getTemplateDetails(token: AccessToken | undefined, templateId: string) {
const url = new URL(`private/templates/${templateId}`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1520,7 +1522,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks
*/
- async listWebhooks(token: AccessToken | undefined,) {
+ async listWebhooks(token: AccessToken | undefined, params?: PaginationParams) {
const url = new URL(`private/webhooks`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1545,7 +1547,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID
*/
- async getWebhook(token: AccessToken | undefined, webhookId: string) {
+ async getWebhookDetails(token: AccessToken | undefined, webhookId: string) {
const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1652,7 +1654,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies
*/
- async listTokenFamilies(token: AccessToken | undefined,) {
+ async listTokenFamilies(token: AccessToken | undefined, params?: PaginationParams) {
const url = new URL(`private/tokenfamilies`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1677,7 +1679,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG
*/
- async getTokenFamily(token: AccessToken | undefined, tokenSlug: string) {
+ async getTokenFamilyDetails(token: AccessToken | undefined, tokenSlug: string) {
const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl);
const headers: Record<string, string> = {}
@@ -1853,7 +1855,7 @@ export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttp
/**
* https://docs.taler.net/core/api-merchant.html#get--management-instances
*/
- async listInstances(token: AccessToken | undefined,) {
+ async listInstances(token: AccessToken | undefined, params?: PaginationParams) {
const url = new URL(`management/instances`, this.baseUrl);
const headers: Record<string, string> = {}