diff options
author | Christian Blättler <blatc2@bfh.ch> | 2024-05-01 08:00:06 +0200 |
---|---|---|
committer | Christian Blättler <blatc2@bfh.ch> | 2024-05-01 08:00:06 +0200 |
commit | 8d1ce9dae1fd94204c142ac599b498bec9680b6c (patch) | |
tree | fc6a55104ca6a457d67336db5757ec442824e074 /packages/bank-ui/src/hooks/account.ts | |
parent | 09046010252b134348de8b18c0c99ffea4e3c95d (diff) | |
parent | 20d2861508df18da18e66c94a5a268067565121b (diff) | |
download | wallet-core-8d1ce9dae1fd94204c142ac599b498bec9680b6c.tar.xz |
Merge branch 'master' into feature/tokens
# Conflicts:
# packages/auditor-backoffice-ui/src/InstanceRoutes.tsx
# packages/merchant-backoffice-ui/src/declaration.d.ts
# packages/merchant-backoffice-ui/src/schemas/index.ts
Diffstat (limited to 'packages/bank-ui/src/hooks/account.ts')
-rw-r--r-- | packages/bank-ui/src/hooks/account.ts | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/packages/bank-ui/src/hooks/account.ts b/packages/bank-ui/src/hooks/account.ts new file mode 100644 index 000000000..43d43a3f2 --- /dev/null +++ b/packages/bank-ui/src/hooks/account.ts @@ -0,0 +1,313 @@ +/* + This file is part of GNU Taler + (C) 2022-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/> + */ + +import { + AccessToken, + OperationOk, + TalerCoreBankResultByMethod, + TalerHttpError, + WithdrawalOperationStatus, +} from "@gnu-taler/taler-util"; +import { useEffect, useState } from "preact/hooks"; +import { useSessionState } from "./session.js"; + +// FIX default import https://github.com/microsoft/TypeScript/issues/49189 +import _useSWR, { SWRHook, mutate } from "swr"; +import { useBankCoreApiContext } from "@gnu-taler/web-util/browser"; +import { PAGINATED_LIST_REQUEST } from "../utils.js"; +const useSWR = _useSWR as unknown as SWRHook; + +export interface InstanceTemplateFilter { + // FIXME: add filter to the template list + position?: string; +} + +export function revalidateAccountDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getAccount", + undefined, + { revalidate: true }, + ); +} + +export function useAccountDetails(account: string) { + const { state: credentials } = useSessionState(); + const { + lib: { bank: api }, + } = useBankCoreApiContext(); + + async function fetcher([username, token]: [string, AccessToken]) { + return await api.getAccount({ username, token }); + } + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getAccount">, + TalerHttpError + >([account, token, "getAccount"], fetcher, {}); + + if (data) return data; + if (error) return error; + return undefined; +} + +export function revalidateWithdrawalDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getWithdrawalById", + undefined, + { revalidate: true }, + ); +} + +export function useWithdrawalDetails(wid: string) { + const { + lib: { bank: api }, + } = useBankCoreApiContext(); + const [latestStatus, setLatestStatus] = useState<WithdrawalOperationStatus>(); + + async function fetcher([wid, old_state]: [ + string, + WithdrawalOperationStatus | undefined, + ]) { + return await api.getWithdrawalById( + wid, + old_state === undefined ? undefined : { old_state, timeoutMs: 15000 }, + ); + } + + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getWithdrawalById">, + TalerHttpError + >([wid, latestStatus, "getWithdrawalById"], fetcher, { + refreshInterval: 3000, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + keepPreviousData: true, + }); + + const currentStatus = + data !== undefined && data.type === "ok" ? data.body.status : undefined; + + useEffect(() => { + if (currentStatus !== undefined && currentStatus !== latestStatus) { + setLatestStatus(currentStatus); + } + }, [currentStatus]); + + if (data) return data; + if (error) return error; + return undefined; +} + +export function revalidateTransactionDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getTransactionById", + undefined, + { revalidate: true }, + ); +} +export function useTransactionDetails(account: string, tid: number) { + const { state: credentials } = useSessionState(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + const { + lib: { bank: api }, + } = useBankCoreApiContext(); + + async function fetcher([username, token, txid]: [ + string, + AccessToken, + number, + ]) { + return await api.getTransactionById({ username, token }, txid); + } + + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getTransactionById">, + TalerHttpError + >([account, token, tid, "getTransactionById"], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + keepPreviousData: true, + }); + + if (data) return data; + if (error) return error; + return undefined; +} + +export async function revalidatePublicAccounts() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getPublicAccounts", + undefined, + { revalidate: true }, + ); +} +export function usePublicAccounts( + filterAccount: string | undefined, + initial?: number, +) { + const [offset, setOffset] = useState<number | undefined>(initial); + + const { + lib: { bank: api }, + } = useBankCoreApiContext(); + + async function fetcher([account, txid]: [ + string | undefined, + number | undefined, + ]) { + return await api.getPublicAccounts( + { account }, + { + limit: PAGINATED_LIST_REQUEST, + offset: txid ? String(txid) : undefined, + order: "asc", + }, + ); + } + + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getPublicAccounts">, + TalerHttpError + >([filterAccount, offset, "getPublicAccounts"], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + keepPreviousData: true, + }); + + 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, + ); +} + +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 < PAGINATED_LIST_REQUEST; + const isFirstPage = offset === undefined; + + const result = structuredClone(data); + if (result.length == PAGINATED_LIST_REQUEST) { + //do now show the last element, used to know if this is the last page + result.pop(); + } + return { + type: "ok", + body: result, + isLastPage, + isFirstPage, + loadNext: () => { + if (!result.length) return; + const id = getId(result[result.length - 1]); + setOffset(id); + }, + loadFirst: () => { + setOffset(undefined); + }, + }; +} + +export function revalidateTransactions() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getTransactions", + undefined, + { revalidate: true }, + ); +} +export function useTransactions(account: string, initial?: number) { + const { state: credentials } = useSessionState(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + + const [offset, setOffset] = useState<number | undefined>(initial); + const { + lib: { bank: api }, + } = useBankCoreApiContext(); + + async function fetcher([username, token, txid]: [ + string, + AccessToken, + number | undefined, + ]) { + return await api.getTransactions( + { username, token }, + { + limit: PAGINATED_LIST_REQUEST, + offset: txid ? String(txid) : undefined, + order: "dec", + }, + ); + } + + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getTransactions">, + TalerHttpError + >([account, token, offset, "getTransactions"], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + refreshWhenOffline: false, + // revalidateOnMount: false, + revalidateIfStale: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + }); + if (error) return error; + if (data === undefined) return undefined; + if (data.type !== "ok") return data; + + return buildPaginatedResult( + data.body.transactions, + offset, + setOffset, + (d) => d.row_id, + ); +} |