summaryrefslogtreecommitdiff
path: root/packages/bank-ui/src/context/config.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/bank-ui/src/context/config.ts')
-rw-r--r--packages/bank-ui/src/context/config.ts263
1 files changed, 263 insertions, 0 deletions
diff --git a/packages/bank-ui/src/context/config.ts b/packages/bank-ui/src/context/config.ts
new file mode 100644
index 000000000..39d12be86
--- /dev/null
+++ b/packages/bank-ui/src/context/config.ts
@@ -0,0 +1,263 @@
+/*
+ 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 {
+ assertUnreachable,
+ LibtoolVersion,
+ TalerBankConversionCacheEviction,
+ TalerBankConversionHttpClient,
+ TalerCorebankApi,
+ TalerAuthenticationHttpClient,
+ TalerCoreBankCacheEviction,
+ TalerCoreBankHttpClient,
+ TalerError
+} from "@gnu-taler/taler-util";
+import {
+ BrowserHttpLib,
+ ErrorLoading,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import {
+ ComponentChildren,
+ createContext,
+ FunctionComponent,
+ h,
+ VNode,
+} from "preact";
+import { useContext, useEffect, useState } from "preact/hooks";
+import {
+ revalidateAccountDetails,
+ revalidatePublicAccounts,
+ revalidateTransactions,
+} from "../hooks/account.js";
+import {
+ revalidateBusinessAccounts,
+ revalidateCashouts,
+ revalidateConversionInfo,
+} from "../hooks/regional.js";
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+export type Type = {
+ url: URL;
+ config: TalerCorebankApi.Config;
+ bank: TalerCoreBankHttpClient;
+ conversion: TalerBankConversionHttpClient;
+ authenticator: (user: string) => TalerAuthenticationHttpClient;
+ hints: VersionHint[];
+};
+
+// FIXME: below
+// @ts-expect-error default value to undefined, should it be another thing?
+const Context = createContext<Type>(undefined);
+
+export const useBankCoreApiContext = (): Type => useContext(Context);
+
+export enum VersionHint {
+ /**
+ * when this flag is on, server is running an old version with cashout before implementing 2fa API
+ */
+ CASHOUT_BEFORE_2FA,
+}
+
+export type ConfigResult =
+ | undefined
+ | { type: "ok"; config: TalerCorebankApi.Config; hints: VersionHint[] }
+ | { type: "incompatible"; result: TalerCorebankApi.Config; supported: string }
+ | { type: "error"; error: TalerError };
+
+export const BankCoreApiProvider = ({
+ baseUrl,
+ children,
+ frameOnError,
+}: {
+ baseUrl: string;
+ children: ComponentChildren;
+ frameOnError: FunctionComponent<{ children: ComponentChildren }>;
+}): VNode => {
+ const [checked, setChecked] = useState<ConfigResult>();
+ const { i18n } = useTranslationContext();
+
+ const { bankClient, conversionClient, authClient } = buildApiClient(new URL(baseUrl))
+
+ useEffect(() => {
+ bankClient
+ .getConfig()
+ .then((resp) => {
+ if (bankClient.isCompatible(resp.body.version)) {
+ setChecked({ type: "ok", config: resp.body, hints: [] });
+ } else {
+ // this API supports version 3.0.3
+ const compare = LibtoolVersion.compare("3:0:3", resp.body.version);
+ if (compare?.compatible ?? false) {
+ setChecked({
+ type: "ok",
+ config: resp.body,
+ hints: [VersionHint.CASHOUT_BEFORE_2FA],
+ });
+ } else {
+ setChecked({
+ type: "incompatible",
+ result: resp.body,
+ supported: bankClient.PROTOCOL_VERSION,
+ });
+ }
+ }
+ })
+ .catch((error: unknown) => {
+ if (error instanceof TalerError) {
+ setChecked({ type: "error", error });
+ }
+ });
+ }, []);
+
+ if (checked === undefined) {
+ return h(frameOnError, { children: h("div", {}, "loading...") });
+ }
+ if (checked.type === "error") {
+ return h(frameOnError, {
+ children: h(ErrorLoading, { error: checked.error, showDetail: true }),
+ });
+ }
+ if (checked.type === "incompatible") {
+ return h(frameOnError, {
+ children: h(
+ "div",
+ {},
+ i18n.str`The bank backend is not supported. Supported version "${checked.supported}", server version "${checked.result.version}"`,
+ ),
+ });
+ }
+ const value: Type = {
+ url: new URL(bankClient.baseUrl),
+ config: checked.config,
+ bank: bankClient,
+ conversion: conversionClient,
+ authenticator: authClient,
+ hints: checked.hints,
+ };
+ return h(Context.Provider, {
+ value,
+ children,
+ });
+};
+
+/**
+ * build http client with cache breaker due to SWR
+ * @param url
+ * @returns
+ */
+function buildApiClient(url: URL) {
+ const httpLib = new BrowserHttpLib();
+
+ const bankClient = new TalerCoreBankHttpClient(url.href, httpLib, {
+ async notifySuccess(op) {
+ switch (op) {
+ case TalerCoreBankCacheEviction.DELELE_ACCOUNT: {
+ await Promise.all([
+ revalidatePublicAccounts(),
+ revalidateBusinessAccounts(),
+ ]);
+ return
+ }
+ case TalerCoreBankCacheEviction.CREATE_ACCOUNT: {
+ // admin balance change on new account
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateTransactions(),
+ revalidatePublicAccounts(),
+ revalidateBusinessAccounts(),
+ ])
+ return;
+ }
+ case TalerCoreBankCacheEviction.UPDATE_ACCOUNT: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ ])
+ return;
+ }
+ case TalerCoreBankCacheEviction.CREATE_TRANSACTION: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateTransactions(),
+ ])
+ return;
+ }
+ case TalerCoreBankCacheEviction.CONFIRM_WITHDRAWAL: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateTransactions(),
+ ])
+ return;
+ }
+ case TalerCoreBankCacheEviction.CREATE_CASHOUT: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateCashouts(),
+ revalidateTransactions(),
+ ])
+ return;
+ }
+ case TalerCoreBankCacheEviction.UPDATE_PASSWORD:
+ case TalerCoreBankCacheEviction.ABORT_WITHDRAWAL:
+ case TalerCoreBankCacheEviction.CREATE_WITHDRAWAL:
+ return;
+ default:
+ assertUnreachable(op)
+ }
+ }
+ });
+ const conversionClient = new TalerBankConversionHttpClient(bankClient.getConversionInfoAPI(), httpLib, {
+ async notifySuccess(op) {
+ switch (op) {
+ case TalerBankConversionCacheEviction.UPDATE_RATE: {
+ await revalidateConversionInfo();
+ return
+ }
+ default:
+ assertUnreachable(op)
+ }
+ }
+ });
+ const authClient = (user: string) => new TalerAuthenticationHttpClient(bankClient.getAuthenticationAPI(user), user, httpLib);
+ return { bankClient, conversionClient, authClient }
+}
+
+export const BankCoreApiProviderTesting = ({
+ children,
+ state,
+ url,
+}: {
+ children: ComponentChildren;
+ state: TalerCorebankApi.Config;
+ url: string;
+}): VNode => {
+ const value: Type = {
+ url: new URL(url),
+ config: state,
+ // @ts-expect-error this API is not being used, not really needed
+ bank: undefined,
+ hints: [],
+ };
+
+ return h(Context.Provider, {
+ value,
+ children,
+ });
+};