summaryrefslogtreecommitdiff
path: root/packages/demobank-ui
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-12-07 09:06:10 -0300
committerSebastian <sebasjm@gmail.com>2022-12-07 16:08:14 -0300
commit8e6bf990069b9c3ae033321b5aeb4d46fa6501e6 (patch)
treefea00d6b97e4d351eadc1e36feeddb4bc9e55816 /packages/demobank-ui
parent2dc3eb0ddd7efe4fd63a51a3aa9b36863d9a1fcb (diff)
downloadwallet-core-8e6bf990069b9c3ae033321b5aeb4d46fa6501e6.tar.gz
wallet-core-8e6bf990069b9c3ae033321b5aeb4d46fa6501e6.tar.bz2
wallet-core-8e6bf990069b9c3ae033321b5aeb4d46fa6501e6.zip
no-fix: move pagestate provider to app component and move some common hooks to web-utils
Diffstat (limited to 'packages/demobank-ui')
-rw-r--r--packages/demobank-ui/src/components/app.tsx5
-rw-r--r--packages/demobank-ui/src/context/pageState.ts121
-rw-r--r--packages/demobank-ui/src/context/translation.ts4
-rw-r--r--packages/demobank-ui/src/declaration.d.ts49
-rw-r--r--packages/demobank-ui/src/hooks/index.ts10
-rw-r--r--packages/demobank-ui/src/hooks/useLang.ts30
-rw-r--r--packages/demobank-ui/src/hooks/useLocalStorage.ts80
-rw-r--r--packages/demobank-ui/src/pages/home/index.tsx384
-rw-r--r--packages/demobank-ui/src/settings.ts27
9 files changed, 301 insertions, 409 deletions
diff --git a/packages/demobank-ui/src/components/app.tsx b/packages/demobank-ui/src/components/app.tsx
index 49b218205..91410a485 100644
--- a/packages/demobank-ui/src/components/app.tsx
+++ b/packages/demobank-ui/src/components/app.tsx
@@ -1,11 +1,14 @@
import { h, FunctionalComponent } from "preact";
+import { PageStateProvider } from "../context/pageState.js";
import { TranslationProvider } from "../context/translation.js";
import { BankHome } from "../pages/home/index.js";
const App: FunctionalComponent = () => {
return (
<TranslationProvider>
- <BankHome />
+ <PageStateProvider>
+ <BankHome />
+ </PageStateProvider>
</TranslationProvider>
);
};
diff --git a/packages/demobank-ui/src/context/pageState.ts b/packages/demobank-ui/src/context/pageState.ts
new file mode 100644
index 000000000..3d7ccd85b
--- /dev/null
+++ b/packages/demobank-ui/src/context/pageState.ts
@@ -0,0 +1,121 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 { hooks } from "@gnu-taler/web-util/lib/index.browser";
+import { ComponentChildren, createContext, h, VNode } from "preact";
+import { StateUpdater, useContext } from "preact/hooks";
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+export type Type = {
+ pageState: PageStateType;
+ pageStateSetter: StateUpdater<PageStateType>;
+};
+const initial: Type = {
+ pageState: {
+ isLoggedIn: false,
+ isRawPayto: false,
+ showPublicHistories: false,
+ withdrawalInProgress: false,
+ },
+ pageStateSetter: () => {
+ null;
+ },
+};
+const Context = createContext<Type>(initial);
+
+export const usePageContext = (): Type => useContext(Context);
+
+export const PageStateProvider = ({
+ children,
+}: {
+ children: ComponentChildren;
+}): VNode => {
+ const [pageState, pageStateSetter] = usePageState();
+
+ return h(Context.Provider, {
+ value: { pageState, pageStateSetter },
+ children,
+ });
+};
+
+/**
+ * Wrapper providing defaults.
+ */
+function usePageState(
+ state: PageStateType = {
+ isLoggedIn: false,
+ isRawPayto: false,
+ showPublicHistories: false,
+ withdrawalInProgress: false,
+ },
+): [PageStateType, StateUpdater<PageStateType>] {
+ const ret = hooks.useNotNullLocalStorage("page-state", JSON.stringify(state));
+ const retObj: PageStateType = JSON.parse(ret[0]);
+
+ const retSetter: StateUpdater<PageStateType> = function (val) {
+ const newVal =
+ val instanceof Function
+ ? JSON.stringify(val(retObj))
+ : JSON.stringify(val);
+
+ ret[1](newVal);
+ };
+
+ //when moving from one page to another
+ //clean up the info and error bar
+ function removeLatestInfo(val: any): ReturnType<typeof retSetter> {
+ const updater = typeof val === "function" ? val : (c: any) => val;
+ return retSetter((current: any) => {
+ const cleanedCurrent: PageStateType = {
+ ...current,
+ info: undefined,
+ errors: undefined,
+ timestamp: new Date().getTime(),
+ };
+ return updater(cleanedCurrent);
+ });
+ }
+
+ return [retObj, removeLatestInfo];
+}
+
+/**
+ * Track page state.
+ */
+export interface PageStateType {
+ isLoggedIn: boolean;
+ isRawPayto: boolean;
+ showPublicHistories: boolean;
+ withdrawalInProgress: boolean;
+ error?: {
+ description?: string;
+ title: string;
+ debug?: string;
+ };
+
+ info?: string;
+ talerWithdrawUri?: string;
+ /**
+ * Not strictly a presentational value, could
+ * be moved in a future "withdrawal state" object.
+ */
+ withdrawalId?: string;
+ timestamp?: number;
+}
diff --git a/packages/demobank-ui/src/context/translation.ts b/packages/demobank-ui/src/context/translation.ts
index a50f81b86..478bdbde0 100644
--- a/packages/demobank-ui/src/context/translation.ts
+++ b/packages/demobank-ui/src/context/translation.ts
@@ -22,7 +22,7 @@
import { i18n, setupI18n } from "@gnu-taler/taler-util";
import { createContext, h, VNode } from "preact";
import { useContext, useEffect } from "preact/hooks";
-import { useLang } from "../hooks/useLang.js";
+import { hooks } from "@gnu-taler/web-util/lib/index.browser";
import { strings } from "../i18n/strings.js";
interface Type {
@@ -70,7 +70,7 @@ export const TranslationProvider = ({
children,
forceLang,
}: Props): VNode => {
- const [lang, changeLanguage, isSaved] = useLang(initial);
+ const [lang, changeLanguage, isSaved] = hooks.useLang(initial);
useEffect(() => {
if (forceLang) {
changeLanguage(forceLang);
diff --git a/packages/demobank-ui/src/declaration.d.ts b/packages/demobank-ui/src/declaration.d.ts
index 00b3d41d5..084686bd2 100644
--- a/packages/demobank-ui/src/declaration.d.ts
+++ b/packages/demobank-ui/src/declaration.d.ts
@@ -18,3 +18,52 @@ declare module "jed" {
const x: any;
export = x;
}
+
+/**********************************************
+ * Type definitions for states and API calls. *
+ *********************************************/
+
+/**
+ * Has the information to reach and
+ * authenticate at the bank's backend.
+ */
+interface BackendStateType {
+ url?: string;
+ username?: string;
+ password?: string;
+}
+
+/**
+ * Request body of POST /transactions.
+ *
+ * If the amount appears twice: both as a Payto parameter and
+ * in the JSON dedicate field, the one on the Payto URI takes
+ * precedence.
+ */
+interface TransactionRequestType {
+ paytoUri: string;
+ amount?: string; // with currency.
+}
+
+/**
+ * Request body of /register.
+ */
+interface CredentialsRequestType {
+ username?: string;
+ password?: string;
+ repeatPassword?: string;
+}
+
+/**
+ * Request body of /register.
+ */
+// interface LoginRequestType {
+// username: string;
+// password: string;
+// }
+
+interface WireTransferRequestType {
+ iban?: string;
+ subject?: string;
+ amount?: string;
+}
diff --git a/packages/demobank-ui/src/hooks/index.ts b/packages/demobank-ui/src/hooks/index.ts
index b4191d182..c6e3fe8c1 100644
--- a/packages/demobank-ui/src/hooks/index.ts
+++ b/packages/demobank-ui/src/hooks/index.ts
@@ -20,7 +20,7 @@
*/
import { StateUpdater } from "preact/hooks";
-import { useLocalStorage, useNotNullLocalStorage } from "./useLocalStorage.js";
+import { hooks } from "@gnu-taler/web-util/lib/index.browser";
export type ValueOrFunction<T> = T | ((p: T) => T);
const calculateRootPath = () => {
@@ -34,11 +34,11 @@ const calculateRootPath = () => {
export function useBackendURL(
url?: string,
): [string, boolean, StateUpdater<string>, () => void] {
- const [value, setter] = useNotNullLocalStorage(
+ const [value, setter] = hooks.useNotNullLocalStorage(
"backend-url",
url || calculateRootPath(),
);
- const [triedToLog, setTriedToLog] = useLocalStorage("tried-login");
+ const [triedToLog, setTriedToLog] = hooks.useLocalStorage("tried-login");
const checkedSetter = (v: ValueOrFunction<string>) => {
setTriedToLog("yes");
@@ -55,13 +55,13 @@ export function useBackendDefaultToken(): [
string | undefined,
StateUpdater<string | undefined>,
] {
- return useLocalStorage("backend-token");
+ return hooks.useLocalStorage("backend-token");
}
export function useBackendInstanceToken(
id: string,
): [string | undefined, StateUpdater<string | undefined>] {
- const [token, setToken] = useLocalStorage(`backend-token-${id}`);
+ const [token, setToken] = hooks.useLocalStorage(`backend-token-${id}`);
const [defaultToken, defaultSetToken] = useBackendDefaultToken();
// instance named 'default' use the default token
diff --git a/packages/demobank-ui/src/hooks/useLang.ts b/packages/demobank-ui/src/hooks/useLang.ts
deleted file mode 100644
index 5b02c5255..000000000
--- a/packages/demobank-ui/src/hooks/useLang.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- This file is part of GNU Anastasis
- (C) 2021-2022 Anastasis SARL
-
- GNU Anastasis is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Anastasis 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { useNotNullLocalStorage } from "./useLocalStorage.js";
-
-function getBrowserLang(): string | undefined {
- if (window.navigator.languages) return window.navigator.languages[0];
- if (window.navigator.language) return window.navigator.language;
- return undefined;
-}
-
-export function useLang(
- initial?: string,
-): [string, (s: string) => void, boolean] {
- const defaultLang = (getBrowserLang() || initial || "en").substring(0, 2);
- return useNotNullLocalStorage("lang-preference", defaultLang);
-}
diff --git a/packages/demobank-ui/src/hooks/useLocalStorage.ts b/packages/demobank-ui/src/hooks/useLocalStorage.ts
deleted file mode 100644
index ed5b491f2..000000000
--- a/packages/demobank-ui/src/hooks/useLocalStorage.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of GNU Anastasis
- (C) 2021-2022 Anastasis SARL
-
- GNU Anastasis is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Anastasis 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { StateUpdater, useState } from "preact/hooks";
-
-export function useLocalStorage(
- key: string,
- initialValue?: string,
-): [string | undefined, StateUpdater<string | undefined>] {
- const [storedValue, setStoredValue] = useState<string | undefined>(
- (): string | undefined => {
- return typeof window !== "undefined"
- ? window.localStorage.getItem(key) || initialValue
- : initialValue;
- },
- );
-
- const setValue = (
- value?: string | ((val?: string) => string | undefined),
- ): void => {
- setStoredValue((p) => {
- const toStore = value instanceof Function ? value(p) : value;
- if (typeof window !== "undefined") {
- if (!toStore) {
- window.localStorage.removeItem(key);
- } else {
- window.localStorage.setItem(key, toStore);
- }
- }
- return toStore;
- });
- };
-
- return [storedValue, setValue];
-}
-
-//TODO: merge with the above function
-export function useNotNullLocalStorage(
- key: string,
- initialValue: string,
-): [string, StateUpdater<string>, boolean] {
- const [storedValue, setStoredValue] = useState<string>((): string => {
- return typeof window !== "undefined"
- ? window.localStorage.getItem(key) || initialValue
- : initialValue;
- });
-
- const setValue = (value: string | ((val: string) => string)): void => {
- const valueToStore = value instanceof Function ? value(storedValue) : value;
- setStoredValue(valueToStore);
- if (typeof window !== "undefined") {
- if (!valueToStore) {
- window.localStorage.removeItem(key);
- } else {
- window.localStorage.setItem(key, valueToStore);
- }
- }
- };
-
- const isSaved = window.localStorage.getItem(key) !== null;
- return [storedValue, setValue, isSaved];
-}
diff --git a/packages/demobank-ui/src/pages/home/index.tsx b/packages/demobank-ui/src/pages/home/index.tsx
index 8b2ffefac..a64c4abe3 100644
--- a/packages/demobank-ui/src/pages/home/index.tsx
+++ b/packages/demobank-ui/src/pages/home/index.tsx
@@ -27,44 +27,14 @@ import {
} from "preact/hooks";
import talerLogo from "../../assets/logo-white.svg";
import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector.js";
-import {
- useLocalStorage,
- useNotNullLocalStorage,
-} from "../../hooks/useLocalStorage.js";
-// import { Translate, useTranslator } from "../../i18n/index.js";
import { useTranslationContext } from "../../context/translation.js";
import { Amounts, HttpStatusCode, parsePaytoUri } from "@gnu-taler/taler-util";
import { createHashHistory } from "history";
import Router, { Route, route } from "preact-router";
import { QrCodeSection } from "./QrCodeSection.js";
-
-interface BankUiSettings {
- allowRegistrations: boolean;
- showDemoNav: boolean;
- bankName: string;
- demoSites: [string, string][];
-}
-
-/**
- * Global settings for the demobank UI.
- */
-const defaultSettings: BankUiSettings = {
- allowRegistrations: true,
- bankName: "Taler Bank",
- showDemoNav: true,
- demoSites: [
- ["Landing", "https://demo.taler.net/"],
- ["Bank", "https://bank.demo.taler.net/"],
- ["Essay Shop", "https://shop.demo.taler.net/"],
- ["Donations", "https://donations.demo.taler.net/"],
- ["Survey", "https://survey.demo.taler.net/"],
- ],
-};
-
-const bankUiSettings: BankUiSettings =
- "talerDemobankSettings" in globalThis
- ? (globalThis as any).talerDemobankSettings
- : defaultSettings;
+import { hooks } from "@gnu-taler/web-util/lib/index.browser";
+import { bankUiSettings } from "../../settings.js";
+import { PageStateType, usePageContext } from "../../context/pageState.js";
/**
* FIXME:
@@ -90,94 +60,6 @@ const bankUiSettings: BankUiSettings =
/************
* Contexts *
***********/
-const CurrencyContext = createContext<any>(null);
-type PageContextType = [PageStateType, StateUpdater<PageStateType>];
-const PageContextDefault: PageContextType = [
- {
- isLoggedIn: false,
- isRawPayto: false,
- showPublicHistories: false,
-
- withdrawalInProgress: false,
- },
- () => {
- null;
- },
-];
-const PageContext = createContext<PageContextType>(PageContextDefault);
-
-/**********************************************
- * Type definitions for states and API calls. *
- *********************************************/
-
-/**
- * Has the information to reach and
- * authenticate at the bank's backend.
- */
-interface BackendStateType {
- url?: string;
- username?: string;
- password?: string;
-}
-
-/**
- * Request body of POST /transactions.
- *
- * If the amount appears twice: both as a Payto parameter and
- * in the JSON dedicate field, the one on the Payto URI takes
- * precedence.
- */
-interface TransactionRequestType {
- paytoUri: string;
- amount?: string; // with currency.
-}
-
-/**
- * Request body of /register.
- */
-interface CredentialsRequestType {
- username?: string;
- password?: string;
- repeatPassword?: string;
-}
-
-/**
- * Request body of /register.
- */
-// interface LoginRequestType {
-// username: string;
-// password: string;
-// }
-
-interface WireTransferRequestType {
- iban?: string;
- subject?: string;
- amount?: string;
-}
-
-/**
- * Track page state.
- */
-interface PageStateType {
- isLoggedIn: boolean;
- isRawPayto: boolean;
- showPublicHistories: boolean;
- withdrawalInProgress: boolean;
- error?: {
- description?: string;
- title: string;
- debug?: string;
- };
-
- info?: string;
- talerWithdrawUri?: string;
- /**
- * Not strictly a presentational value, could
- * be moved in a future "withdrawal state" object.
- */
- withdrawalId?: string;
- timestamp?: number;
-}
/**
* Bank account specific information.
@@ -294,7 +176,7 @@ async function postToBackend(
}
function useTransactionPageNumber(): [number, StateUpdater<number>] {
- const ret = useNotNullLocalStorage("transaction-page", "0");
+ const ret = hooks.useNotNullLocalStorage("transaction-page", "0");
const retObj = JSON.parse(ret[0]);
const retSetter: StateUpdater<number> = function (val) {
const newVal =
@@ -347,7 +229,10 @@ const getBankBackendBaseUrl = (): string => {
function useShowPublicAccount(
state?: string,
): [string | undefined, StateUpdater<string | undefined>] {
- const ret = useLocalStorage("show-public-account", JSON.stringify(state));
+ const ret = hooks.useLocalStorage(
+ "show-public-account",
+ JSON.stringify(state),
+ );
const retObj: string | undefined = ret[0] ? JSON.parse(ret[0]) : ret[0];
const retSetter: StateUpdater<string | undefined> = function (val) {
const newVal =
@@ -367,7 +252,7 @@ type RawPaytoInputTypeOpt = RawPaytoInputType | undefined;
function useRawPaytoInputType(
state?: RawPaytoInputType,
): [RawPaytoInputTypeOpt, StateUpdater<RawPaytoInputTypeOpt>] {
- const ret = useLocalStorage("raw-payto-input-state", state);
+ const ret = hooks.useLocalStorage("raw-payto-input-state", state);
const retObj: RawPaytoInputTypeOpt = ret[0];
const retSetter: StateUpdater<RawPaytoInputTypeOpt> = function (val) {
const newVal = val instanceof Function ? val(retObj) : val;
@@ -387,7 +272,7 @@ type WireTransferRequestTypeOpt = WireTransferRequestType | undefined;
function useWireTransferRequestType(
state?: WireTransferRequestType,
): [WireTransferRequestTypeOpt, StateUpdater<WireTransferRequestTypeOpt>] {
- const ret = useLocalStorage(
+ const ret = hooks.useLocalStorage(
"wire-transfer-request-state",
JSON.stringify(state),
);
@@ -413,7 +298,7 @@ type CredentialsRequestTypeOpt = CredentialsRequestType | undefined;
function useCredentialsRequestType(
state?: CredentialsRequestType,
): [CredentialsRequestTypeOpt, StateUpdater<CredentialsRequestTypeOpt>] {
- const ret = useLocalStorage(
+ const ret = hooks.useLocalStorage(
"credentials-request-state",
JSON.stringify(state),
);
@@ -439,7 +324,7 @@ type BackendStateTypeOpt = BackendStateType | undefined;
function useBackendState(
state?: BackendStateType,
): [BackendStateTypeOpt, StateUpdater<BackendStateTypeOpt>] {
- const ret = useLocalStorage("backend-state", JSON.stringify(state));
+ const ret = hooks.useLocalStorage("backend-state", JSON.stringify(state));
const retObj: BackendStateTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0];
const retSetter: StateUpdater<BackendStateTypeOpt> = function (val) {
const newVal =
@@ -452,67 +337,6 @@ function useBackendState(
}
/**
- * Keep mere business information, like account balance or
- * transactions history.
- */
-// type AccountStateTypeOpt = AccountStateType | undefined;
-// function useAccountState(
-// state?: AccountStateType,
-// ): [AccountStateTypeOpt, StateUpdater<AccountStateTypeOpt>] {
-// const ret = useLocalStorage("account-state", JSON.stringify(state));
-// const retObj: AccountStateTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0];
-// const retSetter: StateUpdater<AccountStateTypeOpt> = function (val) {
-// const newVal =
-// val instanceof Function
-// ? JSON.stringify(val(retObj))
-// : JSON.stringify(val);
-// ret[1](newVal);
-// };
-// return [retObj, retSetter];
-// }
-
-/**
- * Wrapper providing defaults.
- */
-function usePageState(
- state: PageStateType = {
- isLoggedIn: false,
- isRawPayto: false,
- showPublicHistories: false,
- withdrawalInProgress: false,
- },
-): [PageStateType, StateUpdater<PageStateType>] {
- const ret = useNotNullLocalStorage("page-state", JSON.stringify(state));
- const retObj: PageStateType = JSON.parse(ret[0]);
-
- const retSetter: StateUpdater<PageStateType> = function (val) {
- const newVal =
- val instanceof Function
- ? JSON.stringify(val(retObj))
- : JSON.stringify(val);
-
- ret[1](newVal);
- };
-
- //when moving from one page to another
- //clean up the info and error bar
- function removeLatestInfo(val: any): ReturnType<typeof retSetter> {
- const updater = typeof val === "function" ? val : (c: any) => val;
- return retSetter((current: any) => {
- const cleanedCurrent: PageStateType = {
- ...current,
- info: undefined,
- errors: undefined,
- timestamp: new Date().getTime(),
- };
- return updater(cleanedCurrent);
- });
- }
-
- return [retObj, removeLatestInfo];
-}
-
-/**
* Request preparators.
*
* These functions aim at sanitizing the input received
@@ -1045,7 +869,7 @@ function StatusBanner(Props: any): VNode | null {
function BankFrame(Props: any): VNode {
const { i18n } = useTranslationContext();
- const [pageState, pageStateSetter] = useContext(PageContext);
+ const { pageState, pageStateSetter } = usePageContext();
console.log("BankFrame state", pageState);
const logOut = (
<div class="logout">
@@ -1164,19 +988,16 @@ function ShowInputErrorLabel({
}
function PaytoWireTransfer(Props: any): VNode {
- const currency = useContext(CurrencyContext);
- const [pageState, pageStateSetter] = useContext(PageContext); // NOTE: used for go-back button?
+ const { pageState, pageStateSetter } = usePageContext(); // NOTE: used for go-back button?
+
const [submitData, submitDataSetter] = useWireTransferRequestType();
- // const [rawPaytoInput, rawPaytoInputSetter] = useRawPaytoInputType();
+
const [rawPaytoInput, rawPaytoInputSetter] = useState<string | undefined>(
undefined,
);
const { i18n } = useTranslationContext();
- const { focus, backendState } = Props;
- const amountRegex = "^[0-9]+(.[0-9]+)?$";
+ const { focus, backendState, currency } = Props;
const ibanRegex = "^[A-Z][A-Z][0-9]+$";
- const receiverInput = "";
- const subjectInput = "";
let transactionData: TransactionRequestType;
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
@@ -1213,7 +1034,7 @@ function PaytoWireTransfer(Props: any): VNode {
if (!pageState.isRawPayto)
return (
<div>
- <div class="pure-form" name="wire-transfer-form">
+ <form class="pure-form" name="wire-transfer-form">
<p>
<label for="iban">{i18n.str`Receiver IBAN:`}</label>&nbsp;
<input
@@ -1261,13 +1082,22 @@ function PaytoWireTransfer(Props: any): VNode {
<br />
<label for="amount">{i18n.str`Amount:`}</label>&nbsp;
<input
+ type="text"
+ readonly
+ class="currency-indicator"
+ size={currency.length}
+ maxLength={currency.length}
+ tabIndex={-1}
+ value={currency}
+ />
+ &nbsp;
+ <input
type="number"
name="amount"
id="amount"
placeholder="amount"
required
value={submitData?.amount ?? ""}
- pattern={amountRegex}
onInput={(e): void => {
submitDataSetter((submitData: any) => ({
...submitData,
@@ -1275,16 +1105,6 @@ function PaytoWireTransfer(Props: any): VNode {
}));
}}
/>
- &nbsp;
- <input
- type="text"
- readonly
- class="currency-indicator"
- size={currency.length}
- maxLength={currency.length}
- tabIndex={-1}
- value={currency}
- />
<ShowInputErrorLabel
message={errorsWire?.amount}
isDirty={submitData?.amount !== undefined}
@@ -1349,7 +1169,7 @@ function PaytoWireTransfer(Props: any): VNode {
}}
/>
</p>
- </div>
+ </form>
<p>
<a
href="/account"
@@ -1460,7 +1280,7 @@ function PaytoWireTransfer(Props: any): VNode {
* Not providing a back button, only abort.
*/
function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
- const [pageState, pageStateSetter] = useContext(PageContext);
+ const { pageState, pageStateSetter } = usePageContext();
const { backendState } = Props;
const { i18n } = useTranslationContext();
const captchaNumbers = {
@@ -1474,7 +1294,7 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
<h1 class="nav">{i18n.str`Confirm Withdrawal`}</h1>
<article>
<div class="challenge-div">
- <form class="challenge-form">
+ <form class="challenge-form" noValidate>
<div class="pure-form" id="captcha" name="capcha-form">
<h2>{i18n.str`Authorize withdrawal by solving challenge`}</h2>
<p>
@@ -1562,8 +1382,8 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
*/
function TalerWithdrawalQRCode(Props: any): VNode {
// turns true when the wallet POSTed the reserve details:
- const [pageState, pageStateSetter] = useContext(PageContext);
- const { withdrawalId, talerWithdrawUri, accountLabel, backendState } = Props;
+ const { pageState, pageStateSetter } = usePageContext();
+ const { withdrawalId, talerWithdrawUri, backendState } = Props;
const { i18n } = useTranslationContext();
const abortButton = (
<a
@@ -1647,29 +1467,35 @@ function TalerWithdrawalQRCode(Props: any): VNode {
}
function WalletWithdraw(Props: any): VNode {
- const { backendState, pageStateSetter, focus } = Props;
- const currency = useContext(CurrencyContext);
+ const { backendState, pageStateSetter, focus, currency } = Props;
const { i18n } = useTranslationContext();
let submitAmount = "5.00";
- const amountRegex = "^[0-9]+(.[0-9]+)?$";
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
if (focus) ref.current?.focus();
}, [focus]);
return (
- <div id="reserve-form" class="pure-form" name="tform">
+ <form id="reserve-form" class="pure-form" name="tform">
<p>
<label for="withdraw-amount">{i18n.str`Amount to withdraw:`}</label>
&nbsp;
<input
+ type="text"
+ readonly
+ class="currency-indicator"
+ size={currency.length}
+ maxLength={currency.length}
+ tabIndex={-1}
+ value={currency}
+ />
+ &nbsp;
+ <input
type="number"
ref={ref}
id="withdraw-amount"
name="withdraw-amount"
value={submitAmount}
- pattern={amountRegex}
- class="amount"
onChange={(e): void => {
// FIXME: validate using 'parseAmount()',
// deactivate submit button as long as
@@ -1677,16 +1503,6 @@ function WalletWithdraw(Props: any): VNode {
submitAmount = e.currentTarget.value;
}}
/>
- &nbsp;
- <input
- type="text"
- readonly
- class="currency-indicator"
- size={currency.length}
- maxLength={currency.length}
- tabIndex={-1}
- value={currency}
- />
</p>
<p>
<div>
@@ -1712,7 +1528,7 @@ function WalletWithdraw(Props: any): VNode {
/>
</div>
</p>
- </div>
+ </form>
);
}
@@ -1721,8 +1537,7 @@ function WalletWithdraw(Props: any): VNode {
* then specify the details trigger the action.
*/
function PaymentOptions(Props: any): VNode {
- const { backendState, pageStateSetter, focus } = Props;
- const currency = useContext(CurrencyContext);
+ const { backendState, pageStateSetter, currency } = Props;
const { i18n } = useTranslationContext();
const [tab, setTab] = useState<"charge-wallet" | "wire-transfer">(
@@ -1756,6 +1571,7 @@ function PaymentOptions(Props: any): VNode {
<WalletWithdraw
backendState={backendState}
focus
+ currency={currency}
pageStateSetter={pageStateSetter}
/>
</div>
@@ -1766,6 +1582,7 @@ function PaymentOptions(Props: any): VNode {
<PaytoWireTransfer
backendState={backendState}
focus
+ currency={currency}
pageStateSetter={pageStateSetter}
/>
</div>
@@ -1819,7 +1636,7 @@ function LoginForm(Props: any): VNode {
return (
<div class="login-div">
- <form action="javascript:void(0);" class="login-form">
+ <form action="javascript:void(0);" class="login-form" noValidate>
<div class="pure-form">
<h2>{i18n.str`Please login!`}</h2>
<p class="unameFieldLabel loginFieldLabel formFieldLabel">
@@ -1903,7 +1720,7 @@ function LoginForm(Props: any): VNode {
*/
function RegistrationForm(Props: any): VNode {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- const [pageState, pageStateSetter] = useContext(PageContext);
+ const { pageState, pageStateSetter } = usePageContext();
const [submitData, submitDataSetter] = useCredentialsRequestType();
const { i18n } = useTranslationContext();
@@ -1924,7 +1741,7 @@ function RegistrationForm(Props: any): VNode {
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
<article>
<div class="register-div">
- <form action="javascript:void(0);" class="register-form">
+ <form action="javascript:void(0);" class="register-form" noValidate>
<div class="pure-form">
<h2>{i18n.str`Please register!`}</h2>
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
@@ -2140,7 +1957,7 @@ function Account(Props: any): VNode {
// revalidateOnFocus: false,
// revalidateOnReconnect: false,
});
- const [pageState, setPageState] = useContext(PageContext);
+ const { pageState, pageStateSetter: setPageState } = usePageContext();
const {
withdrawalInProgress,
withdrawalId,
@@ -2275,14 +2092,11 @@ function Account(Props: any): VNode {
<section id="payments">
<div class="payments">
<h2>{i18n.str`Payments`}</h2>
- {/* FIXME: turn into button! */}
- <CurrencyContext.Provider value={balance.currency}>
- {Props.children}
- <PaymentOptions
- backendState={backendState}
- pageStateSetter={setPageState}
- />
- </CurrencyContext.Provider>
+ <PaymentOptions
+ currency={balance.currency}
+ backendState={backendState}
+ pageStateSetter={setPageState}
+ />
</div>
</section>
<section id="main">
@@ -2439,71 +2253,61 @@ function PublicHistories(Props: any): VNode {
}
function PublicHistoriesPage(): VNode {
- // const [backendState, backendStateSetter] = useBackendState();
- const [pageState, pageStateSetter] = usePageState();
+ const { pageState, pageStateSetter } = usePageContext();
// const { i18n } = useTranslationContext();
return (
<SWRWithoutCredentials baseUrl={getBankBackendBaseUrl()}>
- <PageContext.Provider value={[pageState, pageStateSetter]}>
- <BankFrame>
- <PublicHistories pageStateSetter={pageStateSetter}>
- <br />
- <a
- class="pure-button"
- onClick={() => {
- pageStateSetter((prevState: PageStateType) => ({
- ...prevState,
- showPublicHistories: false,
- }));
- }}
- >
- Go back
- </a>
- </PublicHistories>
- </BankFrame>
- </PageContext.Provider>
+ <BankFrame>
+ <PublicHistories pageStateSetter={pageStateSetter}>
+ <br />
+ <a
+ class="pure-button"
+ onClick={() => {
+ pageStateSetter((prevState: PageStateType) => ({
+ ...prevState,
+ showPublicHistories: false,
+ }));
+ }}
+ >
+ Go back
+ </a>
+ </PublicHistories>
+ </BankFrame>
</SWRWithoutCredentials>
);
}
function RegistrationPage(): VNode {
const [backendState, backendStateSetter] = useBackendState();
- const [pageState, pageStateSetter] = usePageState();
const { i18n } = useTranslationContext();
if (!bankUiSettings.allowRegistrations) {
return (
- <PageContext.Provider value={[pageState, pageStateSetter]}>
- <BankFrame>
- <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
- </BankFrame>
- </PageContext.Provider>
+ <BankFrame>
+ <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
+ </BankFrame>
);
}
return (
- <PageContext.Provider value={[pageState, pageStateSetter]}>
- <BankFrame>
- <RegistrationForm backendStateSetter={backendStateSetter} />
- </BankFrame>
- </PageContext.Provider>
+ <BankFrame>
+ <RegistrationForm backendStateSetter={backendStateSetter} />
+ </BankFrame>
);
}
function AccountPage(): VNode {
const [backendState, backendStateSetter] = useBackendState();
- const [pageState, pageStateSetter] = usePageState();
const { i18n } = useTranslationContext();
+ const { pageState, pageStateSetter } = usePageContext();
if (!pageState.isLoggedIn) {
return (
- <PageContext.Provider value={[pageState, pageStateSetter]}>
- <BankFrame>
- <h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
- <LoginForm
- pageStateSetter={pageStateSetter}
- backendStateSetter={backendStateSetter}
- />
- </BankFrame>
- </PageContext.Provider>
+ <BankFrame>
+ <h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
+ <LoginForm
+ pageStateSetter={pageStateSetter}
+ backendStateSetter={backendStateSetter}
+ />
+ </BankFrame>
);
}
@@ -2525,12 +2329,10 @@ function AccountPage(): VNode {
password={backendState.password}
backendUrl={backendState.url}
>
- <PageContext.Provider value={[pageState, pageStateSetter]}>
- <Account
- accountLabel={backendState.username}
- backendState={backendState}
- />
- </PageContext.Provider>
+ <Account
+ accountLabel={backendState.username}
+ backendState={backendState}
+ />
</SWRWithCredentials>
);
}
diff --git a/packages/demobank-ui/src/settings.ts b/packages/demobank-ui/src/settings.ts
new file mode 100644
index 000000000..a63ce347e
--- /dev/null
+++ b/packages/demobank-ui/src/settings.ts
@@ -0,0 +1,27 @@
+export interface BankUiSettings {
+ allowRegistrations: boolean;
+ showDemoNav: boolean;
+ bankName: string;
+ demoSites: [string, string][];
+}
+
+/**
+ * Global settings for the demobank UI.
+ */
+const defaultSettings: BankUiSettings = {
+ allowRegistrations: true,
+ bankName: "Taler Bank",
+ showDemoNav: true,
+ demoSites: [
+ ["Landing", "https://demo.taler.net/"],
+ ["Bank", "https://bank.demo.taler.net/"],
+ ["Essay Shop", "https://shop.demo.taler.net/"],
+ ["Donations", "https://donations.demo.taler.net/"],
+ ["Survey", "https://survey.demo.taler.net/"],
+ ],
+};
+
+export const bankUiSettings: BankUiSettings =
+ "talerDemobankSettings" in globalThis
+ ? (globalThis as any).talerDemobankSettings
+ : defaultSettings;