From 8aa9ce6d20b41b7eb9b438a56ccd34cb0da35f80 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Thu, 21 Mar 2024 12:11:31 -0300
Subject: wip

---
 .../src/paths/login/index.tsx                      | 339 +++++++++++----------
 1 file changed, 181 insertions(+), 158 deletions(-)

(limited to 'packages/merchant-backoffice-ui/src/paths/login/index.tsx')

diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index 6c33dd06e..d155dd255 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -1,6 +1,6 @@
 /*
  This file is part of GNU Taler
- (C) 2021-2023 Taler Systems S.A.
+ (C) 2021-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
@@ -19,198 +19,221 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { ComponentChildren, Fragment, h, VNode } from "preact";
-import { useCallback, useEffect, useState } from "preact/hooks";
-import { useBackendContext } from "../../context/backend.js";
-import { useInstanceContext } from "../../context/instance.js";
-import { AccessToken, LoginToken } from "../../declaration.js";
-import { useCredentialsChecker } from "../../hooks/backend.js";
+import {
+  useMerchantApiContext,
+  useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { ComponentChildren, Fragment, VNode, h } from "preact";
+import { useState } from "preact/hooks";
 import { NotificationCard } from "../../components/menu/index.js";
+import { AccessToken } from "../../declaration.js";
+import { useSessionState } from "../../hooks/session.js";
 import { Notification } from "../../utils/types.js";
+import { HttpStatusCode } from "@gnu-taler/taler-util";
 
 interface Props {
-  onConfirm: (token: LoginToken | undefined) => void;
 }
 
 function normalizeToken(r: string): AccessToken {
   return `secret-token:${r}` as AccessToken;
 }
 
-export function LoginPage({ onConfirm }: Props): VNode {
-  const { url: backendURL } = useBackendContext();
-  const { admin, id } = useInstanceContext();
-  const { requestNewLoginToken } = useCredentialsChecker();
+export function LoginPage(_p: Props): VNode {
   const [token, setToken] = useState("");
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-
+  const { logIn } = useSessionState();
+  const { lib } = useMerchantApiContext();
 
   const { i18n } = useTranslationContext();
 
-
-  const doLogin = useCallback(async function doLoginImpl() {
+  async function doLoginImpl() {
     const secretToken = normalizeToken(token);
-    const baseUrl = id === undefined ? backendURL : `${backendURL}/instances/${id}`
-    const result = await requestNewLoginToken(baseUrl, secretToken);
-    if (result.valid) {
-      const { token, expiration } = result
-      onConfirm({ token, expiration });
+    const result = await lib.authenticate.createAccessToken(secretToken, {
+      scope: "write",
+      duration: {
+        d_us: "forever"
+      },
+      refreshable: true,
+    });
+    if (result.type === "ok") {
+      const { access_token } = result.body;
+      logIn({ token: access_token });
+      return;
     } else {
-      onConfirm(undefined);
-      setNotif({
-        message: "Your password is incorrect",
-        type: "ERROR",
-      });
+      switch(result.case) {
+        case HttpStatusCode.Unauthorized: {
+          setNotif({
+            message: "Your password is incorrect",
+            type: "ERROR",
+          });
+          return;
+        }
+        case HttpStatusCode.NotFound: {
+          setNotif({
+            message: "Your instance not found",
+            type: "ERROR",
+          });
+          return;
+        }
+      }
     }
-  }, [id, token])
+  }
 
   if (admin && id !== "default") {
     //admin trying to access another instance
-    return (<div class="columns is-centered" style={{ margin: "auto" }}>
-      <div class="column is-two-thirds ">
-        <div class="modal-card" style={{ width: "100%", margin: 0 }}>
-          <header
-            class="modal-card-head"
-            style={{ border: "1px solid", borderBottom: 0 }}
-          >
-            <p class="modal-card-title">{i18n.str`Login required`}</p>
-          </header>
-          <section
-            class="modal-card-body"
-            style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
-          >
-
-            <p>
-              <i18n.Translate>Need the access token for the instance.</i18n.Translate>
-            </p>
-            <div class="field is-horizontal">
-              <div class="field-label is-normal">
-                <label class="label">
-                  <i18n.Translate>Access Token</i18n.Translate>
-                </label>
-              </div>
-              <div class="field-body">
-                <div class="field">
-                  <p class="control is-expanded">
-                    <input
-                      class="input"
-                      type="password"
-                      placeholder={"current access token"}
-                      name="token"
-                      onKeyPress={(e) =>
-                        e.keyCode === 13
-                          ? doLogin()
-                          : null
-                      }
-                      value={token}
-                      onInput={(e): void => setToken(e?.currentTarget.value)}
-                    />
-                  </p>
+    return (
+      <div class="columns is-centered" style={{ margin: "auto" }}>
+        <div class="column is-two-thirds ">
+          <div class="modal-card" style={{ width: "100%", margin: 0 }}>
+            <header
+              class="modal-card-head"
+              style={{ border: "1px solid", borderBottom: 0 }}
+            >
+              <p class="modal-card-title">{i18n.str`Login required`}</p>
+            </header>
+            <section
+              class="modal-card-body"
+              style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
+            >
+              <p>
+                <i18n.Translate>
+                  Need the access token for the instance.
+                </i18n.Translate>
+              </p>
+              <div class="field is-horizontal">
+                <div class="field-label is-normal">
+                  <label class="label">
+                    <i18n.Translate>Access Token</i18n.Translate>
+                  </label>
+                </div>
+                <div class="field-body">
+                  <div class="field">
+                    <p class="control is-expanded">
+                      <input
+                        class="input"
+                        type="password"
+                        placeholder={"current access token"}
+                        name="token"
+                        onKeyPress={(e) =>
+                          e.keyCode === 13 ? doLoginImpl() : null
+                        }
+                        value={token}
+                        onInput={(e): void => setToken(e?.currentTarget.value)}
+                      />
+                    </p>
+                  </div>
                 </div>
               </div>
-            </div>
-          </section>
-          <footer
-            class="modal-card-foot "
-            style={{
-              justifyContent: "flex-end",
-              border: "1px solid",
-              borderTop: 0,
-            }}
-          >
-            <AsyncButton
-              onClick={doLogin}
+            </section>
+            <footer
+              class="modal-card-foot "
+              style={{
+                justifyContent: "flex-end",
+                border: "1px solid",
+                borderTop: 0,
+              }}
             >
-              <i18n.Translate>Confirm</i18n.Translate>
-            </AsyncButton>
-          </footer>
+              <AsyncButton onClick={doLoginImpl}>
+                <i18n.Translate>Confirm</i18n.Translate>
+              </AsyncButton>
+            </footer>
+          </div>
         </div>
       </div>
-    </div>)
+    );
   }
 
-  return (<Fragment>
-    <NotificationCard notification={notif} />
-    <div class="columns is-centered" style={{ margin: "auto" }}>
-      <div class="column is-two-thirds ">
-        <div class="modal-card" style={{ width: "100%", margin: 0 }}>
-          <header
-            class="modal-card-head"
-            style={{ border: "1px solid", borderBottom: 0 }}
-          >
-            <p class="modal-card-title">{i18n.str`Login required`}</p>
-          </header>
-          <section
-            class="modal-card-body"
-            style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
-          >
-            <i18n.Translate>Please enter your access token.</i18n.Translate>
-
-            <div class="field is-horizontal">
-              <div class="field-label is-normal">
-                <label class="label">
-                  <i18n.Translate>Access Token</i18n.Translate>
-                </label>
-              </div>
-              <div class="field-body">
+  return (
+    <Fragment>
+      <NotificationCard notification={notif} />
+      <div class="columns is-centered" style={{ margin: "auto" }}>
+        <div class="column is-two-thirds ">
+          <div class="modal-card" style={{ width: "100%", margin: 0 }}>
+            <header
+              class="modal-card-head"
+              style={{ border: "1px solid", borderBottom: 0 }}
+            >
+              <p class="modal-card-title">{i18n.str`Login required`}</p>
+            </header>
+            <section
+              class="modal-card-body"
+              style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
+            >
+              <i18n.Translate>Please enter your access token.</i18n.Translate>
 
-                <div class="field">
-                  <p class="control is-expanded">
-                    <input
-                      class="input"
-                      type="password"
-                      placeholder={"current access token"}
-                      name="token"
-                      onKeyPress={(e) =>
-                        e.keyCode === 13
-                          ? doLogin()
-                          : null
-                      }
-                      value={token}
-                      onInput={(e): void => setToken(e?.currentTarget.value)}
-                    />
-                  </p>
+              <div class="field is-horizontal">
+                <div class="field-label is-normal">
+                  <label class="label">
+                    <i18n.Translate>Access Token</i18n.Translate>
+                  </label>
+                </div>
+                <div class="field-body">
+                  <div class="field">
+                    <p class="control is-expanded">
+                      <input
+                        class="input"
+                        type="password"
+                        placeholder={"current access token"}
+                        name="token"
+                        onKeyPress={(e) =>
+                          e.keyCode === 13 ? doLoginImpl() : null
+                        }
+                        value={token}
+                        onInput={(e): void => setToken(e?.currentTarget.value)}
+                      />
+                    </p>
+                  </div>
                 </div>
               </div>
-            </div>
-          </section>
-          <footer
-            class="modal-card-foot "
-            style={{
-              justifyContent: "space-between",
-              border: "1px solid",
-              borderTop: 0,
-            }}
-          >
-            <div />
-            <AsyncButton
-              type="is-info"
-              onClick={doLogin}
+            </section>
+            <footer
+              class="modal-card-foot "
+              style={{
+                justifyContent: "space-between",
+                border: "1px solid",
+                borderTop: 0,
+              }}
             >
-              <i18n.Translate>Confirm</i18n.Translate>
-            </AsyncButton>
-
-          </footer>
+              <div />
+              <AsyncButton type="is-info" onClick={doLoginImpl}>
+                <i18n.Translate>Confirm</i18n.Translate>
+              </AsyncButton>
+            </footer>
+          </div>
         </div>
       </div>
-    </div>
-  </Fragment>
-
+    </Fragment>
   );
 }
 
-function AsyncButton({ onClick, disabled, type = "", children }: { type?: string, disabled?: boolean, onClick: () => Promise<void>, children: ComponentChildren }): VNode {
-  const [running, setRunning] = useState(false)
-  return <button class={"button " + type} disabled={disabled || running} onClick={() => {
-    setRunning(true)
-    onClick().then(() => {
-      setRunning(false)
-    }).catch(() => {
-      setRunning(false)
-    })
-  }}>
-    {children}
-  </button>
+function AsyncButton({
+  onClick,
+  disabled,
+  type = "",
+  children,
+}: {
+  type?: string;
+  disabled?: boolean;
+  onClick: () => Promise<void>;
+  children: ComponentChildren;
+}): VNode {
+  const [running, setRunning] = useState(false);
+  return (
+    <button
+      class={"button " + type}
+      disabled={disabled || running}
+      onClick={() => {
+        setRunning(true);
+        onClick()
+          .then(() => {
+            setRunning(false);
+          })
+          .catch(() => {
+            setRunning(false);
+          });
+      }}
+    >
+      {children}
+    </button>
+  );
 }
-
-
-- 
cgit v1.2.3

