diff options
Diffstat (limited to 'packages/demobank-ui/src/hooks/account.ts')
-rw-r--r-- | packages/demobank-ui/src/hooks/account.ts | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/packages/demobank-ui/src/hooks/account.ts b/packages/demobank-ui/src/hooks/account.ts new file mode 100644 index 000000000..61a11b1a5 --- /dev/null +++ b/packages/demobank-ui/src/hooks/account.ts @@ -0,0 +1,294 @@ +/* + 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, + TalerCoreBankResultByMethod, + TalerHttpError, + WithdrawalOperationStatus, +} from "@gnu-taler/taler-util"; +import { useEffect, useState } from "preact/hooks"; +import { PAGE_SIZE } from "../utils.js"; +import { useSessionState } from "./session.js"; + +// FIX default import https://github.com/microsoft/TypeScript/issues/49189 +import _useSWR, { SWRHook, mutate } from "swr"; +import { useBankCoreApiContext } from "../context/config.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 { 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 { 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 { 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 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 { api } = useBankCoreApiContext(); + + async function fetcher([account, txid]: [ + string | undefined, + number | undefined, + ]) { + return await api.getPublicAccounts( + { account }, + { + limit: PAGE_SIZE, + 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, + }); + + const isLastPage = + data && data.type === "ok" && data.body.public_accounts.length <= PAGE_SIZE; + const isFirstPage = !offset; + + const result = data && data.type == "ok" ? structuredClone(data.body.public_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); + }, + }; + + // 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() { + 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 { api } = useBankCoreApiContext(); + + async function fetcher([username, token, txid]: [ + string, + AccessToken, + number | undefined, + ]) { + return await api.getTransactions( + { username, token }, + { + limit: PAGE_SIZE +1 , + 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, + }); + + 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); + }, + }; + + if (data) { + return { ok: true, data, ...pagination }; + } + if (error) { + return error; + } + return undefined; +} |