no-fix: move pagestate provider to app component and move some common hooks to web-utils
This commit is contained in:
parent
2dc3eb0ddd
commit
8e6bf99006
@ -1,11 +1,14 @@
|
|||||||
import { h, FunctionalComponent } from "preact";
|
import { h, FunctionalComponent } from "preact";
|
||||||
|
import { PageStateProvider } from "../context/pageState.js";
|
||||||
import { TranslationProvider } from "../context/translation.js";
|
import { TranslationProvider } from "../context/translation.js";
|
||||||
import { BankHome } from "../pages/home/index.js";
|
import { BankHome } from "../pages/home/index.js";
|
||||||
|
|
||||||
const App: FunctionalComponent = () => {
|
const App: FunctionalComponent = () => {
|
||||||
return (
|
return (
|
||||||
<TranslationProvider>
|
<TranslationProvider>
|
||||||
<BankHome />
|
<PageStateProvider>
|
||||||
|
<BankHome />
|
||||||
|
</PageStateProvider>
|
||||||
</TranslationProvider>
|
</TranslationProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
121
packages/demobank-ui/src/context/pageState.ts
Normal file
121
packages/demobank-ui/src/context/pageState.ts
Normal file
@ -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;
|
||||||
|
}
|
@ -22,7 +22,7 @@
|
|||||||
import { i18n, setupI18n } from "@gnu-taler/taler-util";
|
import { i18n, setupI18n } from "@gnu-taler/taler-util";
|
||||||
import { createContext, h, VNode } from "preact";
|
import { createContext, h, VNode } from "preact";
|
||||||
import { useContext, useEffect } from "preact/hooks";
|
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";
|
import { strings } from "../i18n/strings.js";
|
||||||
|
|
||||||
interface Type {
|
interface Type {
|
||||||
@ -70,7 +70,7 @@ export const TranslationProvider = ({
|
|||||||
children,
|
children,
|
||||||
forceLang,
|
forceLang,
|
||||||
}: Props): VNode => {
|
}: Props): VNode => {
|
||||||
const [lang, changeLanguage, isSaved] = useLang(initial);
|
const [lang, changeLanguage, isSaved] = hooks.useLang(initial);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (forceLang) {
|
if (forceLang) {
|
||||||
changeLanguage(forceLang);
|
changeLanguage(forceLang);
|
||||||
|
49
packages/demobank-ui/src/declaration.d.ts
vendored
49
packages/demobank-ui/src/declaration.d.ts
vendored
@ -18,3 +18,52 @@ declare module "jed" {
|
|||||||
const x: any;
|
const x: any;
|
||||||
export = x;
|
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;
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { StateUpdater } from "preact/hooks";
|
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);
|
export type ValueOrFunction<T> = T | ((p: T) => T);
|
||||||
|
|
||||||
const calculateRootPath = () => {
|
const calculateRootPath = () => {
|
||||||
@ -34,11 +34,11 @@ const calculateRootPath = () => {
|
|||||||
export function useBackendURL(
|
export function useBackendURL(
|
||||||
url?: string,
|
url?: string,
|
||||||
): [string, boolean, StateUpdater<string>, () => void] {
|
): [string, boolean, StateUpdater<string>, () => void] {
|
||||||
const [value, setter] = useNotNullLocalStorage(
|
const [value, setter] = hooks.useNotNullLocalStorage(
|
||||||
"backend-url",
|
"backend-url",
|
||||||
url || calculateRootPath(),
|
url || calculateRootPath(),
|
||||||
);
|
);
|
||||||
const [triedToLog, setTriedToLog] = useLocalStorage("tried-login");
|
const [triedToLog, setTriedToLog] = hooks.useLocalStorage("tried-login");
|
||||||
|
|
||||||
const checkedSetter = (v: ValueOrFunction<string>) => {
|
const checkedSetter = (v: ValueOrFunction<string>) => {
|
||||||
setTriedToLog("yes");
|
setTriedToLog("yes");
|
||||||
@ -55,13 +55,13 @@ export function useBackendDefaultToken(): [
|
|||||||
string | undefined,
|
string | undefined,
|
||||||
StateUpdater<string | undefined>,
|
StateUpdater<string | undefined>,
|
||||||
] {
|
] {
|
||||||
return useLocalStorage("backend-token");
|
return hooks.useLocalStorage("backend-token");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useBackendInstanceToken(
|
export function useBackendInstanceToken(
|
||||||
id: string,
|
id: string,
|
||||||
): [string | undefined, StateUpdater<string | undefined>] {
|
): [string | undefined, StateUpdater<string | undefined>] {
|
||||||
const [token, setToken] = useLocalStorage(`backend-token-${id}`);
|
const [token, setToken] = hooks.useLocalStorage(`backend-token-${id}`);
|
||||||
const [defaultToken, defaultSetToken] = useBackendDefaultToken();
|
const [defaultToken, defaultSetToken] = useBackendDefaultToken();
|
||||||
|
|
||||||
// instance named 'default' use the default token
|
// instance named 'default' use the default token
|
||||||
|
@ -27,44 +27,14 @@ import {
|
|||||||
} from "preact/hooks";
|
} from "preact/hooks";
|
||||||
import talerLogo from "../../assets/logo-white.svg";
|
import talerLogo from "../../assets/logo-white.svg";
|
||||||
import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector.js";
|
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 { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Amounts, HttpStatusCode, parsePaytoUri } from "@gnu-taler/taler-util";
|
import { Amounts, HttpStatusCode, parsePaytoUri } from "@gnu-taler/taler-util";
|
||||||
import { createHashHistory } from "history";
|
import { createHashHistory } from "history";
|
||||||
import Router, { Route, route } from "preact-router";
|
import Router, { Route, route } from "preact-router";
|
||||||
import { QrCodeSection } from "./QrCodeSection.js";
|
import { QrCodeSection } from "./QrCodeSection.js";
|
||||||
|
import { hooks } from "@gnu-taler/web-util/lib/index.browser";
|
||||||
interface BankUiSettings {
|
import { bankUiSettings } from "../../settings.js";
|
||||||
allowRegistrations: boolean;
|
import { PageStateType, usePageContext } from "../../context/pageState.js";
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME:
|
* FIXME:
|
||||||
@ -90,94 +60,6 @@ const bankUiSettings: BankUiSettings =
|
|||||||
/************
|
/************
|
||||||
* Contexts *
|
* 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.
|
* Bank account specific information.
|
||||||
@ -294,7 +176,7 @@ async function postToBackend(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function useTransactionPageNumber(): [number, StateUpdater<number>] {
|
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 retObj = JSON.parse(ret[0]);
|
||||||
const retSetter: StateUpdater<number> = function (val) {
|
const retSetter: StateUpdater<number> = function (val) {
|
||||||
const newVal =
|
const newVal =
|
||||||
@ -347,7 +229,10 @@ const getBankBackendBaseUrl = (): string => {
|
|||||||
function useShowPublicAccount(
|
function useShowPublicAccount(
|
||||||
state?: string,
|
state?: string,
|
||||||
): [string | undefined, StateUpdater<string | undefined>] {
|
): [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 retObj: string | undefined = ret[0] ? JSON.parse(ret[0]) : ret[0];
|
||||||
const retSetter: StateUpdater<string | undefined> = function (val) {
|
const retSetter: StateUpdater<string | undefined> = function (val) {
|
||||||
const newVal =
|
const newVal =
|
||||||
@ -367,7 +252,7 @@ type RawPaytoInputTypeOpt = RawPaytoInputType | undefined;
|
|||||||
function useRawPaytoInputType(
|
function useRawPaytoInputType(
|
||||||
state?: RawPaytoInputType,
|
state?: RawPaytoInputType,
|
||||||
): [RawPaytoInputTypeOpt, StateUpdater<RawPaytoInputTypeOpt>] {
|
): [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 retObj: RawPaytoInputTypeOpt = ret[0];
|
||||||
const retSetter: StateUpdater<RawPaytoInputTypeOpt> = function (val) {
|
const retSetter: StateUpdater<RawPaytoInputTypeOpt> = function (val) {
|
||||||
const newVal = val instanceof Function ? val(retObj) : val;
|
const newVal = val instanceof Function ? val(retObj) : val;
|
||||||
@ -387,7 +272,7 @@ type WireTransferRequestTypeOpt = WireTransferRequestType | undefined;
|
|||||||
function useWireTransferRequestType(
|
function useWireTransferRequestType(
|
||||||
state?: WireTransferRequestType,
|
state?: WireTransferRequestType,
|
||||||
): [WireTransferRequestTypeOpt, StateUpdater<WireTransferRequestTypeOpt>] {
|
): [WireTransferRequestTypeOpt, StateUpdater<WireTransferRequestTypeOpt>] {
|
||||||
const ret = useLocalStorage(
|
const ret = hooks.useLocalStorage(
|
||||||
"wire-transfer-request-state",
|
"wire-transfer-request-state",
|
||||||
JSON.stringify(state),
|
JSON.stringify(state),
|
||||||
);
|
);
|
||||||
@ -413,7 +298,7 @@ type CredentialsRequestTypeOpt = CredentialsRequestType | undefined;
|
|||||||
function useCredentialsRequestType(
|
function useCredentialsRequestType(
|
||||||
state?: CredentialsRequestType,
|
state?: CredentialsRequestType,
|
||||||
): [CredentialsRequestTypeOpt, StateUpdater<CredentialsRequestTypeOpt>] {
|
): [CredentialsRequestTypeOpt, StateUpdater<CredentialsRequestTypeOpt>] {
|
||||||
const ret = useLocalStorage(
|
const ret = hooks.useLocalStorage(
|
||||||
"credentials-request-state",
|
"credentials-request-state",
|
||||||
JSON.stringify(state),
|
JSON.stringify(state),
|
||||||
);
|
);
|
||||||
@ -439,7 +324,7 @@ type BackendStateTypeOpt = BackendStateType | undefined;
|
|||||||
function useBackendState(
|
function useBackendState(
|
||||||
state?: BackendStateType,
|
state?: BackendStateType,
|
||||||
): [BackendStateTypeOpt, StateUpdater<BackendStateTypeOpt>] {
|
): [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 retObj: BackendStateTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0];
|
||||||
const retSetter: StateUpdater<BackendStateTypeOpt> = function (val) {
|
const retSetter: StateUpdater<BackendStateTypeOpt> = function (val) {
|
||||||
const newVal =
|
const newVal =
|
||||||
@ -451,67 +336,6 @@ function useBackendState(
|
|||||||
return [retObj, retSetter];
|
return [retObj, retSetter];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Request preparators.
|
||||||
*
|
*
|
||||||
@ -1045,7 +869,7 @@ function StatusBanner(Props: any): VNode | null {
|
|||||||
|
|
||||||
function BankFrame(Props: any): VNode {
|
function BankFrame(Props: any): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const [pageState, pageStateSetter] = useContext(PageContext);
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
console.log("BankFrame state", pageState);
|
console.log("BankFrame state", pageState);
|
||||||
const logOut = (
|
const logOut = (
|
||||||
<div class="logout">
|
<div class="logout">
|
||||||
@ -1164,19 +988,16 @@ function ShowInputErrorLabel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function PaytoWireTransfer(Props: any): VNode {
|
function PaytoWireTransfer(Props: any): VNode {
|
||||||
const currency = useContext(CurrencyContext);
|
const { pageState, pageStateSetter } = usePageContext(); // NOTE: used for go-back button?
|
||||||
const [pageState, pageStateSetter] = useContext(PageContext); // NOTE: used for go-back button?
|
|
||||||
const [submitData, submitDataSetter] = useWireTransferRequestType();
|
const [submitData, submitDataSetter] = useWireTransferRequestType();
|
||||||
// const [rawPaytoInput, rawPaytoInputSetter] = useRawPaytoInputType();
|
|
||||||
const [rawPaytoInput, rawPaytoInputSetter] = useState<string | undefined>(
|
const [rawPaytoInput, rawPaytoInputSetter] = useState<string | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const { focus, backendState } = Props;
|
const { focus, backendState, currency } = Props;
|
||||||
const amountRegex = "^[0-9]+(.[0-9]+)?$";
|
|
||||||
const ibanRegex = "^[A-Z][A-Z][0-9]+$";
|
const ibanRegex = "^[A-Z][A-Z][0-9]+$";
|
||||||
const receiverInput = "";
|
|
||||||
const subjectInput = "";
|
|
||||||
let transactionData: TransactionRequestType;
|
let transactionData: TransactionRequestType;
|
||||||
const ref = useRef<HTMLInputElement>(null);
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -1213,7 +1034,7 @@ function PaytoWireTransfer(Props: any): VNode {
|
|||||||
if (!pageState.isRawPayto)
|
if (!pageState.isRawPayto)
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div class="pure-form" name="wire-transfer-form">
|
<form class="pure-form" name="wire-transfer-form">
|
||||||
<p>
|
<p>
|
||||||
<label for="iban">{i18n.str`Receiver IBAN:`}</label>
|
<label for="iban">{i18n.str`Receiver IBAN:`}</label>
|
||||||
<input
|
<input
|
||||||
@ -1260,22 +1081,6 @@ function PaytoWireTransfer(Props: any): VNode {
|
|||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<label for="amount">{i18n.str`Amount:`}</label>
|
<label for="amount">{i18n.str`Amount:`}</label>
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
name="amount"
|
|
||||||
id="amount"
|
|
||||||
placeholder="amount"
|
|
||||||
required
|
|
||||||
value={submitData?.amount ?? ""}
|
|
||||||
pattern={amountRegex}
|
|
||||||
onInput={(e): void => {
|
|
||||||
submitDataSetter((submitData: any) => ({
|
|
||||||
...submitData,
|
|
||||||
amount: e.currentTarget.value,
|
|
||||||
}));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
readonly
|
readonly
|
||||||
@ -1285,6 +1090,21 @@ function PaytoWireTransfer(Props: any): VNode {
|
|||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
value={currency}
|
value={currency}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="amount"
|
||||||
|
id="amount"
|
||||||
|
placeholder="amount"
|
||||||
|
required
|
||||||
|
value={submitData?.amount ?? ""}
|
||||||
|
onInput={(e): void => {
|
||||||
|
submitDataSetter((submitData: any) => ({
|
||||||
|
...submitData,
|
||||||
|
amount: e.currentTarget.value,
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<ShowInputErrorLabel
|
<ShowInputErrorLabel
|
||||||
message={errorsWire?.amount}
|
message={errorsWire?.amount}
|
||||||
isDirty={submitData?.amount !== undefined}
|
isDirty={submitData?.amount !== undefined}
|
||||||
@ -1349,7 +1169,7 @@ function PaytoWireTransfer(Props: any): VNode {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</form>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
href="/account"
|
href="/account"
|
||||||
@ -1460,7 +1280,7 @@ function PaytoWireTransfer(Props: any): VNode {
|
|||||||
* Not providing a back button, only abort.
|
* Not providing a back button, only abort.
|
||||||
*/
|
*/
|
||||||
function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
|
function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
|
||||||
const [pageState, pageStateSetter] = useContext(PageContext);
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
const { backendState } = Props;
|
const { backendState } = Props;
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const captchaNumbers = {
|
const captchaNumbers = {
|
||||||
@ -1474,7 +1294,7 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
|
|||||||
<h1 class="nav">{i18n.str`Confirm Withdrawal`}</h1>
|
<h1 class="nav">{i18n.str`Confirm Withdrawal`}</h1>
|
||||||
<article>
|
<article>
|
||||||
<div class="challenge-div">
|
<div class="challenge-div">
|
||||||
<form class="challenge-form">
|
<form class="challenge-form" noValidate>
|
||||||
<div class="pure-form" id="captcha" name="capcha-form">
|
<div class="pure-form" id="captcha" name="capcha-form">
|
||||||
<h2>{i18n.str`Authorize withdrawal by solving challenge`}</h2>
|
<h2>{i18n.str`Authorize withdrawal by solving challenge`}</h2>
|
||||||
<p>
|
<p>
|
||||||
@ -1562,8 +1382,8 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
|
|||||||
*/
|
*/
|
||||||
function TalerWithdrawalQRCode(Props: any): VNode {
|
function TalerWithdrawalQRCode(Props: any): VNode {
|
||||||
// turns true when the wallet POSTed the reserve details:
|
// turns true when the wallet POSTed the reserve details:
|
||||||
const [pageState, pageStateSetter] = useContext(PageContext);
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
const { withdrawalId, talerWithdrawUri, accountLabel, backendState } = Props;
|
const { withdrawalId, talerWithdrawUri, backendState } = Props;
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const abortButton = (
|
const abortButton = (
|
||||||
<a
|
<a
|
||||||
@ -1647,37 +1467,19 @@ function TalerWithdrawalQRCode(Props: any): VNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function WalletWithdraw(Props: any): VNode {
|
function WalletWithdraw(Props: any): VNode {
|
||||||
const { backendState, pageStateSetter, focus } = Props;
|
const { backendState, pageStateSetter, focus, currency } = Props;
|
||||||
const currency = useContext(CurrencyContext);
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
let submitAmount = "5.00";
|
let submitAmount = "5.00";
|
||||||
const amountRegex = "^[0-9]+(.[0-9]+)?$";
|
|
||||||
|
|
||||||
const ref = useRef<HTMLInputElement>(null);
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (focus) ref.current?.focus();
|
if (focus) ref.current?.focus();
|
||||||
}, [focus]);
|
}, [focus]);
|
||||||
return (
|
return (
|
||||||
<div id="reserve-form" class="pure-form" name="tform">
|
<form id="reserve-form" class="pure-form" name="tform">
|
||||||
<p>
|
<p>
|
||||||
<label for="withdraw-amount">{i18n.str`Amount to withdraw:`}</label>
|
<label for="withdraw-amount">{i18n.str`Amount to withdraw:`}</label>
|
||||||
|
|
||||||
<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
|
|
||||||
// amount is not valid
|
|
||||||
submitAmount = e.currentTarget.value;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
readonly
|
readonly
|
||||||
@ -1687,6 +1489,20 @@ function WalletWithdraw(Props: any): VNode {
|
|||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
value={currency}
|
value={currency}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
ref={ref}
|
||||||
|
id="withdraw-amount"
|
||||||
|
name="withdraw-amount"
|
||||||
|
value={submitAmount}
|
||||||
|
onChange={(e): void => {
|
||||||
|
// FIXME: validate using 'parseAmount()',
|
||||||
|
// deactivate submit button as long as
|
||||||
|
// amount is not valid
|
||||||
|
submitAmount = e.currentTarget.value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<div>
|
<div>
|
||||||
@ -1712,7 +1528,7 @@ function WalletWithdraw(Props: any): VNode {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1721,8 +1537,7 @@ function WalletWithdraw(Props: any): VNode {
|
|||||||
* then specify the details trigger the action.
|
* then specify the details trigger the action.
|
||||||
*/
|
*/
|
||||||
function PaymentOptions(Props: any): VNode {
|
function PaymentOptions(Props: any): VNode {
|
||||||
const { backendState, pageStateSetter, focus } = Props;
|
const { backendState, pageStateSetter, currency } = Props;
|
||||||
const currency = useContext(CurrencyContext);
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const [tab, setTab] = useState<"charge-wallet" | "wire-transfer">(
|
const [tab, setTab] = useState<"charge-wallet" | "wire-transfer">(
|
||||||
@ -1756,6 +1571,7 @@ function PaymentOptions(Props: any): VNode {
|
|||||||
<WalletWithdraw
|
<WalletWithdraw
|
||||||
backendState={backendState}
|
backendState={backendState}
|
||||||
focus
|
focus
|
||||||
|
currency={currency}
|
||||||
pageStateSetter={pageStateSetter}
|
pageStateSetter={pageStateSetter}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -1766,6 +1582,7 @@ function PaymentOptions(Props: any): VNode {
|
|||||||
<PaytoWireTransfer
|
<PaytoWireTransfer
|
||||||
backendState={backendState}
|
backendState={backendState}
|
||||||
focus
|
focus
|
||||||
|
currency={currency}
|
||||||
pageStateSetter={pageStateSetter}
|
pageStateSetter={pageStateSetter}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -1819,7 +1636,7 @@ function LoginForm(Props: any): VNode {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="login-div">
|
<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">
|
<div class="pure-form">
|
||||||
<h2>{i18n.str`Please login!`}</h2>
|
<h2>{i18n.str`Please login!`}</h2>
|
||||||
<p class="unameFieldLabel loginFieldLabel formFieldLabel">
|
<p class="unameFieldLabel loginFieldLabel formFieldLabel">
|
||||||
@ -1903,7 +1720,7 @@ function LoginForm(Props: any): VNode {
|
|||||||
*/
|
*/
|
||||||
function RegistrationForm(Props: any): VNode {
|
function RegistrationForm(Props: any): VNode {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const [pageState, pageStateSetter] = useContext(PageContext);
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
const [submitData, submitDataSetter] = useCredentialsRequestType();
|
const [submitData, submitDataSetter] = useCredentialsRequestType();
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
@ -1924,7 +1741,7 @@ function RegistrationForm(Props: any): VNode {
|
|||||||
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
|
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
|
||||||
<article>
|
<article>
|
||||||
<div class="register-div">
|
<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">
|
<div class="pure-form">
|
||||||
<h2>{i18n.str`Please register!`}</h2>
|
<h2>{i18n.str`Please register!`}</h2>
|
||||||
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
||||||
@ -2140,7 +1957,7 @@ function Account(Props: any): VNode {
|
|||||||
// revalidateOnFocus: false,
|
// revalidateOnFocus: false,
|
||||||
// revalidateOnReconnect: false,
|
// revalidateOnReconnect: false,
|
||||||
});
|
});
|
||||||
const [pageState, setPageState] = useContext(PageContext);
|
const { pageState, pageStateSetter: setPageState } = usePageContext();
|
||||||
const {
|
const {
|
||||||
withdrawalInProgress,
|
withdrawalInProgress,
|
||||||
withdrawalId,
|
withdrawalId,
|
||||||
@ -2275,14 +2092,11 @@ function Account(Props: any): VNode {
|
|||||||
<section id="payments">
|
<section id="payments">
|
||||||
<div class="payments">
|
<div class="payments">
|
||||||
<h2>{i18n.str`Payments`}</h2>
|
<h2>{i18n.str`Payments`}</h2>
|
||||||
{/* FIXME: turn into button! */}
|
<PaymentOptions
|
||||||
<CurrencyContext.Provider value={balance.currency}>
|
currency={balance.currency}
|
||||||
{Props.children}
|
backendState={backendState}
|
||||||
<PaymentOptions
|
pageStateSetter={setPageState}
|
||||||
backendState={backendState}
|
/>
|
||||||
pageStateSetter={setPageState}
|
|
||||||
/>
|
|
||||||
</CurrencyContext.Provider>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section id="main">
|
<section id="main">
|
||||||
@ -2439,71 +2253,61 @@ function PublicHistories(Props: any): VNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function PublicHistoriesPage(): VNode {
|
function PublicHistoriesPage(): VNode {
|
||||||
// const [backendState, backendStateSetter] = useBackendState();
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
const [pageState, pageStateSetter] = usePageState();
|
|
||||||
// const { i18n } = useTranslationContext();
|
// const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
<SWRWithoutCredentials baseUrl={getBankBackendBaseUrl()}>
|
<SWRWithoutCredentials baseUrl={getBankBackendBaseUrl()}>
|
||||||
<PageContext.Provider value={[pageState, pageStateSetter]}>
|
<BankFrame>
|
||||||
<BankFrame>
|
<PublicHistories pageStateSetter={pageStateSetter}>
|
||||||
<PublicHistories pageStateSetter={pageStateSetter}>
|
<br />
|
||||||
<br />
|
<a
|
||||||
<a
|
class="pure-button"
|
||||||
class="pure-button"
|
onClick={() => {
|
||||||
onClick={() => {
|
pageStateSetter((prevState: PageStateType) => ({
|
||||||
pageStateSetter((prevState: PageStateType) => ({
|
...prevState,
|
||||||
...prevState,
|
showPublicHistories: false,
|
||||||
showPublicHistories: false,
|
}));
|
||||||
}));
|
}}
|
||||||
}}
|
>
|
||||||
>
|
Go back
|
||||||
Go back
|
</a>
|
||||||
</a>
|
</PublicHistories>
|
||||||
</PublicHistories>
|
</BankFrame>
|
||||||
</BankFrame>
|
|
||||||
</PageContext.Provider>
|
|
||||||
</SWRWithoutCredentials>
|
</SWRWithoutCredentials>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function RegistrationPage(): VNode {
|
function RegistrationPage(): VNode {
|
||||||
const [backendState, backendStateSetter] = useBackendState();
|
const [backendState, backendStateSetter] = useBackendState();
|
||||||
const [pageState, pageStateSetter] = usePageState();
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
if (!bankUiSettings.allowRegistrations) {
|
if (!bankUiSettings.allowRegistrations) {
|
||||||
return (
|
return (
|
||||||
<PageContext.Provider value={[pageState, pageStateSetter]}>
|
<BankFrame>
|
||||||
<BankFrame>
|
<p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
|
||||||
<p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
|
</BankFrame>
|
||||||
</BankFrame>
|
|
||||||
</PageContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<PageContext.Provider value={[pageState, pageStateSetter]}>
|
<BankFrame>
|
||||||
<BankFrame>
|
<RegistrationForm backendStateSetter={backendStateSetter} />
|
||||||
<RegistrationForm backendStateSetter={backendStateSetter} />
|
</BankFrame>
|
||||||
</BankFrame>
|
|
||||||
</PageContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AccountPage(): VNode {
|
function AccountPage(): VNode {
|
||||||
const [backendState, backendStateSetter] = useBackendState();
|
const [backendState, backendStateSetter] = useBackendState();
|
||||||
const [pageState, pageStateSetter] = usePageState();
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
|
|
||||||
if (!pageState.isLoggedIn) {
|
if (!pageState.isLoggedIn) {
|
||||||
return (
|
return (
|
||||||
<PageContext.Provider value={[pageState, pageStateSetter]}>
|
<BankFrame>
|
||||||
<BankFrame>
|
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
|
||||||
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
|
<LoginForm
|
||||||
<LoginForm
|
pageStateSetter={pageStateSetter}
|
||||||
pageStateSetter={pageStateSetter}
|
backendStateSetter={backendStateSetter}
|
||||||
backendStateSetter={backendStateSetter}
|
/>
|
||||||
/>
|
</BankFrame>
|
||||||
</BankFrame>
|
|
||||||
</PageContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2525,12 +2329,10 @@ function AccountPage(): VNode {
|
|||||||
password={backendState.password}
|
password={backendState.password}
|
||||||
backendUrl={backendState.url}
|
backendUrl={backendState.url}
|
||||||
>
|
>
|
||||||
<PageContext.Provider value={[pageState, pageStateSetter]}>
|
<Account
|
||||||
<Account
|
accountLabel={backendState.username}
|
||||||
accountLabel={backendState.username}
|
backendState={backendState}
|
||||||
backendState={backendState}
|
/>
|
||||||
/>
|
|
||||||
</PageContext.Provider>
|
|
||||||
</SWRWithCredentials>
|
</SWRWithCredentials>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
27
packages/demobank-ui/src/settings.ts
Normal file
27
packages/demobank-ui/src/settings.ts
Normal file
@ -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;
|
3
packages/web-util/src/hooks/index.ts
Normal file
3
packages/web-util/src/hooks/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
export { useLang } from "./useLang.js";
|
||||||
|
export { useLocalStorage, useNotNullLocalStorage } from "./useLocalStorage.js"
|
@ -1,37 +1,2 @@
|
|||||||
//`ws://localhost:8003/socket`
|
export * as hooks from "./hooks/index.js";
|
||||||
export function setupLiveReload(wsURL: string | undefined) {
|
|
||||||
if (!wsURL) return;
|
|
||||||
const ws = new WebSocket(wsURL);
|
|
||||||
ws.addEventListener("message", (message) => {
|
|
||||||
const event = JSON.parse(message.data);
|
|
||||||
if (event.type === "LOG") {
|
|
||||||
console.log(event.message);
|
|
||||||
}
|
|
||||||
if (event.type === "RELOAD") {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
if (event.type === "UPDATE") {
|
|
||||||
const c = document.getElementById("container");
|
|
||||||
if (c) {
|
|
||||||
document.body.removeChild(c);
|
|
||||||
}
|
|
||||||
const d = document.createElement("div");
|
|
||||||
d.setAttribute("id", "container");
|
|
||||||
d.setAttribute("class", "app-container");
|
|
||||||
document.body.appendChild(d);
|
|
||||||
const s = document.createElement("script");
|
|
||||||
s.setAttribute("id", "code");
|
|
||||||
s.setAttribute("type", "application/javascript");
|
|
||||||
s.textContent = atob(event.content);
|
|
||||||
document.body.appendChild(s);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ws.onerror = (error) => {
|
|
||||||
console.error(error);
|
|
||||||
};
|
|
||||||
ws.onclose = (e) => {
|
|
||||||
setTimeout(setupLiveReload, 500);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export { renderStories, parseGroupImport } from "./stories.js";
|
export { renderStories, parseGroupImport } from "./stories.js";
|
||||||
|
@ -17,7 +17,7 @@ function setupLiveReload(): void {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("unsupported", event);
|
console.log("unsupported", message);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("error", (error) => {
|
ws.addEventListener("error", (error) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user