aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/hooks
diff options
context:
space:
mode:
Diffstat (limited to 'packages/demobank-ui/src/hooks')
-rw-r--r--packages/demobank-ui/src/hooks/access.ts36
-rw-r--r--packages/demobank-ui/src/hooks/backend.ts30
-rw-r--r--packages/demobank-ui/src/hooks/bank-state.ts104
-rw-r--r--packages/demobank-ui/src/hooks/circuit.ts20
4 files changed, 143 insertions, 47 deletions
diff --git a/packages/demobank-ui/src/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts
index fc1cff129..80ef1874f 100644
--- a/packages/demobank-ui/src/hooks/access.ts
+++ b/packages/demobank-ui/src/hooks/access.ts
@@ -14,13 +14,13 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AccessToken, TalerBankIntegrationResultByMethod, TalerCoreBankResultByMethod, TalerHttpError, WithdrawalOperationStatus } from "@gnu-taler/taler-util";
+import { AccessToken, TalerCoreBankResultByMethod, TalerHttpError, WithdrawalOperationStatus } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils.js";
import { useBackendState } from "./backend.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import _useSWR, { SWRHook } from "swr";
+import _useSWR, { SWRHook, mutate } from "swr";
import { useBankCoreApiContext } from "../context/config.js";
const useSWR = _useSWR as unknown as SWRHook;
@@ -30,6 +30,10 @@ export interface InstanceTemplateFilter {
position?: string;
}
+export function revalidateAccountDetails() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getAccount", undefined, { revalidate: true })
+}
+
export function useAccountDetails(account: string) {
const { state: credentials } = useBackendState();
const { api } = useBankCoreApiContext();
@@ -40,15 +44,6 @@ export function useAccountDetails(account: string) {
const token = credentials.status !== "loggedIn" ? undefined : credentials.token
const { data, error } = useSWR<TalerCoreBankResultByMethod<"getAccount">, TalerHttpError>(
[account, token, "getAccount"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
});
if (data) return data
@@ -56,6 +51,10 @@ export function useAccountDetails(account: string) {
return undefined;
}
+export function revalidateWithdrawalDetails() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getWithdrawalById")
+}
+
export function useWithdrawalDetails(wid: string) {
const { api } = useBankCoreApiContext();
const [latestStatus, setLatestStatus] = useState<WithdrawalOperationStatus>()
@@ -90,6 +89,9 @@ export function useWithdrawalDetails(wid: string) {
return undefined;
}
+export function revalidateTransactionDetails() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getTransactionById")
+}
export function useTransactionDetails(account: string, tid: number) {
const { state: credentials } = useBackendState();
const token = credentials.status !== "loggedIn" ? undefined : credentials.token
@@ -117,6 +119,9 @@ export function useTransactionDetails(account: string, tid: number) {
return undefined;
}
+export function revalidatePublicAccounts() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getPublicAccounts")
+}
export function usePublicAccounts(filterAccount: string | undefined, initial?: number) {
const [offset, setOffset] = useState<number | undefined>(initial);
const { api } = useBankCoreApiContext();
@@ -171,12 +176,9 @@ export function usePublicAccounts(filterAccount: string | undefined, initial?: n
return undefined;
}
-/**
-
- * @param account
- * @param args
- * @returns
- */
+export function revalidateTransactions() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getTransactions", undefined, { revalidate: true })
+}
export function useTransactions(account: string, initial?: number) {
const { state: credentials } = useBackendState();
const token = credentials.status !== "loggedIn" ? undefined : credentials.token
diff --git a/packages/demobank-ui/src/hooks/backend.ts b/packages/demobank-ui/src/hooks/backend.ts
index 863b47bf3..46918ac10 100644
--- a/packages/demobank-ui/src/hooks/backend.ts
+++ b/packages/demobank-ui/src/hooks/backend.ts
@@ -19,16 +19,15 @@ import {
Codec,
buildCodecForObject,
buildCodecForUnion,
- canonicalizeBaseUrl,
codecForBoolean,
codecForConstString,
- codecForString,
+ codecForString
} from "@gnu-taler/taler-util";
import {
buildStorageKey,
useLocalStorage
} from "@gnu-taler/web-util/browser";
-import { useSWRConfig } from "swr";
+import { mutate } from "swr";
/**
* Has the information to reach and
@@ -105,7 +104,6 @@ export function useBackendState(): BackendStateHandler {
BACKEND_STATE_KEY,
defaultState,
);
- const mutateAll = useMatchMutate();
return {
state,
@@ -129,29 +127,11 @@ export function useBackendState(): BackendStateHandler {
isUserAdministrator: info.username === "admin",
};
update(nextState);
- mutateAll(/.*/)
+ cleanAllCache()
},
};
}
-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, value?: unknown) {
- const allKeys = Array.from(cache.keys());
- const keys = allKeys.filter((key) => re.test(key));
- const mutations = keys.map((key) => {
- return mutate(key, value, true);
- });
- return Promise.all(mutations);
- };
+function cleanAllCache(): void {
+ mutate(() => true, undefined, { revalidate: false })
}
diff --git a/packages/demobank-ui/src/hooks/bank-state.ts b/packages/demobank-ui/src/hooks/bank-state.ts
index addbbfc0f..99d835c9c 100644
--- a/packages/demobank-ui/src/hooks/bank-state.ts
+++ b/packages/demobank-ui/src/hooks/bank-state.ts
@@ -15,31 +15,127 @@
*/
import {
+ AbsoluteTime,
Codec,
+ TalerCorebankApi,
buildCodecForObject,
+ buildCodecForUnion,
+ codecForAbsoluteTime,
+ codecForAny,
+ codecForConstString,
codecForString,
+ codecForTanTransmission,
codecOptional
} from "@gnu-taler/taler-util";
import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
+export type ChallengeInProgess =
+ DeleteAccountChallenge |
+ UpdateAccountChallenge |
+ UpdatePasswordChallenge |
+ CreateTransactionChallenge |
+ ConfirmWithdrawalChallenge |
+ CashoutChallenge;
+
+type BaseChallenge<OpType extends string, ReqType> = {
+ id: string,
+ operation: OpType,
+ sent: AbsoluteTime,
+ info?: TalerCorebankApi.TanTransmission,
+ request: ReqType
+}
+
+type DeleteAccountChallenge = BaseChallenge<"delete-account", string>
+type UpdateAccountChallenge = BaseChallenge<"update-account", TalerCorebankApi.AccountReconfiguration>
+type UpdatePasswordChallenge = BaseChallenge<"update-password", TalerCorebankApi.AccountPasswordChange>
+type CreateTransactionChallenge = BaseChallenge<"create-transaction", TalerCorebankApi.CreateTransactionRequest>
+type ConfirmWithdrawalChallenge = BaseChallenge<"confirm-withdrawal", string>
+type CashoutChallenge = BaseChallenge<"create-cashout", TalerCorebankApi.CashoutRequest>
+
+const codecForChallengeUpdatePassword = (): Codec<UpdatePasswordChallenge> =>
+ buildCodecForObject<UpdatePasswordChallenge>()
+ .property("operation", codecForConstString("update-password"))
+ .property("id", codecForString())
+ .property("sent", codecForAbsoluteTime)
+ .property("info", codecOptional(codecForTanTransmission()))
+ .property("request", codecForAny())
+ .build("UpdatePasswordChallenge");
+
+const codecForChallengeDeleteAccount = (): Codec<DeleteAccountChallenge> =>
+ buildCodecForObject<DeleteAccountChallenge>()
+ .property("operation", codecForConstString("delete-account"))
+ .property("id", codecForString())
+ .property("sent", codecForAbsoluteTime)
+ .property("request", codecForString())
+ .property("info", codecOptional(codecForTanTransmission()))
+ .build("DeleteAccountChallenge");
+
+const codecForChallengeUpdateAccount = (): Codec<UpdateAccountChallenge> =>
+ buildCodecForObject<UpdateAccountChallenge>()
+ .property("operation", codecForConstString("update-account"))
+ .property("id", codecForString())
+ .property("sent", codecForAbsoluteTime)
+ .property("info", codecOptional(codecForTanTransmission()))
+ .property("request", codecForAny())
+ .build("UpdateAccountChallenge");
+
+const codecForChallengeCreateTransaction = (): Codec<CreateTransactionChallenge> =>
+ buildCodecForObject<CreateTransactionChallenge>()
+ .property("operation", codecForConstString("create-transaction"))
+ .property("id", codecForString())
+ .property("sent", codecForAbsoluteTime)
+ .property("info", codecOptional(codecForTanTransmission()))
+ .property("request", codecForAny())
+ .build("CreateTransactionChallenge");
+
+const codecForChallengeConfirmWithdrawal = (): Codec<ConfirmWithdrawalChallenge> =>
+ buildCodecForObject<ConfirmWithdrawalChallenge>()
+ .property("operation", codecForConstString("confirm-withdrawal"))
+ .property("id", codecForString())
+ .property("sent", codecForAbsoluteTime)
+ .property("info", codecOptional(codecForTanTransmission()))
+ .property("request", codecForString())
+ .build("ConfirmWithdrawalChallenge");
+
+const codecForChallengeCashout = (): Codec<CashoutChallenge> =>
+ buildCodecForObject<CashoutChallenge>()
+ .property("operation", codecForConstString("create-cashout"))
+ .property("id", codecForString())
+ .property("sent", codecForAbsoluteTime)
+ .property("info", codecOptional(codecForTanTransmission()))
+ .property("request", codecForAny())
+ .build("CashoutChallenge");
+
+const codecForChallenge = (): Codec<ChallengeInProgess> =>
+ buildCodecForUnion<ChallengeInProgess>()
+ .discriminateOn("operation")
+ .alternative("confirm-withdrawal", codecForChallengeConfirmWithdrawal())
+ .alternative("create-cashout", codecForChallengeCashout())
+ .alternative("create-transaction", codecForChallengeCreateTransaction())
+ .alternative("delete-account", codecForChallengeDeleteAccount())
+ .alternative("update-account", codecForChallengeUpdateAccount())
+ .alternative("update-password", codecForChallengeUpdatePassword())
+ .build("ChallengeInProgess");
+
+
interface BankState {
currentWithdrawalOperationId: string | undefined;
- currentChallengeId: string | undefined;
+ currentChallenge: ChallengeInProgess | undefined;
}
export const codecForBankState = (): Codec<BankState> =>
buildCodecForObject<BankState>()
.property("currentWithdrawalOperationId", codecOptional(codecForString()))
- .property("currentChallengeId", codecOptional(codecForString()))
+ .property("currentChallenge", codecOptional(codecForChallenge()))
.build("BankState");
const defaultBankState: BankState = {
currentWithdrawalOperationId: undefined,
- currentChallengeId: undefined,
+ currentChallenge: undefined,
};
const BANK_STATE_KEY = buildStorageKey(
- "bank-state",
+ "bank-app-state",
codecForBankState(),
);
diff --git a/packages/demobank-ui/src/hooks/circuit.ts b/packages/demobank-ui/src/hooks/circuit.ts
index 8a27f652c..8bff6858d 100644
--- a/packages/demobank-ui/src/hooks/circuit.ts
+++ b/packages/demobank-ui/src/hooks/circuit.ts
@@ -19,7 +19,7 @@ import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils.js";
import { useBackendState } from "./backend.js";
import { AccessToken, AmountJson, AmountString, Amounts, OperationOk, TalerBankConversionResultByMethod, TalerCoreBankErrorsByMethod, TalerCoreBankResultByMethod, TalerCorebankApi, TalerError, TalerHttpError, opFixedSuccess } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook } from "swr";
+import _useSWR, { SWRHook, mutate } from "swr";
import { useBankCoreApiContext } from "../context/config.js";
import { assertUnreachable } from "../pages/WithdrawalOperationPage.js";
import { format, getDate, getDay, getHours, getMonth, getYear, set, sub } from "date-fns";
@@ -42,6 +42,9 @@ type CashoutEstimators = {
estimateByDebit: EstimatorFunction;
};
+export function revalidateConversionInfo() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getConversionInfoAPI")
+}
export function useConversionInfo() {
const { api, config } = useBankCoreApiContext()
@@ -114,6 +117,9 @@ export function useEstimator(): CashoutEstimators {
};
}
+export function revalidateBusinessAccounts() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getAccounts")
+}
export function useBusinessAccounts() {
const { state: credentials } = useBackendState();
const token = credentials.status !== "loggedIn" ? undefined : credentials.token
@@ -174,6 +180,9 @@ type CashoutWithId = TalerCorebankApi.CashoutStatusResponse & { id: number }
function notUndefined(c: CashoutWithId | undefined): c is CashoutWithId {
return c !== undefined
}
+export function revalidateOnePendingCashouts() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "useOnePendingCashouts")
+}
export function useOnePendingCashouts(account: string) {
const { state: credentials } = useBackendState();
const { api, config } = useBankCoreApiContext();
@@ -211,6 +220,9 @@ export function useOnePendingCashouts(account: string) {
return undefined;
}
+export function revalidateCashouts() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "useCashouts")
+}
export function useCashouts(account: string) {
const { state: credentials } = useBackendState();
const { api, config } = useBankCoreApiContext();
@@ -251,6 +263,9 @@ export function useCashouts(account: string) {
return undefined;
}
+export function revalidateCashoutDetails() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "getCashoutById")
+}
export function useCashoutDetails(cashoutId: number | undefined) {
const { state: credentials } = useBackendState();
const creds = credentials.status !== "loggedIn" ? undefined : credentials
@@ -284,6 +299,9 @@ export type MonitorMetrics = {
}
export type LastMonitor = { current: TalerCoreBankResultByMethod<"getMonitor">, previous: TalerCoreBankResultByMethod<"getMonitor"> }
+export function revalidateLastMonitorInfo() {
+ mutate(key => Array.isArray(key) && key[key.length - 1] === "useLastMonitorInfo")
+}
export function useLastMonitorInfo(currentMoment: number, previousMoment: number, timeframe: TalerCorebankApi.MonitorTimeframeParam) {
const { api, config } = useBankCoreApiContext();
const { state: credentials } = useBackendState();