From a8c5a9696c1735a178158cbc9ac4f9bb4b6f013d Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Wed, 8 Feb 2023 17:41:19 -0300
Subject: impl accout management and refactor

---
 .../demobank-ui/src/pages/RegistrationPage.tsx     | 176 ++++++++-------------
 1 file changed, 63 insertions(+), 113 deletions(-)

(limited to 'packages/demobank-ui/src/pages/RegistrationPage.tsx')

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");
-  }
-}
-- 
cgit v1.2.3

