gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: use async button


From: gnunet
Subject: [taler-wallet-core] branch master updated: use async button
Date: Mon, 04 Mar 2024 20:38:22 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new e528c7015 use async button
e528c7015 is described below

commit e528c70159bbc147f8a947c16b60246fce65cca8
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Mar 4 16:38:15 2024 -0300

    use async button
---
 packages/demobank-ui/src/pages/LoginForm.tsx       | 81 +++++++-----------
 packages/demobank-ui/src/pages/QrCodeSection.tsx   | 72 ++++++----------
 .../demobank-ui/src/pages/RegistrationPage.tsx     | 95 ++++------------------
 3 files changed, 71 insertions(+), 177 deletions(-)

diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx 
b/packages/demobank-ui/src/pages/LoginForm.tsx
index b351785d9..09c0a8785 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -20,9 +20,11 @@ import {
   assertUnreachable,
 } from "@gnu-taler/taler-util";
 import {
+  Button,
   LocalNotificationBanner,
   ShowInputErrorLabel,
   useLocalNotification,
+  useLocalNotificationHandler,
   useTranslationContext,
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
@@ -55,7 +57,7 @@ export function LoginForm({
   const [password, setPassword] = useState<string | undefined>();
   const { i18n } = useTranslationContext();
   const { api } = useBankCoreApiContext();
-  const [notification, notify, handleError] = useLocalNotification();
+  const [notification, withErrorHandler] = useLocalNotificationHandler();
   const { config } = useBankCoreApiContext();
 
   const ref = useRef<HTMLInputElement>(null);
@@ -63,8 +65,6 @@ export function LoginForm({
     ref.current?.focus();
   }, []);
 
-  const [busy, setBusy] = useState<Record<string, undefined>>();
-
   const errors =
     undefinedIfEmpty({
       username: !username
@@ -73,50 +73,31 @@ export function LoginForm({
         //   ? i18n.str`Use letters and numbers only, and start with a 
lowercase letter`
         undefined,
       password: !password ? i18n.str`Missing password` : undefined,
-    }) ?? busy;
+    });
 
   async function doLogout() {
     backend.logOut();
   }
 
-  async function doLogin() {
-    if (!username || !password) return;
-    setBusy({});
-    await handleError(async () => {
-      const resp = await api
-        .getAuthenticationAPI(username)
-        .createAccessToken(password, {
-          // scope: "readwrite" as "write", // FIX: different than merchant
-          scope: "readwrite",
-          duration: { d_us: "forever" },
-          refreshable: true,
-        });
-      if (resp.type === "ok") {
-        backend.logIn({ username, token: resp.body.access_token });
-      } else {
-        switch (resp.case) {
-          case HttpStatusCode.Unauthorized:
-            return notify({
-              type: "error",
-              title: i18n.str`Wrong credentials for "${username}"`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case HttpStatusCode.NotFound:
-            return notify({
-              type: "error",
-              title: i18n.str`Account not found`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          default:
-            assertUnreachable(resp);
-        }
+  const loginHandler = !username || !password ? undefined : withErrorHandler(
+    async () => api
+      .getAuthenticationAPI(username)
+      .createAccessToken(password, {
+        // scope: "readwrite" as "write", // FIX: different than merchant
+        scope: "readwrite",
+        duration: { d_us: "forever" },
+        refreshable: true,
+      }),
+    (result) => {
+      backend.logIn({ username, token: result.body.access_token })
+    },
+    (fail) => {
+      switch (fail.case) {
+        case HttpStatusCode.Unauthorized: return i18n.str`Wrong credentials 
for "${username}"`;
+        case HttpStatusCode.NotFound: return i18n.str`Account not found`;
       }
-    });
-    setPassword(undefined);
-    setBusy(undefined);
-  }
+    }
+  )
 
   return (
     <div class="flex min-h-full flex-col justify-center ">
@@ -209,33 +190,27 @@ export function LoginForm({
                 <i18n.Translate>Cancel</i18n.Translate>
               </button>
 
-              <button
+              <Button
                 type="submit"
                 name="check"
                 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();
-                  doLogin();
-                }}
+                handler={loginHandler}
               >
                 <i18n.Translate>Check</i18n.Translate>
-              </button>
+              </Button>
             </div>
           ) : (
             <div>
-              <button
+              <Button
                 type="submit"
                 name="login"
                 class="flex w-full justify-center 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={(e) => {
-                  e.preventDefault();
-                  doLogin();
-                }}
+                handler={loginHandler}
               >
                 <i18n.Translate>Log in</i18n.Translate>
-              </button>
+              </Button>
             </div>
           )}
         </form>
diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx 
b/packages/demobank-ui/src/pages/QrCodeSection.tsx
index d20b269a8..7091214e0 100644
--- a/packages/demobank-ui/src/pages/QrCodeSection.tsx
+++ b/packages/demobank-ui/src/pages/QrCodeSection.tsx
@@ -15,16 +15,15 @@
  */
 
 import {
-  assertUnreachable,
   HttpStatusCode,
   stringifyWithdrawUri,
-  TranslatedString,
-  WithdrawUriResult,
+  WithdrawUriResult
 } from "@gnu-taler/taler-util";
 import {
+  Button,
   LocalNotificationBanner,
-  useLocalNotification,
-  useTranslationContext,
+  useLocalNotificationHandler,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, h, VNode } from "preact";
 import { useEffect } from "preact/hooks";
@@ -50,47 +49,27 @@ export function QrCodeSection({
     walletInegrationApi.publishTalerAction(withdrawUri);
   }, []);
 
-  const [notification, notify, handleError] = useLocalNotification();
+  const [notification, handleError] = useLocalNotificationHandler();
 
   const { api } = useBankCoreApiContext();
 
-  async function doAbort() {
-    await handleError(async () => {
-      if (!creds) return;
-      const resp = await api.abortWithdrawalById(
+  const onAbortHandler = handleError(
+    async () => {
+      if (!creds) return undefined;
+      return api.abortWithdrawalById(
         creds,
         withdrawUri.withdrawalOperationId,
-      );
-      if (resp.type === "ok") {
-        onAborted();
-      } else {
-        switch (resp.case) {
-          case HttpStatusCode.Conflict:
-            return notify({
-              type: "error",
-              title: i18n.str`The reserve operation has been confirmed 
previously and can't be aborted`,
-            });
-          case HttpStatusCode.BadRequest:
-            return notify({
-              type: "error",
-              title: i18n.str`The operation id is invalid.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case HttpStatusCode.NotFound:
-            return notify({
-              type: "error",
-              title: i18n.str`The operation was not found.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          default: {
-            assertUnreachable(resp);
-          }
-        }
+      )
+    },
+    onAborted,
+    (fail) => {
+      switch (fail.case) {
+        case HttpStatusCode.BadRequest: return i18n.str`The operation id is 
invalid.`;
+        case HttpStatusCode.NotFound: return i18n.str`The operation was not 
found.`;
+        case HttpStatusCode.Conflict: return i18n.str`The reserve operation 
has been confirmed previously and can't be aborted`;
       }
-    });
-  }
+    }
+  )
 
   return (
     <Fragment>
@@ -120,15 +99,14 @@ export function QrCodeSection({
             </p>
           </div>
           <div class="flex items-center justify-between gap-x-6 border-t 
border-gray-900/10 pt-2 mt-2 ">
-            <button
+            <Button
               type="button"
               name="cancel"
-              // class="disabled:opacity-50 disabled:cursor-default 
cursor-pointer rounded-md  px-3 py-2 text-sm font-semibold text-black shadow-sm 
hover:bg-red-500 focus-visible:outline focus-visible:outline-2 
focus-visible:outline-offset-2 focus-visible:outline-red-600"
               class="text-sm font-semibold leading-6 text-gray-900"
-              onClick={doAbort}
+              handler={onAbortHandler}
             >
               <i18n.Translate>Cancel</i18n.Translate>
-            </button>
+            </Button>
             <a
               href={talerWithdrawUri}
               name="withdraw"
@@ -157,14 +135,14 @@ export function QrCodeSection({
           </div>
         </div>
         <div class="flex items-center justify-center gap-x-6 border-t 
border-gray-900/10 px-4 py-4 sm:px-8">
-          <button
+          <Button
             type="button"
             // class="disabled:opacity-50 disabled:cursor-default 
cursor-pointer rounded-md  px-3 py-2 text-sm font-semibold text-black shadow-sm 
hover:bg-red-500 focus-visible:outline focus-visible:outline-2 
focus-visible:outline-offset-2 focus-visible:outline-red-600"
             class="text-sm font-semibold leading-6 text-gray-900"
-            onClick={doAbort}
+            handler={onAbortHandler}
           >
             <i18n.Translate>Cancel</i18n.Translate>
-          </button>
+          </Button>
         </div>
       </div>
     </Fragment>
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx 
b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index 87e284411..18b4c470b 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -16,6 +16,7 @@
 import {
   AccessToken,
   HttpStatusCode,
+  OperationFail,
   TalerErrorCode,
   TranslatedString,
   assertUnreachable,
@@ -30,7 +31,7 @@ import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { useBankCoreApiContext } from "../context/config.js";
 import { useSettingsContext } from "../context/settings.js";
-import { EmptyObject, RouteDefinition } from "../route.js";
+import { RouteDefinition } from "../route.js";
 import { undefinedIfEmpty } from "../utils.js";
 import { getRandomPassword, getRandomUsername } from "./rnd.js";
 
@@ -76,7 +77,7 @@ function RegistrationForm({
   // const [phone, setPhone] = useState<string | undefined>();
   // const [email, setEmail] = useState<string | undefined>();
   const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
-  const [notification, notify, handleError] = useLocalNotification();
+  const [notification, _, handleError] = useLocalNotification();
   const settings = useSettingsContext();
 
   const { api } = useBankCoreApiContext();
@@ -114,7 +115,7 @@ function RegistrationForm({
     password: string,
     onComplete: () => void,
   ) {
-    await handleError(async () => {
+    await handleError(async (onError) => {
       const resp = await api.createAccount("" as AccessToken, {
         name,
         username,
@@ -123,80 +124,20 @@ function RegistrationForm({
       if (resp.type === "ok") {
         onComplete();
       } else {
-        switch (resp.case) {
-          case HttpStatusCode.BadRequest:
-            return notify({
-              type: "error",
-              title: i18n.str`Server replied with invalid phone or email.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_UNALLOWED_DEBIT:
-            return notify({
-              type: "error",
-              title: i18n.str`Registration is disabled because the bank ran 
out of bonus credit.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case HttpStatusCode.Unauthorized:
-            return notify({
-              type: "error",
-              title: i18n.str`No enough permission to create that account.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
-            return notify({
-              type: "error",
-              title: i18n.str`That account id is already taken.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
-            return notify({
-              type: "error",
-              title: i18n.str`That username is already taken.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
-            return notify({
-              type: "error",
-              title: i18n.str`That username can't be used because is 
reserved.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
-            return notify({
-              type: "error",
-              title: i18n.str`Only admin is allow to set debt limit.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_MISSING_TAN_INFO:
-            return notify({
-              type: "error",
-              title: i18n.str`No information for the selected authentication 
channel.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
-            return notify({
-              type: "error",
-              title: i18n.str`Authentication channel is not supported.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
-            return notify({
-              type: "error",
-              title: i18n.str`Only admin can create accounts with second 
factor authentication.`,
-              description: resp.detail.hint as TranslatedString,
-              debug: resp.detail,
-            });
-          default:
-            assertUnreachable(resp);
-        }
+        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.`;
+          }
+        })
       }
     });
   }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]