diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/RegistrationPage.tsx')
-rw-r--r-- | packages/demobank-ui/src/pages/RegistrationPage.tsx | 176 |
1 files changed, 63 insertions, 113 deletions
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx index 29f1bf5ee..247ef8d80 100644 --- a/packages/demobank-ui/src/pages/RegistrationPage.tsx +++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx @@ -13,38 +13,36 @@ 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 { Logger } from "@gnu-taler/taler-util"; -import { Fragment, h, VNode } from "preact"; -import { route } from "preact-router"; -import { StateUpdater, useState } from "preact/hooks"; -import { useBackendContext } from "../context/backend.js"; -import { PageStateType, usePageContext } from "../context/pageState.js"; +import { HttpStatusCode, Logger } from "@gnu-taler/taler-util"; import { - InternationalizationAPI, + RequestError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; -import { BackendStateHandler } from "../hooks/backend.js"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { useBackendContext } from "../context/backend.js"; +import { PageStateType } from "../context/pageState.js"; +import { useTestingAPI } from "../hooks/access.js"; import { bankUiSettings } from "../settings.js"; -import { getBankBackendBaseUrl, undefinedIfEmpty } from "../utils.js"; -import { BankFrame } from "./BankFrame.js"; +import { undefinedIfEmpty } from "../utils.js"; import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js"; const logger = new Logger("RegistrationPage"); -export function RegistrationPage(): VNode { +export function RegistrationPage({ + onError, + onComplete, +}: { + onComplete: () => void; + onError: (e: PageStateType["error"]) => void; +}): VNode { const { i18n } = useTranslationContext(); if (!bankUiSettings.allowRegistrations) { return ( - <BankFrame> - <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p> - </BankFrame> + <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p> ); } - return ( - <BankFrame> - <RegistrationForm /> - </BankFrame> - ); + return <RegistrationForm onComplete={onComplete} onError={onError} />; } export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9]*$/; @@ -53,13 +51,19 @@ export const PASSWORD_REGEX = /^[a-z0-9][a-zA-Z0-9]*$/; /** * Collect and submit registration data. */ -function RegistrationForm(): VNode { +function RegistrationForm({ + onComplete, + onError, +}: { + onComplete: () => void; + onError: (e: PageStateType["error"]) => void; +}): VNode { const backend = useBackendContext(); - const { pageState, pageStateSetter } = usePageContext(); const [username, setUsername] = useState<string | undefined>(); const [password, setPassword] = useState<string | undefined>(); const [repeatPassword, setRepeatPassword] = useState<string | undefined>(); + const { register } = useTestingAPI(); const { i18n } = useTranslationContext(); const errors = undefinedIfEmpty({ @@ -104,6 +108,7 @@ function RegistrationForm(): VNode { name="register-un" type="text" placeholder="Username" + autocomplete="username" value={username ?? ""} onInput={(e): void => { setUsername(e.currentTarget.value); @@ -121,6 +126,7 @@ function RegistrationForm(): VNode { name="register-pw" id="register-pw" placeholder="Password" + autocomplete="new-password" value={password ?? ""} required onInput={(e): void => { @@ -139,6 +145,7 @@ function RegistrationForm(): VNode { style={{ marginBottom: 8 }} name="register-repeat" id="register-repeat" + autocomplete="new-password" placeholder="Same password" value={repeatPassword ?? ""} required @@ -155,19 +162,42 @@ function RegistrationForm(): VNode { class="pure-button pure-button-primary btn-register" type="submit" disabled={!!errors} - onClick={(e) => { + onClick={async (e) => { e.preventDefault(); - if (!username || !password) return; - registrationCall( - { username, password }, - backend, // will store BE URL, if OK. - pageStateSetter, - i18n, - ); - setUsername(undefined); - setPassword(undefined); - setRepeatPassword(undefined); + if (!username || !password) return; + try { + const credentials = { username, password }; + await register(credentials); + setUsername(undefined); + setPassword(undefined); + setRepeatPassword(undefined); + backend.logIn(credentials); + onComplete(); + } catch (error) { + if (error instanceof RequestError) { + const errorData: SandboxBackend.SandboxError = + error.info.error; + if (error.info.status === HttpStatusCode.Conflict) { + onError({ + title: i18n.str`That username is already taken`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } else { + onError({ + title: i18n.str`New registration gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } + } else if (error instanceof Error) { + onError({ + title: i18n.str`Registration failed, please report`, + description: error.message, + }); + } + } }} > {i18n.str`Register`} @@ -180,7 +210,7 @@ function RegistrationForm(): VNode { setUsername(undefined); setPassword(undefined); setRepeatPassword(undefined); - route("/account"); + onComplete(); }} > {i18n.str`Cancel`} @@ -192,83 +222,3 @@ function RegistrationForm(): VNode { </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. - */ - backend: BackendStateHandler, - pageStateSetter: StateUpdater<PageStateType>, - i18n: InternationalizationAPI, -): Promise<void> { - const url = getBankBackendBaseUrl(); - - const headers = new Headers(); - headers.append("Content-Type", "application/json"); - const registerEndpoint = new URL("access-api/testing/register", url); - let res: Response; - try { - res = await fetch(registerEndpoint.href, { - method: "POST", - body: JSON.stringify({ - username: req.username, - password: req.password, - }), - headers, - }); - } catch (error) { - logger.error( - `Could not POST new registration to the bank (${registerEndpoint.href})`, - error, - ); - pageStateSetter((prevState) => ({ - ...prevState, - - error: { - title: i18n.str`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: i18n.str`That username is already taken`, - debug: JSON.stringify(response), - }, - })); - } else { - pageStateSetter((prevState) => ({ - ...prevState, - - error: { - title: i18n.str`New registration gave response error`, - debug: JSON.stringify(response), - }, - })); - } - } else { - // registration was ok - backend.save({ - url, - username: req.username, - password: req.password, - }); - route("/account"); - } -} |