diff options
author | Sebastian <sebasjm@gmail.com> | 2024-03-08 14:09:31 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-03-08 14:09:31 -0300 |
commit | ddd32a690bd13b1eb1aef1356a1d59fd64e254bf (patch) | |
tree | 44126872f6e8195a3617e2002c696c0afa13fb0d /packages/demobank-ui/src/pages/RegistrationPage.tsx | |
parent | e0e82cdf07930d766081e42203c5a4e66d43191f (diff) | |
download | wallet-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.tsx | 415 |
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); -} |