aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-09-25 12:18:59 -0300
committerSebastian <sebasjm@gmail.com>2023-09-25 14:50:46 -0300
commit820f953b96b2b2852c32dc16a2fa920c6c717788 (patch)
tree584cbc88f22e4900d5e1a87156f7a05a4ecfc636
parent4041a76a58503572c6fe8edc87658afc946a11e0 (diff)
check config number
-rw-r--r--packages/demobank-ui/src/components/Routing.tsx31
-rw-r--r--packages/demobank-ui/src/components/app.tsx47
-rw-r--r--packages/demobank-ui/src/hooks/config.ts51
-rw-r--r--packages/demobank-ui/src/pages/LoginForm.tsx232
-rw-r--r--packages/demobank-ui/src/utils.ts22
5 files changed, 214 insertions, 169 deletions
diff --git a/packages/demobank-ui/src/components/Routing.tsx b/packages/demobank-ui/src/components/Routing.tsx
index 05af1719b..aafc95687 100644
--- a/packages/demobank-ui/src/components/Routing.tsx
+++ b/packages/demobank-ui/src/components/Routing.tsx
@@ -14,36 +14,43 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { createHashHistory } from "history";
-import { VNode, h } from "preact";
+import { Fragment, VNode, h } from "preact";
import { Route, Router, route } from "preact-router";
-import { useEffect, useErrorBoundary } from "preact/hooks";
+import { useEffect } from "preact/hooks";
+import { useBackendContext } from "../context/backend.js";
import { BankFrame } from "../pages/BankFrame.js";
-import { BusinessAccount } from "../pages/business/Home.js";
import { HomePage, WithdrawalOperationPage } from "../pages/HomePage.js";
+import { LoginForm } from "../pages/LoginForm.js";
import { PublicHistoriesPage } from "../pages/PublicHistoriesPage.js";
import { RegistrationPage } from "../pages/RegistrationPage.js";
-import { useBackendContext } from "../context/backend.js";
-import { LoginForm } from "../pages/LoginForm.js";
import { AdminHome } from "../pages/admin/Home.js";
+import { BusinessAccount } from "../pages/business/Home.js";
import { bankUiSettings } from "../settings.js";
-import { notifyError } from "@gnu-taler/web-util/browser";
export function Routing(): VNode {
const history = createHashHistory();
const backend = useBackendContext();
-
+ const {i18n} = useTranslationContext();
+
if (backend.state.status === "loggedOut") {
return <BankFrame >
<Router history={history}>
<Route
path="/login"
component={() => (
- <LoginForm
- onRegister={() => {
- route("/register");
- }}
- />
+ <Fragment>
+ <div class="sm:mx-auto sm:w-full sm:max-w-sm">
+ <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h2>
+ </div>
+
+ <LoginForm
+ onRegister={() => {
+ route("/register");
+ }}
+ />
+ </Fragment>
)}
/>
<Route
diff --git a/packages/demobank-ui/src/components/app.tsx b/packages/demobank-ui/src/components/app.tsx
index 22752ab78..ebda31035 100644
--- a/packages/demobank-ui/src/components/app.tsx
+++ b/packages/demobank-ui/src/components/app.tsx
@@ -15,15 +15,20 @@
*/
import {
+ LibtoolVersion,
getGlobalLogLevel,
setGlobalLogLevelFromString,
} from "@gnu-taler/taler-util";
-import { TranslationProvider } from "@gnu-taler/web-util/browser";
-import { FunctionalComponent, h } from "preact";
+import { TranslationProvider, useApiContext } from "@gnu-taler/web-util/browser";
+import { ComponentChildren, Fragment, FunctionalComponent, VNode, h } from "preact";
import { SWRConfig } from "swr";
-import { BackendStateProvider } from "../context/backend.js";
+import { BackendStateProvider, useBackendContext } from "../context/backend.js";
import { strings } from "../i18n/strings.js";
import { Routing } from "./Routing.js";
+import { useEffect, useState } from "preact/hooks";
+import { Loading } from "./Loading.js";
+import { getInitialBackendBaseURL } from "../hooks/backend.js";
+import { BANK_INTEGRATION_PROTOCOL_VERSION, useConfigState } from "../hooks/config.js";
const WITH_LOCAL_STORAGE_CACHE = false;
/**
@@ -47,22 +52,38 @@ const App: FunctionalComponent = () => {
return (
<TranslationProvider source={strings}>
<BackendStateProvider>
- <SWRConfig
- value={{
- provider: WITH_LOCAL_STORAGE_CACHE
- ? localStorageProvider
- : undefined,
- }}
- >
- <Routing />
- </SWRConfig>
+ <VersionCheck>
+ <SWRConfig
+ value={{
+ provider: WITH_LOCAL_STORAGE_CACHE
+ ? localStorageProvider
+ : undefined,
+ }}
+ >
+ <Routing />
+ </SWRConfig>
+ </VersionCheck>
</BackendStateProvider>
- </TranslationProvider>
+ </TranslationProvider >
);
};
(window as any).setGlobalLogLevelFromString = setGlobalLogLevelFromString;
(window as any).getGlobalLevel = getGlobalLogLevel;
+function VersionCheck({ children }: { children: ComponentChildren }): VNode {
+ const checked = useConfigState()
+
+ if (checked === undefined) {
+ return <Loading />
+ }
+ if (checked === false) {
+ return <div>
+ the bank backend is not supported. supported version "{BANK_INTEGRATION_PROTOCOL_VERSION}"
+ </div>
+ }
+ return <Fragment>{children}</Fragment>
+}
+
function localStorageProvider(): Map<unknown, unknown> {
const map = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]"));
diff --git a/packages/demobank-ui/src/hooks/config.ts b/packages/demobank-ui/src/hooks/config.ts
new file mode 100644
index 000000000..4b22e8ad3
--- /dev/null
+++ b/packages/demobank-ui/src/hooks/config.ts
@@ -0,0 +1,51 @@
+import { LibtoolVersion } from "@gnu-taler/taler-util";
+import { useApiContext } from "@gnu-taler/web-util/browser";
+import { useEffect, useState } from "preact/hooks";
+import { getInitialBackendBaseURL } from "./backend.js";
+
+/**
+ * Protocol version spoken with the bank.
+ *
+ * Uses libtool's current:revision:age versioning.
+ */
+export const BANK_INTEGRATION_PROTOCOL_VERSION = "0:0:0";
+
+async function getConfigState(
+ request: ReturnType<typeof useApiContext>["request"],
+): Promise<SandboxBackend.Config | undefined> {
+ try {
+ const url = getInitialBackendBaseURL();
+ const result = await request<SandboxBackend.Config>(
+ url,
+ `config`,
+ );
+ return result.data;
+ } catch (error) {
+ return undefined;
+ }
+}
+
+export function useConfigState(): boolean | undefined {
+ const [checked, setChecked] = useState<boolean>()
+ const { request } = useApiContext();
+
+ useEffect(() => {
+
+ getConfigState(request)
+ .then((result) => {
+ if (!result) {
+ setChecked(false)
+ } else {
+ const r = LibtoolVersion.compare(BANK_INTEGRATION_PROTOCOL_VERSION, result.version)
+ setChecked(r?.compatible);
+ }
+ })
+ .catch((error) => {
+ setChecked(false);
+ });
+ });
+
+ return checked;
+}
+
+
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx
index f579678f2..0fbbef7c3 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -128,132 +128,120 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
const isSessionExpired = !onRegister
return (
- <Fragment>
- <h1 class="nav"></h1>
- {/* {error && (
- <ErrorBannerFloat error={error} onClear={() => saveError(undefined)} />
- )} */}
-
- <div class="flex min-h-full flex-col justify-center">
- {/* <div class="sm:mx-auto sm:w-full sm:max-w-sm">
- <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h2>
- </div> */}
-
- <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
- <form class="space-y-6" noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <div>
- <label for="username" class="block text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Username</i18n.Translate>
- </label>
- <div class="mt-2">
- <input
- ref={ref}
- autoFocus
- type="text"
- name="username"
- id="username"
- class="block w-full disabled:bg-gray-200 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={username ?? ""}
- disabled={isSessionExpired}
- enterkeyhint="next"
- placeholder="identification"
- autocomplete="username"
- required
- onInput={(e): void => {
- setUsername(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.username}
- isDirty={username !== undefined}
- />
- </div>
+ <div class="flex min-h-full flex-col justify-center">
+
+ <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
+ <form class="space-y-6" noValidate
+ onSubmit={(e) => {
+ e.preventDefault();
+ }}
+ autoCapitalize="none"
+ autoCorrect="off"
+ >
+ <div>
+ <label for="username" class="block text-sm font-medium leading-6 text-gray-900">
+ <i18n.Translate>Username</i18n.Translate>
+ </label>
+ <div class="mt-2">
+ <input
+ ref={ref}
+ autoFocus
+ type="text"
+ name="username"
+ id="username"
+ class="block w-full disabled:bg-gray-200 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+ value={username ?? ""}
+ disabled={isSessionExpired}
+ enterkeyhint="next"
+ placeholder="identification"
+ autocomplete="username"
+ required
+ onInput={(e): void => {
+ setUsername(e.currentTarget.value);
+ }}
+ />
+ <ShowInputErrorLabel
+ message={errors?.username}
+ isDirty={username !== undefined}
+ />
</div>
+ </div>
- <div>
- <div class="flex items-center justify-between">
- <label for="password" class="block text-sm font-medium leading-6 text-gray-900">Password</label>
- </div>
- <div class="mt-2">
- <input
- type="password"
- name="password"
- id="password"
- autocomplete="current-password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- enterkeyhint="send"
- value={password ?? ""}
- placeholder="Password"
- required
- onInput={(e): void => {
- setPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.password}
- isDirty={password !== undefined}
- />
- </div>
+ <div>
+ <div class="flex items-center justify-between">
+ <label for="password" class="block text-sm font-medium leading-6 text-gray-900">Password</label>
</div>
-
- {isSessionExpired ? <div class="flex justify-between">
- <button type="submit"
- class="rounded-md bg-white-600 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-600"
- onClick={(e) => {
- e.preventDefault()
- doLogin()
- }}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
-
- <button type="submit"
- class="rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={(e) => {
- e.preventDefault()
- doLogin()
- }}
- >
- <i18n.Translate>Renew session</i18n.Translate>
- </button>
- </div> : <div>
- <button type="submit"
- class="flex w-full justify-center rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={(e) => {
- e.preventDefault()
- doLogin()
+ <div class="mt-2">
+ <input
+ type="password"
+ name="password"
+ id="password"
+ autocomplete="current-password"
+ class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+ enterkeyhint="send"
+ value={password ?? ""}
+ placeholder="Password"
+ required
+ onInput={(e): void => {
+ setPassword(e.currentTarget.value);
}}
- >
- <i18n.Translate>Log in</i18n.Translate>
- </button>
- </div>}
- </form>
-
- {bankUiSettings.allowRegistrations && onRegister &&
- <p class="mt-10 text-center text-sm text-gray-500 border-t">
- <button type="submit"
- class="flex mt-4 rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
- onClick={(e) => {
- e.preventDefault()
- onRegister()
- }}
- >
- <i18n.Translate>Register</i18n.Translate>
- </button>
- </p>
- }
- </div>
+ />
+ <ShowInputErrorLabel
+ message={errors?.password}
+ isDirty={password !== undefined}
+ />
+ </div>
+ </div>
+
+ {isSessionExpired ? <div class="flex justify-between">
+ <button type="submit"
+ class="rounded-md bg-white-600 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-600"
+ onClick={(e) => {
+ e.preventDefault()
+ doLogin()
+ }}
+ >
+ <i18n.Translate>Cancel</i18n.Translate>
+ </button>
+
+ <button type="submit"
+ class="rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ disabled={!!errors}
+ onClick={(e) => {
+ e.preventDefault()
+ doLogin()
+ }}
+ >
+ <i18n.Translate>Renew session</i18n.Translate>
+ </button>
+ </div> : <div>
+ <button type="submit"
+ class="flex w-full justify-center rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ disabled={!!errors}
+ onClick={(e) => {
+ e.preventDefault()
+ doLogin()
+ }}
+ >
+ <i18n.Translate>Log in</i18n.Translate>
+ </button>
+ </div>}
+ </form>
+
+ {bankUiSettings.allowRegistrations && onRegister &&
+ <p class="mt-10 text-center text-sm text-gray-500 border-t">
+ <button type="submit"
+ class="flex mt-4 rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
+ onClick={(e) => {
+ e.preventDefault()
+ onRegister()
+ }}
+ >
+ <i18n.Translate>Register</i18n.Translate>
+ </button>
+ </p>
+ }
</div>
-
-
- </Fragment>
+ </div>
);
}
diff --git a/packages/demobank-ui/src/utils.ts b/packages/demobank-ui/src/utils.ts
index c13b9a3cb..e7673f078 100644
--- a/packages/demobank-ui/src/utils.ts
+++ b/packages/demobank-ui/src/utils.ts
@@ -88,28 +88,6 @@ export enum CashoutStatus {
PENDING = "pending",
}
-// export function partialWithObjects<T extends object>(obj: T | undefined, () => complete): WithIntermediate<T> {
-// const root = obj === undefined ? {} : obj;
-// return Object.entries(root).([key, value]) => {
-
-// })
-// return undefined as any
-// }
-
-/**
- * Craft headers with Authorization and Content-Type.
- */
-// export function prepareHeaders(username?: string, password?: string): Headers {
-// const headers = new Headers();
-// if (username && password) {
-// headers.append(
-// "Authorization",
-// `Basic ${window.btoa(`${username}:${password}`)}`,
-// );
-// }
-// headers.append("Content-Type", "application/json");
-// return headers;
-// }
export const PAGE_SIZE = 20;
export const MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1;