no-fix: moving out registration page
This commit is contained in:
parent
5d5b63416b
commit
e4a2937f2a
@ -1,9 +1,26 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 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 { createHashHistory } from "history";
|
import { createHashHistory } from "history";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import Router, { route, Route } from "preact-router";
|
import Router, { route, Route } from "preact-router";
|
||||||
import { useEffect } from "preact/hooks";
|
import { useEffect } from "preact/hooks";
|
||||||
import { AccountPage, RegistrationPage } from "./home/index.js";
|
import { AccountPage } from "./home/index.js";
|
||||||
import { PublicHistoriesPage } from "./home/PublicHistoriesPage.js";
|
import { PublicHistoriesPage } from "./home/PublicHistoriesPage.js";
|
||||||
|
import { RegistrationPage } from "./home/RegistrationPage.js";
|
||||||
|
|
||||||
export function Routing(): VNode {
|
export function Routing(): VNode {
|
||||||
const history = createHashHistory();
|
const history = createHashHistory();
|
||||||
|
254
packages/demobank-ui/src/pages/home/RegistrationPage.tsx
Normal file
254
packages/demobank-ui/src/pages/home/RegistrationPage.tsx
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 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 { Fragment, h, VNode } from "preact";
|
||||||
|
import { route } from "preact-router";
|
||||||
|
import { StateUpdater, useState } from "preact/hooks";
|
||||||
|
import { PageStateType, usePageContext } from "../../context/pageState.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
|
import { BackendStateType, useBackendState } from "../../hooks/backend.js";
|
||||||
|
import { bankUiSettings } from "../../settings.js";
|
||||||
|
import { getBankBackendBaseUrl, undefinedIfEmpty } from "../../utils.js";
|
||||||
|
import { BankFrame } from "./BankFrame.js";
|
||||||
|
import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js";
|
||||||
|
|
||||||
|
export function RegistrationPage(): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
if (!bankUiSettings.allowRegistrations) {
|
||||||
|
return (
|
||||||
|
<BankFrame>
|
||||||
|
<p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
|
||||||
|
</BankFrame>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<BankFrame>
|
||||||
|
<RegistrationForm />
|
||||||
|
</BankFrame>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect and submit registration data.
|
||||||
|
*/
|
||||||
|
function RegistrationForm(): VNode {
|
||||||
|
const [backendState, backendStateSetter] = useBackendState();
|
||||||
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
|
const [username, setUsername] = useState<string | undefined>();
|
||||||
|
const [password, setPassword] = useState<string | undefined>();
|
||||||
|
const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
|
||||||
|
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
|
const errors = undefinedIfEmpty({
|
||||||
|
username: !username ? i18n.str`Missing username` : undefined,
|
||||||
|
password: !password ? i18n.str`Missing password` : undefined,
|
||||||
|
repeatPassword: !repeatPassword
|
||||||
|
? i18n.str`Missing password`
|
||||||
|
: repeatPassword !== password
|
||||||
|
? i18n.str`Password don't match`
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
|
||||||
|
<article>
|
||||||
|
<div class="register-div">
|
||||||
|
<form action="javascript:void(0);" class="register-form" noValidate>
|
||||||
|
<div class="pure-form">
|
||||||
|
<h2>{i18n.str`Please register!`}</h2>
|
||||||
|
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
||||||
|
<label for="register-un">{i18n.str`Username:`}</label>
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
id="register-un"
|
||||||
|
name="register-un"
|
||||||
|
type="text"
|
||||||
|
placeholder="Username"
|
||||||
|
value={username ?? ""}
|
||||||
|
onInput={(e): void => {
|
||||||
|
setUsername(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.username}
|
||||||
|
isDirty={username !== undefined}
|
||||||
|
/>
|
||||||
|
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
||||||
|
<label for="register-pw">{i18n.str`Password:`}</label>
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="register-pw"
|
||||||
|
id="register-pw"
|
||||||
|
placeholder="Password"
|
||||||
|
value={password ?? ""}
|
||||||
|
required
|
||||||
|
onInput={(e): void => {
|
||||||
|
setPassword(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.password}
|
||||||
|
isDirty={password !== undefined}
|
||||||
|
/>
|
||||||
|
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
||||||
|
<label for="register-repeat">{i18n.str`Repeat Password:`}</label>
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
style={{ marginBottom: 8 }}
|
||||||
|
name="register-repeat"
|
||||||
|
id="register-repeat"
|
||||||
|
placeholder="Same password"
|
||||||
|
value={repeatPassword ?? ""}
|
||||||
|
required
|
||||||
|
onInput={(e): void => {
|
||||||
|
setRepeatPassword(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.repeatPassword}
|
||||||
|
isDirty={repeatPassword !== undefined}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<button
|
||||||
|
class="pure-button pure-button-primary btn-register"
|
||||||
|
disabled={!!errors}
|
||||||
|
onClick={() => {
|
||||||
|
if (!username || !password) return;
|
||||||
|
registrationCall(
|
||||||
|
{ username, password },
|
||||||
|
backendStateSetter, // will store BE URL, if OK.
|
||||||
|
pageStateSetter,
|
||||||
|
);
|
||||||
|
|
||||||
|
setUsername(undefined);
|
||||||
|
setPassword(undefined);
|
||||||
|
setRepeatPassword(undefined);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.str`Register`}
|
||||||
|
</button>
|
||||||
|
{/* FIXME: should use a different color */}
|
||||||
|
<button
|
||||||
|
class="pure-button pure-button-secondary btn-cancel"
|
||||||
|
onClick={() => {
|
||||||
|
setUsername(undefined);
|
||||||
|
setPassword(undefined);
|
||||||
|
setRepeatPassword(undefined);
|
||||||
|
route("/account");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.str`Cancel`}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function requests /register.
|
||||||
|
*
|
||||||
|
* This function is responsible to change two states:
|
||||||
|
* the backend's (to store the login credentials) and
|
||||||
|
* the page's (to indicate a successful login or a problem).
|
||||||
|
*/
|
||||||
|
async function registrationCall(
|
||||||
|
req: { username: string; password: string },
|
||||||
|
/**
|
||||||
|
* FIXME: figure out if the two following
|
||||||
|
* functions can be retrieved somewhat from
|
||||||
|
* the state.
|
||||||
|
*/
|
||||||
|
backendStateSetter: StateUpdater<BackendStateType | undefined>,
|
||||||
|
pageStateSetter: StateUpdater<PageStateType>,
|
||||||
|
): Promise<void> {
|
||||||
|
let baseUrl = getBankBackendBaseUrl();
|
||||||
|
/**
|
||||||
|
* If the base URL doesn't end with slash and the path
|
||||||
|
* is not empty, then the concatenation made by URL()
|
||||||
|
* drops the last path element.
|
||||||
|
*/
|
||||||
|
if (!baseUrl.endsWith("/")) baseUrl += "/";
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append("Content-Type", "application/json");
|
||||||
|
const url = new URL("access-api/testing/register", baseUrl);
|
||||||
|
let res: Response;
|
||||||
|
try {
|
||||||
|
res = await fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: req.username,
|
||||||
|
password: req.password,
|
||||||
|
}),
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
`Could not POST new registration to the bank (${url.href})`,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
pageStateSetter((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
|
||||||
|
error: {
|
||||||
|
title: `Registration failed, please report`,
|
||||||
|
debug: JSON.stringify(error),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!res.ok) {
|
||||||
|
const response = await res.json();
|
||||||
|
if (res.status === 409) {
|
||||||
|
pageStateSetter((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
|
||||||
|
error: {
|
||||||
|
title: `That username is already taken`,
|
||||||
|
debug: JSON.stringify(response),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
pageStateSetter((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
|
||||||
|
error: {
|
||||||
|
title: `New registration gave response error`,
|
||||||
|
debug: JSON.stringify(response),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// registration was ok
|
||||||
|
pageStateSetter((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
isLoggedIn: true,
|
||||||
|
}));
|
||||||
|
backendStateSetter((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
url: baseUrl,
|
||||||
|
username: req.username,
|
||||||
|
password: req.password,
|
||||||
|
}));
|
||||||
|
route("/account");
|
||||||
|
}
|
||||||
|
}
|
29
packages/demobank-ui/src/pages/home/ShowInputErrorLabel.tsx
Normal file
29
packages/demobank-ui/src/pages/home/ShowInputErrorLabel.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 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 { Fragment, h, VNode } from "preact";
|
||||||
|
|
||||||
|
export function ShowInputErrorLabel({
|
||||||
|
isDirty,
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
message: string | undefined;
|
||||||
|
isDirty: boolean;
|
||||||
|
}): VNode {
|
||||||
|
if (message && isDirty)
|
||||||
|
return <div style={{ marginTop: 8, color: "red" }}>{message}</div>;
|
||||||
|
return <Fragment />;
|
||||||
|
}
|
@ -30,10 +30,12 @@ import { QrCodeSection } from "./QrCodeSection.js";
|
|||||||
import {
|
import {
|
||||||
getBankBackendBaseUrl,
|
getBankBackendBaseUrl,
|
||||||
getIbanFromPayto,
|
getIbanFromPayto,
|
||||||
|
undefinedIfEmpty,
|
||||||
validateAmount,
|
validateAmount,
|
||||||
} from "../../utils.js";
|
} from "../../utils.js";
|
||||||
import { BankFrame } from "./BankFrame.js";
|
import { BankFrame } from "./BankFrame.js";
|
||||||
import { Transactions } from "./Transactions.js";
|
import { Transactions } from "./Transactions.js";
|
||||||
|
import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME:
|
* FIXME:
|
||||||
@ -553,112 +555,10 @@ async function loginCall(
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function requests /register.
|
|
||||||
*
|
|
||||||
* This function is responsible to change two states:
|
|
||||||
* the backend's (to store the login credentials) and
|
|
||||||
* the page's (to indicate a successful login or a problem).
|
|
||||||
*/
|
|
||||||
async function registrationCall(
|
|
||||||
req: { username: string; password: string },
|
|
||||||
/**
|
|
||||||
* FIXME: figure out if the two following
|
|
||||||
* functions can be retrieved somewhat from
|
|
||||||
* the state.
|
|
||||||
*/
|
|
||||||
backendStateSetter: StateUpdater<BackendStateType | undefined>,
|
|
||||||
pageStateSetter: StateUpdater<PageStateType>,
|
|
||||||
): Promise<void> {
|
|
||||||
let baseUrl = getBankBackendBaseUrl();
|
|
||||||
/**
|
|
||||||
* If the base URL doesn't end with slash and the path
|
|
||||||
* is not empty, then the concatenation made by URL()
|
|
||||||
* drops the last path element.
|
|
||||||
*/
|
|
||||||
if (!baseUrl.endsWith("/")) baseUrl += "/";
|
|
||||||
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.append("Content-Type", "application/json");
|
|
||||||
const url = new URL("access-api/testing/register", baseUrl);
|
|
||||||
let res: Response;
|
|
||||||
try {
|
|
||||||
res = await fetch(url.href, {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
username: req.username,
|
|
||||||
password: req.password,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
`Could not POST new registration to the bank (${url.href})`,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
pageStateSetter((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
|
|
||||||
error: {
|
|
||||||
title: `Registration failed, please report`,
|
|
||||||
debug: JSON.stringify(error),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!res.ok) {
|
|
||||||
const response = await res.json();
|
|
||||||
if (res.status === 409) {
|
|
||||||
pageStateSetter((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
|
|
||||||
error: {
|
|
||||||
title: `That username is already taken`,
|
|
||||||
debug: JSON.stringify(response),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
pageStateSetter((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
|
|
||||||
error: {
|
|
||||||
title: `New registration gave response error`,
|
|
||||||
debug: JSON.stringify(response),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// registration was ok
|
|
||||||
pageStateSetter((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
isLoggedIn: true,
|
|
||||||
}));
|
|
||||||
backendStateSetter((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
url: baseUrl,
|
|
||||||
username: req.username,
|
|
||||||
password: req.password,
|
|
||||||
}));
|
|
||||||
route("/account");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
* Functional components. *
|
* Functional components. *
|
||||||
*************************/
|
*************************/
|
||||||
|
|
||||||
function ShowInputErrorLabel({
|
|
||||||
isDirty,
|
|
||||||
message,
|
|
||||||
}: {
|
|
||||||
message: string | undefined;
|
|
||||||
isDirty: boolean;
|
|
||||||
}): VNode {
|
|
||||||
if (message && isDirty)
|
|
||||||
return <div style={{ marginTop: 8, color: "red" }}>{message}</div>;
|
|
||||||
return <Fragment />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function PaytoWireTransfer({
|
function PaytoWireTransfer({
|
||||||
focus,
|
focus,
|
||||||
currency,
|
currency,
|
||||||
@ -1257,11 +1157,6 @@ function PaymentOptions({ currency }: { currency?: string }): VNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
|
|
||||||
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
|
|
||||||
? obj
|
|
||||||
: undefined;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Collect and submit login data.
|
* Collect and submit login data.
|
||||||
*/
|
*/
|
||||||
@ -1361,129 +1256,6 @@ function LoginForm(): VNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect and submit registration data.
|
|
||||||
*/
|
|
||||||
function RegistrationForm(): VNode {
|
|
||||||
const [backendState, backendStateSetter] = useBackendState();
|
|
||||||
const { pageState, pageStateSetter } = usePageContext();
|
|
||||||
const [username, setUsername] = useState<string | undefined>();
|
|
||||||
const [password, setPassword] = useState<string | undefined>();
|
|
||||||
const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
|
|
||||||
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
const errors = undefinedIfEmpty({
|
|
||||||
username: !username ? i18n.str`Missing username` : undefined,
|
|
||||||
password: !password ? i18n.str`Missing password` : undefined,
|
|
||||||
repeatPassword: !repeatPassword
|
|
||||||
? i18n.str`Missing password`
|
|
||||||
: repeatPassword !== password
|
|
||||||
? i18n.str`Password don't match`
|
|
||||||
: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
|
|
||||||
<article>
|
|
||||||
<div class="register-div">
|
|
||||||
<form action="javascript:void(0);" class="register-form" noValidate>
|
|
||||||
<div class="pure-form">
|
|
||||||
<h2>{i18n.str`Please register!`}</h2>
|
|
||||||
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
|
||||||
<label for="register-un">{i18n.str`Username:`}</label>
|
|
||||||
</p>
|
|
||||||
<input
|
|
||||||
id="register-un"
|
|
||||||
name="register-un"
|
|
||||||
type="text"
|
|
||||||
placeholder="Username"
|
|
||||||
value={username ?? ""}
|
|
||||||
onInput={(e): void => {
|
|
||||||
setUsername(e.currentTarget.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ShowInputErrorLabel
|
|
||||||
message={errors?.username}
|
|
||||||
isDirty={username !== undefined}
|
|
||||||
/>
|
|
||||||
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
|
||||||
<label for="register-pw">{i18n.str`Password:`}</label>
|
|
||||||
</p>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
name="register-pw"
|
|
||||||
id="register-pw"
|
|
||||||
placeholder="Password"
|
|
||||||
value={password ?? ""}
|
|
||||||
required
|
|
||||||
onInput={(e): void => {
|
|
||||||
setPassword(e.currentTarget.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ShowInputErrorLabel
|
|
||||||
message={errors?.password}
|
|
||||||
isDirty={username !== undefined}
|
|
||||||
/>
|
|
||||||
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
|
||||||
<label for="register-repeat">{i18n.str`Repeat Password:`}</label>
|
|
||||||
</p>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
style={{ marginBottom: 8 }}
|
|
||||||
name="register-repeat"
|
|
||||||
id="register-repeat"
|
|
||||||
placeholder="Same password"
|
|
||||||
value={repeatPassword ?? ""}
|
|
||||||
required
|
|
||||||
onInput={(e): void => {
|
|
||||||
setRepeatPassword(e.currentTarget.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ShowInputErrorLabel
|
|
||||||
message={errors?.repeatPassword}
|
|
||||||
isDirty={username !== undefined}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<button
|
|
||||||
class="pure-button pure-button-primary btn-register"
|
|
||||||
disabled={!!errors}
|
|
||||||
onClick={() => {
|
|
||||||
if (!username || !password) return;
|
|
||||||
registrationCall(
|
|
||||||
{ username, password },
|
|
||||||
backendStateSetter, // will store BE URL, if OK.
|
|
||||||
pageStateSetter,
|
|
||||||
);
|
|
||||||
|
|
||||||
setUsername(undefined);
|
|
||||||
setPassword(undefined);
|
|
||||||
setRepeatPassword(undefined);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.str`Register`}
|
|
||||||
</button>
|
|
||||||
{/* FIXME: should use a different color */}
|
|
||||||
<button
|
|
||||||
class="pure-button pure-button-secondary btn-cancel"
|
|
||||||
onClick={() => {
|
|
||||||
setUsername(undefined);
|
|
||||||
setPassword(undefined);
|
|
||||||
setRepeatPassword(undefined);
|
|
||||||
route("/account");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.str`Cancel`}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show only the account's balance. NOTE: the backend state
|
* Show only the account's balance. NOTE: the backend state
|
||||||
* is mostly needed to provide the user's credentials to POST
|
* is mostly needed to provide the user's credentials to POST
|
||||||
@ -1689,22 +1461,6 @@ function SWRWithCredentials(props: any): VNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RegistrationPage(): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
if (!bankUiSettings.allowRegistrations) {
|
|
||||||
return (
|
|
||||||
<BankFrame>
|
|
||||||
<p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
|
|
||||||
</BankFrame>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<BankFrame>
|
|
||||||
<RegistrationForm />
|
|
||||||
</BankFrame>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AccountPage(): VNode {
|
export function AccountPage(): VNode {
|
||||||
const [backendState, backendStateSetter] = useBackendState();
|
const [backendState, backendStateSetter] = useBackendState();
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
@ -46,3 +46,9 @@ export function getBankBackendBaseUrl(): string {
|
|||||||
console.log(`using bank base URL (${maybeRootPath})`);
|
console.log(`using bank base URL (${maybeRootPath})`);
|
||||||
return maybeRootPath;
|
return maybeRootPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
|
||||||
|
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
|
||||||
|
? obj
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user