summaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/pages/RegistrationPage.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-03-08 14:09:31 -0300
committerSebastian <sebasjm@gmail.com>2024-03-08 14:09:31 -0300
commitddd32a690bd13b1eb1aef1356a1d59fd64e254bf (patch)
tree44126872f6e8195a3617e2002c696c0afa13fb0d /packages/demobank-ui/src/pages/RegistrationPage.tsx
parente0e82cdf07930d766081e42203c5a4e66d43191f (diff)
downloadwallet-core-ddd32a690bd13b1eb1aef1356a1d59fd64e254bf.tar.gz
wallet-core-ddd32a690bd13b1eb1aef1356a1d59fd64e254bf.tar.bz2
wallet-core-ddd32a690bd13b1eb1aef1356a1d59fd64e254bf.zip
demobank => bank
Diffstat (limited to 'packages/demobank-ui/src/pages/RegistrationPage.tsx')
-rw-r--r--packages/demobank-ui/src/pages/RegistrationPage.tsx415
1 files changed, 0 insertions, 415 deletions
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx
deleted file mode 100644
index e9f7e602f..000000000
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 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 {
- AccessToken,
- HttpStatusCode,
- OperationFail,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- LocalNotificationBanner,
- ShowInputErrorLabel,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useSettingsContext } from "../context/settings.js";
-import { RouteDefinition } from "../route.js";
-import { undefinedIfEmpty } from "../utils.js";
-import { getRandomPassword, getRandomUsername } from "./rnd.js";
-
-export function RegistrationPage({
- onRegistrationSuccesful,
- routeCancel,
-}: {
- onRegistrationSuccesful: (user: string, password: string) => void;
- routeCancel: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { config } = useBankCoreApiContext();
- if (!config.allow_registrations) {
- return (
- <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
- );
- }
- return (
- <RegistrationForm
- onRegistrationSuccesful={onRegistrationSuccesful}
- routeCancel={routeCancel}
- />
- );
-}
-
-export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9-]*$/;
-export const PHONE_REGEX = /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/;
-export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
-
-/**
- * Collect and submit registration data.
- */
-function RegistrationForm({
- onRegistrationSuccesful,
- routeCancel,
-}: {
- onRegistrationSuccesful: (user: string, password: string) => void;
- routeCancel: RouteDefinition;
-}): VNode {
- const [username, setUsername] = useState<string | undefined>();
- const [name, setName] = useState<string | undefined>();
- const [password, setPassword] = useState<string | undefined>();
- // const [phone, setPhone] = useState<string | undefined>();
- // const [email, setEmail] = useState<string | undefined>();
- const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
- const [notification, _, handleError] = useLocalNotification();
- const settings = useSettingsContext();
-
- const { bank: api } = useBankCoreApiContext();
- // const { register } = useTestingAPI();
- const { i18n } = useTranslationContext();
-
- const errors = undefinedIfEmpty({
- name: !name ? i18n.str`Missing name` : undefined,
- username: !username
- ? i18n.str`Missing username`
- : !USERNAME_REGEX.test(username)
- ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- : undefined,
- // phone: !phone
- // ? undefined
- // : !PHONE_REGEX.test(phone)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- // : undefined,
- // email: !email
- // ? undefined
- // : !EMAIL_REGEX.test(email)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- // : undefined,
- password: !password ? i18n.str`Missing password` : undefined,
- repeatPassword: !repeatPassword
- ? i18n.str`Missing password`
- : repeatPassword !== password
- ? i18n.str`Passwords don't match`
- : undefined,
- });
-
- async function doRegistrationAndLogin(
- name: string,
- username: string,
- password: string,
- onComplete: () => void,
- ) {
- await handleError(async (onError) => {
- const resp = await api.createAccount("" as AccessToken, {
- name,
- username,
- password,
- });
- if (resp.type === "ok") {
- onComplete();
- } else {
- onError(resp, (_case) => {
- switch(_case) {
- case HttpStatusCode.BadRequest: return i18n.str`Server replied with invalid phone or email.`;
- case HttpStatusCode.Unauthorized: return i18n.str`No enough permission to create that account.`;
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return i18n.str`Registration is disabled because the bank ran out of bonus credit.`;
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return i18n.str`That username can't be used because is reserved.`;
- case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: return i18n.str`That username is already taken.`;
- case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return i18n.str`That account id is already taken.`;
- case TalerErrorCode.BANK_MISSING_TAN_INFO: return i18n.str`No information for the selected authentication channel.`;
- case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return i18n.str`Authentication channel is not supported.`;
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return i18n.str`Only admin is allow to set debt limit.`;
- case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL: return i18n.str`Only admin can create accounts with second factor authentication.`;
- }
- })
- }
- });
- }
-
- async function doRegistrationStep() {
- if (!username || !password || !name) return;
- await doRegistrationAndLogin(name, username, password, () => {
- setUsername(undefined);
- setPassword(undefined);
- setRepeatPassword(undefined);
- onRegistrationSuccesful(username, password);
- });
- }
-
- async function doRandomRegistration() {
- const user = getRandomUsername();
-
- const password = settings.simplePasswordForRandomAccounts
- ? "123"
- : getRandomPassword();
- const username = `_${user.first}-${user.second}_`;
- const name = `${capitalizeFirstLetter(user.first)} ${capitalizeFirstLetter(
- user.second,
- )}`;
- await doRegistrationAndLogin(name, username, password, () => {
- onRegistrationSuccesful(username, password);
- });
- }
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
-
- <div class="flex min-h-full flex-col justify-center">
- <div class="sm:mx-auto sm:w-full sm:max-w-sm">
- <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Account registration`}</h2>
- </div>
-
- <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <div>
- <label
- for="username"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Login username</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="username"
- id="username"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={username ?? ""}
- enterkeyhint="next"
- placeholder="account identification to login"
- autocomplete="username"
- required
- onInput={(e): void => {
- setUsername(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.username}
- isDirty={username !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="password"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Password</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- </div>
- <div class="mt-2">
- <input
- type="password"
- name="password"
- id="password"
- autocomplete="current-password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- enterkeyhint="send"
- value={password ?? ""}
- placeholder="Password"
- required
- onInput={(e): void => {
- setPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.password}
- isDirty={password !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="register-repeat"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Repeat password</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- </div>
- <div class="mt-2">
- <input
- type="password"
- name="register-repeat"
- id="register-repeat"
- autocomplete="current-password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- enterkeyhint="send"
- value={repeatPassword ?? ""}
- placeholder="Same password"
- required
- onInput={(e): void => {
- setRepeatPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.repeatPassword}
- isDirty={repeatPassword !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="name"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Full name</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- </div>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="name"
- id="name"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={name ?? ""}
- enterkeyhint="next"
- placeholder="John Doe"
- autocomplete="name"
- required
- onInput={(e): void => {
- setName(e.currentTarget.value);
- }}
- />
- {/* <ShowInputErrorLabel
- message={errors?.name}
- isDirty={name !== undefined}
- /> */}
- </div>
- </div>
-
- {/* <div>
- <label for="phone" class="block text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Phone</i18n.Translate>
- </label>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="phone"
- id="phone"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={phone ?? ""}
- enterkeyhint="next"
- placeholder="your phone"
- autocomplete="none"
- onInput={(e): void => {
- setPhone(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.phone}
- isDirty={phone !== undefined}
- />
- </div>
- </div>
- <div>
- <label for="email" class="block text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Email</i18n.Translate>
- </label>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="email"
- id="email"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={email ?? ""}
- enterkeyhint="next"
- placeholder="your email"
- autocomplete="email"
- onInput={(e): void => {
- setEmail(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.email}
- isDirty={email !== undefined}
- />
- </div>
- </div> */}
-
- <div class="flex w-full justify-between">
- <a
- name="cancel"
- href={routeCancel.url({})}
- class="ring-1 ring-gray-600 rounded-md bg-white disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-white-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="register"
- class=" rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={async (e) => {
- e.preventDefault();
-
- doRegistrationStep();
- }}
- >
- <i18n.Translate>Register</i18n.Translate>
- </button>
- </div>
- </form>
-
- {settings.allowRandomAccountCreation && (
- <p class="mt-10 text-center text-sm text-gray-500 border-t">
- <button
- type="submit"
- name="create random"
- class="flex mt-4 w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600"
- onClick={(e) => {
- e.preventDefault();
- doRandomRegistration();
- }}
- >
- <i18n.Translate>Create a random temporary user</i18n.Translate>
- </button>
- </p>
- )}
- </div>
- </div>
- </Fragment>
- );
-}
-
-function capitalizeFirstLetter(str: string) {
- return str.charAt(0).toUpperCase() + str.slice(1);
-}