From a3aa7d95d09c83794067c47df4a455c0e3f21806 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Fri, 7 Apr 2023 17:30:01 -0300
Subject: anon withdrawal confirmation, and fix error with infinity loop

---
 packages/demobank-ui/src/pages/AdminPage.tsx | 179 ++++++++++++---------------
 1 file changed, 81 insertions(+), 98 deletions(-)

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

diff --git a/packages/demobank-ui/src/pages/AdminPage.tsx b/packages/demobank-ui/src/pages/AdminPage.tsx
index 92464a43e..b867d0103 100644
--- a/packages/demobank-ui/src/pages/AdminPage.tsx
+++ b/packages/demobank-ui/src/pages/AdminPage.tsx
@@ -14,13 +14,9 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { Amounts, HttpStatusCode, parsePaytoUri } from "@gnu-taler/taler-util";
 import {
-  Amounts,
-  HttpStatusCode,
-  parsePaytoUri,
-  TranslatedString,
-} from "@gnu-taler/taler-util";
-import {
+  ErrorType,
   HttpResponsePaginated,
   RequestError,
   useTranslationContext,
@@ -29,11 +25,7 @@ import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Cashouts } from "../components/Cashouts/index.js";
 import { useBackendContext } from "../context/backend.js";
-import {
-  ErrorMessage,
-  PageStateType,
-  usePageContext,
-} from "../context/pageState.js";
+import { ErrorMessage, notifyInfo } from "../context/pageState.js";
 import { useAccountDetails } from "../hooks/access.js";
 import {
   useAdminAccountAPI,
@@ -50,6 +42,7 @@ import {
 } from "../utils.js";
 import { ErrorBannerFloat } from "./BankFrame.js";
 import { ShowCashoutDetails } from "./BusinessAccount.js";
+import { handleNotOkResult } from "./HomePage.js";
 import { PaytoWireTransferForm } from "./PaytoWireTransferForm.js";
 import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js";
 
@@ -69,14 +62,12 @@ function randomPassword(): string {
 }
 
 interface Props {
-  onLoadNotOk: <T>(
-    error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
-  ) => VNode;
+  onRegister: () => void;
 }
 /**
  * Query account information and show QR code if there is pending withdrawal
  */
-export function AdminPage({ onLoadNotOk }: Props): VNode {
+export function AdminPage({ onRegister }: Props): VNode {
   const [account, setAccount] = useState<string | undefined>();
   const [showDetails, setShowDetails] = useState<string | undefined>();
   const [showCashouts, setShowCashouts] = useState<string | undefined>();
@@ -87,24 +78,13 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
   >();
 
   const [createAccount, setCreateAccount] = useState(false);
-  const { pageStateSetter } = usePageContext();
-
-  function showInfoMessage(info: TranslatedString): void {
-    pageStateSetter((prev) => ({
-      ...prev,
-      info,
-    }));
-  }
-  function saveError(error: PageStateType["error"]): void {
-    pageStateSetter((prev) => ({ ...prev, error }));
-  }
 
   const result = useBusinessAccounts({ account });
   const { i18n } = useTranslationContext();
 
   if (result.loading) return <div />;
   if (!result.ok) {
-    return onLoadNotOk(result);
+    return handleNotOkResult(i18n, onRegister)(result);
   }
 
   const { customers } = result.data;
@@ -113,7 +93,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
     return (
       <ShowCashoutDetails
         id={showCashoutDetails}
-        onLoadNotOk={onLoadNotOk}
+        onLoadNotOk={handleNotOkResult(i18n, onRegister)}
         onCancel={() => {
           setShowCashoutDetails(undefined);
         }}
@@ -155,13 +135,13 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
     return (
       <ShowAccountDetails
         account={showDetails}
-        onLoadNotOk={onLoadNotOk}
+        onLoadNotOk={handleNotOkResult(i18n, onRegister)}
         onChangePassword={() => {
           setUpdatePassword(showDetails);
           setShowDetails(undefined);
         }}
         onUpdateSuccess={() => {
-          showInfoMessage(i18n.str`Account updated`);
+          notifyInfo(i18n.str`Account updated`);
           setShowDetails(undefined);
         }}
         onClear={() => {
@@ -174,9 +154,9 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
     return (
       <RemoveAccount
         account={removeAccount}
-        onLoadNotOk={onLoadNotOk}
+        onLoadNotOk={handleNotOkResult(i18n, onRegister)}
         onUpdateSuccess={() => {
-          showInfoMessage(i18n.str`Account removed`);
+          notifyInfo(i18n.str`Account removed`);
           setRemoveAccount(undefined);
         }}
         onClear={() => {
@@ -189,9 +169,9 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
     return (
       <UpdateAccountPassword
         account={updatePassword}
-        onLoadNotOk={onLoadNotOk}
+        onLoadNotOk={handleNotOkResult(i18n, onRegister)}
         onUpdateSuccess={() => {
-          showInfoMessage(i18n.str`Password changed`);
+          notifyInfo(i18n.str`Password changed`);
           setUpdatePassword(undefined);
         }}
         onClear={() => {
@@ -205,7 +185,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
       <CreateNewAccount
         onClose={() => setCreateAccount(false)}
         onCreateSuccess={(password) => {
-          showInfoMessage(
+          notifyInfo(
             i18n.str`Account created with password "${password}". The user must change the password on the next login.`,
           );
           setCreateAccount(false);
@@ -214,59 +194,6 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
     );
   }
 
-  function AdminAccount(): VNode {
-    const r = useBackendContext();
-    const account = r.state.status === "loggedIn" ? r.state.username : "admin";
-    const result = useAccountDetails(account);
-
-    if (!result.ok) {
-      return onLoadNotOk(result);
-    }
-    const { data } = result;
-    const balance = Amounts.parseOrThrow(data.balance.amount);
-    const debitThreshold = Amounts.parseOrThrow(result.data.debitThreshold);
-    const balanceIsDebit =
-      result.data.balance.credit_debit_indicator == "debit";
-    const limit = balanceIsDebit
-      ? Amounts.sub(debitThreshold, balance).amount
-      : Amounts.add(balance, debitThreshold).amount;
-    if (!balance) return <Fragment />;
-    return (
-      <Fragment>
-        <section id="assets">
-          <div class="asset-summary">
-            <h2>{i18n.str`Bank account balance`}</h2>
-            {!balance ? (
-              <div class="large-amount" style={{ color: "gray" }}>
-                Waiting server response...
-              </div>
-            ) : (
-              <div class="large-amount amount">
-                {balanceIsDebit ? <b>-</b> : null}
-                <span class="value">{`${Amounts.stringifyValue(
-                  balance,
-                )}`}</span>
-                &nbsp;
-                <span class="currency">{`${balance.currency}`}</span>
-              </div>
-            )}
-          </div>
-        </section>
-        <PaytoWireTransferForm
-          focus
-          limit={limit}
-          onSuccess={() => {
-            pageStateSetter((prevState: PageStateType) => ({
-              ...prevState,
-              info: i18n.str`Wire transfer created!`,
-            }));
-          }}
-          onError={saveError}
-        />
-      </Fragment>
-    );
-  }
-
   return (
     <Fragment>
       <div>
@@ -293,7 +220,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
         </div>
       </p>
 
-      <AdminAccount />
+      <AdminAccount onRegister={onRegister} />
       <section
         id="main"
         style={{ width: 600, marginLeft: "auto", marginRight: "auto" }}
@@ -393,6 +320,53 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
   );
 }
 
+function AdminAccount({ onRegister }: { onRegister: () => void }): VNode {
+  const { i18n } = useTranslationContext();
+  const r = useBackendContext();
+  const account = r.state.status === "loggedIn" ? r.state.username : "admin";
+  const result = useAccountDetails(account);
+
+  if (!result.ok) {
+    return handleNotOkResult(i18n, onRegister)(result);
+  }
+  const { data } = result;
+  const balance = Amounts.parseOrThrow(data.balance.amount);
+  const debitThreshold = Amounts.parseOrThrow(result.data.debitThreshold);
+  const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
+  const limit = balanceIsDebit
+    ? Amounts.sub(debitThreshold, balance).amount
+    : Amounts.add(balance, debitThreshold).amount;
+  if (!balance) return <Fragment />;
+  return (
+    <Fragment>
+      <section id="assets">
+        <div class="asset-summary">
+          <h2>{i18n.str`Bank account balance`}</h2>
+          {!balance ? (
+            <div class="large-amount" style={{ color: "gray" }}>
+              Waiting server response...
+            </div>
+          ) : (
+            <div class="large-amount amount">
+              {balanceIsDebit ? <b>-</b> : null}
+              <span class="value">{`${Amounts.stringifyValue(balance)}`}</span>
+              &nbsp;
+              <span class="currency">{`${balance.currency}`}</span>
+            </div>
+          )}
+        </div>
+      </section>
+      <PaytoWireTransferForm
+        focus
+        limit={limit}
+        onSuccess={() => {
+          notifyInfo(i18n.str`Wire transfer created!`);
+        }}
+      />
+    </Fragment>
+  );
+}
+
 const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/;
 const EMAIL_REGEX =
   /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@@ -442,10 +416,13 @@ export function UpdateAccountPassword({
   const [repeat, setRepeat] = useState<string | undefined>();
   const [error, saveError] = useState<ErrorMessage | undefined>();
 
-  if (result.clientError) {
-    if (result.isNotfound) return <div>account not found</div>;
-  }
   if (!result.ok) {
+    if (result.loading || result.type === ErrorType.TIMEOUT) {
+      return onLoadNotOk(result);
+    }
+    if (result.status === HttpStatusCode.NotFound) {
+      return <div>account not found</div>;
+    }
     return onLoadNotOk(result);
   }
 
@@ -679,10 +656,13 @@ export function ShowAccountDetails({
   >();
   const [error, saveError] = useState<ErrorMessage | undefined>();
 
-  if (result.clientError) {
-    if (result.isNotfound) return <div>account not found</div>;
-  }
   if (!result.ok) {
+    if (result.loading || result.type === ErrorType.TIMEOUT) {
+      return onLoadNotOk(result);
+    }
+    if (result.status === HttpStatusCode.NotFound) {
+      return <div>account not found</div>;
+    }
     return onLoadNotOk(result);
   }
 
@@ -804,10 +784,13 @@ function RemoveAccount({
   const { deleteAccount } = useAdminAccountAPI();
   const [error, saveError] = useState<ErrorMessage | undefined>();
 
-  if (result.clientError) {
-    if (result.isNotfound) return <div>account not found</div>;
-  }
   if (!result.ok) {
+    if (result.loading || result.type === ErrorType.TIMEOUT) {
+      return onLoadNotOk(result);
+    }
+    if (result.status === HttpStatusCode.NotFound) {
+      return <div>account not found</div>;
+    }
     return onLoadNotOk(result);
   }
 
-- 
cgit v1.2.3

