diff options
author | Sebastian <sebasjm@gmail.com> | 2024-03-08 09:20:02 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-03-08 09:20:11 -0300 |
commit | 2a4dbc67e8d1e6a256431e34f0b2e0e19d204f70 (patch) | |
tree | 67fdb4e1eefee6ec36727d616fba611def822864 /packages/demobank-ui/src/hooks/regional.ts | |
parent | 64dea5e94086d8f79d1af7e5b7ee045d72d02495 (diff) | |
download | wallet-core-2a4dbc67e8d1e6a256431e34f0b2e0e19d204f70.tar.xz |
remove dead code
Diffstat (limited to 'packages/demobank-ui/src/hooks/regional.ts')
-rw-r--r-- | packages/demobank-ui/src/hooks/regional.ts | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/packages/demobank-ui/src/hooks/regional.ts b/packages/demobank-ui/src/hooks/regional.ts new file mode 100644 index 000000000..a9ebb30a2 --- /dev/null +++ b/packages/demobank-ui/src/hooks/regional.ts @@ -0,0 +1,484 @@ +/* + 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 { PAGE_SIZE } from "../utils.js"; +import { useSessionState } from "./session.js"; + +import { + AccessToken, + AmountJson, + Amounts, + HttpStatusCode, + OperationOk, + TalerBankConversionResultByMethod, + TalerCoreBankErrorsByMethod, + TalerCoreBankResultByMethod, + TalerCorebankApi, + TalerError, + TalerHttpError, + opFixedSuccess, +} from "@gnu-taler/taler-util"; +import _useSWR, { SWRHook, mutate } from "swr"; +import { useBankCoreApiContext } from "../context/config.js"; +import { useState } from "preact/hooks"; + +// FIX default import https://github.com/microsoft/TypeScript/issues/49189 +const useSWR = _useSWR as unknown as SWRHook; + +export type TransferCalculation = { + debit: AmountJson; + credit: AmountJson; + beforeFee: AmountJson; +} | "amount-is-too-small"; +type EstimatorFunction = ( + amount: AmountJson, + fee: AmountJson, +) => Promise<TransferCalculation>; + +type ConversionEstimators = { + estimateByCredit: EstimatorFunction; + estimateByDebit: EstimatorFunction; +}; + +export function revalidateConversionInfo() { + return mutate( + (key) => + Array.isArray(key) && key[key.length - 1] === "getConversionInfoAPI", + ); +} +export function useConversionInfo() { + const { api, config } = useBankCoreApiContext(); + + async function fetcher() { + return await api.getConversionInfoAPI().getConfig(); + } + const { data, error } = useSWR< + TalerBankConversionResultByMethod<"getConfig">, + TalerHttpError + >(!config.allow_conversion ? undefined : ["getConversionInfoAPI"], 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 useCashinEstimator(): ConversionEstimators { + const { api } = useBankCoreApiContext(); + return { + estimateByCredit: async (fiatAmount, fee) => { + const resp = await api.getConversionInfoAPI().getCashinRate({ + credit: fiatAmount, + }); + if (resp.type === "fail") { + switch (resp.case) { + case HttpStatusCode.Conflict: { + return "amount-is-too-small" + } + // this below can't happen + case HttpStatusCode.NotImplemented: //it should not be able to call this function + case HttpStatusCode.BadRequest: //we are using just one parameter + throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + } + } + const credit = Amounts.parseOrThrow(resp.body.amount_credit); + const debit = Amounts.parseOrThrow(resp.body.amount_debit); + const beforeFee = Amounts.sub(credit, fee).amount; + + return { + debit, + beforeFee, + credit, + }; + }, + estimateByDebit: async (regionalAmount, fee) => { + const resp = await api.getConversionInfoAPI().getCashinRate({ + debit: regionalAmount, + }); + if (resp.type === "fail") { + switch (resp.case) { + case HttpStatusCode.Conflict: { + return "amount-is-too-small" + } + // this below can't happen + case HttpStatusCode.NotImplemented: //it should not be able to call this function + case HttpStatusCode.BadRequest: //we are using just one parameter + throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + } + } + const credit = Amounts.parseOrThrow(resp.body.amount_credit); + const debit = Amounts.parseOrThrow(resp.body.amount_debit); + const beforeFee = Amounts.add(credit, fee).amount; + + return { + debit, + beforeFee, + credit, + }; + }, + }; +} + +export function useCashoutEstimator(): ConversionEstimators { + const { api } = useBankCoreApiContext(); + return { + estimateByCredit: async (fiatAmount, fee) => { + const resp = await api.getConversionInfoAPI().getCashoutRate({ + credit: fiatAmount, + }); + if (resp.type === "fail") { + switch (resp.case) { + case HttpStatusCode.Conflict: { + return "amount-is-too-small" + } + // this below can't happen + case HttpStatusCode.NotImplemented: //it should not be able to call this function + case HttpStatusCode.BadRequest: //we are using just one parameter + throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + } + } + const credit = Amounts.parseOrThrow(resp.body.amount_credit); + const debit = Amounts.parseOrThrow(resp.body.amount_debit); + const beforeFee = Amounts.sub(credit, fee).amount; + + return { + debit, + beforeFee, + credit, + }; + }, + estimateByDebit: async (regionalAmount, fee) => { + const resp = await api.getConversionInfoAPI().getCashoutRate({ + debit: regionalAmount, + }); + if (resp.type === "fail") { + switch (resp.case) { + case HttpStatusCode.Conflict: { + return "amount-is-too-small" + } + // this below can't happen + case HttpStatusCode.NotImplemented: //it should not be able to call this function + case HttpStatusCode.BadRequest: //we are using just one parameter + throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + } + } + const credit = Amounts.parseOrThrow(resp.body.amount_credit); + const debit = Amounts.parseOrThrow(resp.body.amount_debit); + const beforeFee = Amounts.add(credit, fee).amount; + + return { + debit, + beforeFee, + credit, + }; + }, + }; +} + +/** + * @deprecated use useCashoutEstimator + */ +export function useEstimator(): ConversionEstimators { + return useCashoutEstimator() +} + +export function revalidateBusinessAccounts() { + return mutate((key) => Array.isArray(key) && key[key.length - 1] === "getAccounts", undefined, { revalidate: true }); +} +export function useBusinessAccounts() { + const { state: credentials } = useSessionState(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + const { api } = useBankCoreApiContext(); + + const [offset, setOffset] = useState<number | undefined>(); + + function fetcher([token, offset]: [AccessToken, number]) { + // FIXME: add account name filter + return api.getAccounts( + token, + {}, + { + limit: PAGE_SIZE + 1, + offset: String(offset), + order: "asc", + }, + ); + } + + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getAccounts">, + TalerHttpError + >([token, offset ?? 0, "getAccounts"], 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.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 = { + 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; +} + +type CashoutWithId = TalerCorebankApi.CashoutStatusResponse & { id: number }; +function notUndefined(c: CashoutWithId | undefined): c is CashoutWithId { + return c !== undefined; +} +export function revalidateOnePendingCashouts() { + return mutate( + (key) => + Array.isArray(key) && key[key.length - 1] === "useOnePendingCashouts", undefined, { revalidate: true } + ); +} +export function useOnePendingCashouts(account: string) { + const { state: credentials } = useSessionState(); + const { api, config } = useBankCoreApiContext(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + + async function fetcher([username, token]: [string, AccessToken]) { + const list = await api.getAccountCashouts({ username, token }); + if (list.type !== "ok") { + return list; + } + const pendingCashout = list.body.cashouts.length > 0 ? list.body.cashouts[0] : undefined; + if (!pendingCashout) return opFixedSuccess(list.httpResp, undefined); + const cashoutInfo = await api.getCashoutById( + { username, token }, + pendingCashout.cashout_id, + ); + if (cashoutInfo.type !== "ok") { + return cashoutInfo; + } + return opFixedSuccess(list.httpResp, { + ...cashoutInfo.body, + id: pendingCashout.cashout_id, + }); + } + + const { data, error } = useSWR< + | OperationOk<CashoutWithId | undefined> + | TalerCoreBankErrorsByMethod<"getAccountCashouts"> + | TalerCoreBankErrorsByMethod<"getCashoutById">, + TalerHttpError + >( + !config.allow_conversion + ? undefined + : [account, token, "useOnePendingCashouts"], + 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 revalidateCashouts() { + return mutate((key) => Array.isArray(key) && key[key.length - 1] === "useCashouts"); +} +export function useCashouts(account: string) { + const { state: credentials } = useSessionState(); + const { api, config } = useBankCoreApiContext(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + + async function fetcher([username, token]: [string, AccessToken]) { + const list = await api.getAccountCashouts({ username, token }); + if (list.type !== "ok") { + return list; + } + const all: Array<CashoutWithId | undefined> = await Promise.all( + list.body.cashouts.map(async (c) => { + const r = await api.getCashoutById({ username, token }, c.cashout_id); + if (r.type === "fail") { + return undefined; + } + return { ...r.body, id: c.cashout_id }; + }), + ); + const cashouts = all.filter(notUndefined); + return { type: "ok" as const, body: { cashouts }, httpResp: list.httpResp }; + } + const { data, error } = useSWR< + | OperationOk<{ cashouts: CashoutWithId[] }> + | TalerCoreBankErrorsByMethod<"getAccountCashouts">, + TalerHttpError + >( + !config.allow_conversion ? undefined : [account, token, "useCashouts"], + 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 revalidateCashoutDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getCashoutById", undefined, { revalidate: true } + ); +} +export function useCashoutDetails(cashoutId: number | undefined) { + const { state: credentials } = useSessionState(); + const creds = credentials.status !== "loggedIn" ? undefined : credentials; + const { api } = useBankCoreApiContext(); + + async function fetcher([username, token, id]: [string, AccessToken, number]) { + return api.getCashoutById({ username, token }, id); + } + + const { data, error } = useSWR< + TalerCoreBankResultByMethod<"getCashoutById">, + TalerHttpError + >( + cashoutId === undefined + ? undefined + : [creds?.username, creds?.token, cashoutId, "getCashoutById"], + 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 type MonitorMetrics = { + lastHour: TalerCoreBankResultByMethod<"getMonitor">; + lastDay: TalerCoreBankResultByMethod<"getMonitor">; + lastMonth: TalerCoreBankResultByMethod<"getMonitor">; +}; + +export type LastMonitor = { + current: TalerCoreBankResultByMethod<"getMonitor">; + previous: TalerCoreBankResultByMethod<"getMonitor">; +}; +export function revalidateLastMonitorInfo() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "useLastMonitorInfo", undefined, { revalidate: true } + ); +} +export function useLastMonitorInfo( + currentMoment: number, + previousMoment: number, + timeframe: TalerCorebankApi.MonitorTimeframeParam, +) { + const { api } = useBankCoreApiContext(); + const { state: credentials } = useSessionState(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + + async function fetcher([token, timeframe]: [ + AccessToken, + TalerCorebankApi.MonitorTimeframeParam, + ]) { + const [current, previous] = await Promise.all([ + api.getMonitor(token, { timeframe, which: currentMoment }), + api.getMonitor(token, { timeframe, which: previousMoment }), + ]); + return { + current, + previous, + }; + } + + const { data, error } = useSWR<LastMonitor, TalerHttpError>( + !token ? undefined : [token, timeframe, "useLastMonitorInfo"], + 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; +} |