From 1723f16b9c4b008e9e44578c2587c7a1bd6560b4 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 25 Feb 2023 19:43:45 -0300 Subject: some fixes afte testing demobank with ms --- packages/demobank-ui/src/pages/AccountPage.tsx | 4 +- packages/demobank-ui/src/pages/AdminPage.tsx | 45 ++-- packages/demobank-ui/src/pages/BusinessAccount.tsx | 257 +++++++++++++++------ packages/demobank-ui/src/pages/HomePage.tsx | 56 ++++- .../src/pages/PaytoWireTransferForm.tsx | 14 +- .../demobank-ui/src/pages/PublicHistoriesPage.tsx | 4 +- .../demobank-ui/src/pages/RegistrationPage.tsx | 69 ++++-- packages/demobank-ui/src/pages/Routing.tsx | 56 ++++- .../demobank-ui/src/pages/WithdrawalQRCode.tsx | 4 +- 9 files changed, 374 insertions(+), 135 deletions(-) (limited to 'packages/demobank-ui/src/pages') diff --git a/packages/demobank-ui/src/pages/AccountPage.tsx b/packages/demobank-ui/src/pages/AccountPage.tsx index ae0c2b1f8..bd9a5acd7 100644 --- a/packages/demobank-ui/src/pages/AccountPage.tsx +++ b/packages/demobank-ui/src/pages/AccountPage.tsx @@ -28,7 +28,9 @@ import { PaymentOptions } from "./PaymentOptions.js"; interface Props { account: string; - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } /** * Query account information and show QR code if there is pending withdrawal diff --git a/packages/demobank-ui/src/pages/AdminPage.tsx b/packages/demobank-ui/src/pages/AdminPage.tsx index b4ce58588..0a1dc26ec 100644 --- a/packages/demobank-ui/src/pages/AdminPage.tsx +++ b/packages/demobank-ui/src/pages/AdminPage.tsx @@ -59,7 +59,9 @@ function randomPassword(): string { } interface Props { - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } /** * Query account information and show QR code if there is pending withdrawal @@ -109,6 +111,11 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { if (showCashouts) { return (
+
+

+ Cashout for account {showCashouts} +

+
{ @@ -116,15 +123,17 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { setShowCashouts(undefined); }} /> - { - e.preventDefault(); - setShowCashouts(undefined); - }} - /> +

+ { + e.preventDefault(); + setShowCashouts(undefined); + }} + /> +

); } @@ -184,7 +193,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode { onClose={() => setCreateAccount(false)} onCreateSuccess={(password) => { showInfoMessage( - i18n.str`Account created with password "${password}"`, + i18n.str`Account created with password "${password}". The user must change the password on the next login.`, ); setCreateAccount(false); }} @@ -326,7 +335,9 @@ export function UpdateAccountPassword({ onUpdateSuccess, onLoadNotOk, }: { - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; onClear: () => void; onUpdateSuccess: () => void; account: string; @@ -521,7 +532,9 @@ export function ShowAccountDetails({ onLoadNotOk, onChangePassword, }: { - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; onClear?: () => void; onChangePassword: () => void; onUpdateSuccess: () => void; @@ -628,7 +641,9 @@ function RemoveAccount({ onUpdateSuccess, onLoadNotOk, }: { - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; onClear: () => void; onUpdateSuccess: () => void; account: string; @@ -806,7 +821,7 @@ function AccountForm({ />
- + void; onRegister: () => void; - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } export function BusinessAccount({ onClose, @@ -79,6 +82,9 @@ export function BusinessAccount({ setNewcashout(false); }} onComplete={(id) => { + showInfoMessage( + i18n.str`Cashout created. You need to confirm the operation to complete the transaction.`, + ); setNewcashout(false); setShowCashoutDetails(id); }} @@ -156,7 +162,9 @@ interface PropsCashout { account: string; onComplete: (id: string) => void; onCancel: () => void; - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } type FormType = { @@ -180,7 +188,7 @@ function CreateCashout({ const result = useAccountDetails(account); const [error, saveError] = useState(); - const [form, setForm] = useState>({}); + const [form, setForm] = useState>({ isDebit: true }); const { createCashout } = useCircuitAccountAPI(); if (!result.ok) return onLoadNotOk(result); @@ -277,10 +285,14 @@ function CreateCashout({ type="text" readonly class="currency-indicator" - size={balance.currency.length} - maxLength={balance.currency.length} + size={ + !form.isDebit ? fiatCurrency.length : balance.currency.length + } + maxLength={ + !form.isDebit ? fiatCurrency.length : balance.currency.length + } tabIndex={-1} - value={balance.currency} + value={!form.isDebit ? fiatCurrency : balance.currency} />  
- +
      ; + switch (e.cause.type) { + case ErrorType.TIMEOUT: { + saveError({ + title: i18n.str`Request timeout, try again later.`, + }); + break; + } + case ErrorType.CLIENT: { + const errorData = e.cause.error; + + if ( + e.cause.status === HttpStatusCode.PreconditionFailed + ) { + saveError({ + title: i18n.str`The account does not have sufficient funds`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } else if (e.cause.status === HttpStatusCode.Conflict) { + saveError({ + title: i18n.str`No contact information for this channel`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } else { + saveError({ + title: i18n.str`New cashout gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } + break; + } + case ErrorType.SERVER: { + const errorData = e.cause.error; + if ( + e.cause.status === HttpStatusCode.ServiceUnavailable + ) { + saveError({ + title: i18n.str`The bank does not support the TAN channel for this operation`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } else { + saveError({ + title: i18n.str`Creating cashout returned with a server error`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + } + break; + } + case ErrorType.UNEXPECTED: { + saveError({ + title: i18n.str`Unexpected error trying to create cashout.`, + debug: JSON.stringify(error.cause), + }); + break; + } + default: { + assertUnreachable(e.cause); + } } } else if (error instanceof Error) { saveError({ @@ -592,7 +639,9 @@ function CreateCashout({ interface ShowCashoutProps { id: string; onCancel: () => void; - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } export function ShowCashoutDetails({ id, @@ -699,22 +748,59 @@ export function ShowCashoutDetails({ onCancel(); } catch (error) { if (error instanceof RequestError) { - const errorData: SandboxBackend.SandboxError = - error.info.error; - if ( - error.info.status === HttpStatusCode.PreconditionFailed - ) { - saveError({ - title: i18n.str`Cashout was already aborted`, - description: errorData.error.description, - debug: JSON.stringify(error.info), - }); - } else { - saveError({ - title: i18n.str`Aborting cashout gave response error`, - description: errorData.error.description, - debug: JSON.stringify(error.info), - }); + const e = + error as RequestError; + switch (e.cause.type) { + case ErrorType.TIMEOUT: { + saveError({ + title: i18n.str`Request timeout, try again later.`, + }); + break; + } + case ErrorType.CLIENT: { + const errorData = e.cause.error; + if ( + e.cause.status === HttpStatusCode.PreconditionFailed + ) { + saveError({ + title: i18n.str`Cashout was already aborted`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } else { + saveError({ + title: i18n.str`Aborting cashout gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.info), + }); + } + + saveError({ + title: i18n.str`Aborting cashout gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + break; + } + case ErrorType.SERVER: { + const errorData = e.cause.error; + saveError({ + title: i18n.str`Aborting cashout returned with a server error`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + break; + } + case ErrorType.UNEXPECTED: { + saveError({ + title: i18n.str`Unexpected error trying to abort cashout.`, + debug: JSON.stringify(error.cause), + }); + break; + } + default: { + assertUnreachable(e.cause); + } } } else if (error instanceof Error) { saveError({ @@ -741,13 +827,44 @@ export function ShowCashoutDetails({ }); } catch (error) { if (error instanceof RequestError) { - const errorData: SandboxBackend.SandboxError = - error.info.error; - saveError({ - title: i18n.str`Confirmation of cashout gave response error`, - description: errorData.error.description, - debug: JSON.stringify(error.info), - }); + const e = + error as RequestError; + switch (e.cause.type) { + case ErrorType.TIMEOUT: { + saveError({ + title: i18n.str`Request timeout, try again later.`, + }); + break; + } + case ErrorType.CLIENT: { + const errorData = e.cause.error; + saveError({ + title: i18n.str`Confirmation of cashout gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + break; + } + case ErrorType.SERVER: { + const errorData = e.cause.error; + saveError({ + title: i18n.str`Confirmation of cashout gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + break; + } + case ErrorType.UNEXPECTED: { + saveError({ + title: i18n.str`Unexpected error trying to cashout.`, + debug: JSON.stringify(error.cause), + }); + break; + } + default: { + assertUnreachable(e.cause); + } + } } else if (error instanceof Error) { saveError({ title: i18n.str`Confirmation failed, please report`, @@ -767,3 +884,7 @@ export function ShowCashoutDetails({
); } + +export function assertUnreachable(x: never): never { + throw new Error("Didn't expect to get here"); +} diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx index 5af195f48..a360bd64c 100644 --- a/packages/demobank-ui/src/pages/HomePage.tsx +++ b/packages/demobank-ui/src/pages/HomePage.tsx @@ -14,9 +14,11 @@ GNU Taler; see the file COPYING. If not, see */ -import { Logger } from "@gnu-taler/taler-util"; +import { HttpStatusCode, Logger } from "@gnu-taler/taler-util"; import { + ErrorType, HttpResponsePaginated, + RequestError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; @@ -119,9 +121,9 @@ function handleNotOkResult( onErrorHandler: (state: PageStateType["error"]) => void, i18n: ReturnType["i18n"], onRegister: () => void, -): (result: HttpResponsePaginated) => VNode { - return function handleNotOkResult2( - result: HttpResponsePaginated, +): (result: HttpResponsePaginated) => VNode { + return function handleNotOkResult2( + result: HttpResponsePaginated, ): VNode { if (result.clientError && result.isUnauthorized) { onErrorHandler({ @@ -137,13 +139,49 @@ function handleNotOkResult( } if (result.loading) return ; if (!result.ok) { - onErrorHandler({ - title: i18n.str`The backend reported a problem: HTTP status #${result.status}`, - description: `Diagnostic from ${result.info?.url} is "${result.message}"`, - debug: JSON.stringify(result.error), - }); + switch (result.type) { + case ErrorType.TIMEOUT: { + onErrorHandler({ + title: i18n.str`Request timeout, try again later.`, + }); + break; + } + case ErrorType.CLIENT: { + const errorData = result.error; + onErrorHandler({ + title: i18n.str`Could not load due to a client error`, + description: errorData.error.description, + debug: JSON.stringify(result), + }); + break; + } + case ErrorType.SERVER: { + const errorData = result.error; + onErrorHandler({ + title: i18n.str`Server returned with error`, + description: errorData.error.description, + debug: JSON.stringify(result), + }); + break; + } + case ErrorType.UNEXPECTED: { + onErrorHandler({ + title: i18n.str`Unexpected error.`, + description: `Diagnostic from ${result.info?.url} is "${result.message}"`, + debug: JSON.stringify(result.error), + }); + break; + } + default: { + assertUnreachable(result); + } + } + return ; } return
; }; } +export function assertUnreachable(x: never): never { + throw new Error("Didn't expect to get here"); +} diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx index d859b1cc7..07b011a00 100644 --- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx +++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx @@ -48,7 +48,7 @@ export function PaytoWireTransferForm({ onSuccess: () => void; currency: string; }): VNode { - const backend = useBackendContext(); + // const backend = useBackendContext(); // const { pageState, pageStateSetter } = usePageContext(); // NOTE: used for go-back button? const [isRawPayto, setIsRawPayto] = useState(false); @@ -188,17 +188,7 @@ export function PaytoWireTransferForm({ paytoUri, amount: `${currency}:${amount}`, }); - // return await createTransactionCall( - // transactionData, - // backend.state, - // pageStateSetter, - // () => { - // setAmount(undefined); - // setIban(undefined); - // setSubject(undefined); - // }, - // i18n, - // ); + onSuccess(); }} /> (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } /** diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx index 247ef8d80..c6bc3c327 100644 --- a/packages/demobank-ui/src/pages/RegistrationPage.tsx +++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx @@ -15,6 +15,7 @@ */ import { HttpStatusCode, Logger } from "@gnu-taler/taler-util"; import { + ErrorType, RequestError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -176,26 +177,52 @@ function RegistrationForm({ 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), - }); + const e = + error as RequestError; + switch (e.cause.type) { + case ErrorType.TIMEOUT: { + onError({ + title: i18n.str`Request timeout, try again later.`, + }); + break; + } + case ErrorType.CLIENT: { + const errorData = e.cause.error; + if (e.cause.status === HttpStatusCode.Conflict) { + onError({ + title: i18n.str`That username is already taken`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + } else { + onError({ + title: i18n.str`New registration gave response error`, + description: errorData.error.description, + debug: JSON.stringify(error.cause), + }); + } + break; + } + case ErrorType.SERVER: { + const errorData = e.cause.error; + onError({ + title: i18n.str`New registration gave response error`, + description: errorData?.error?.description, + debug: JSON.stringify(error.cause), + }); + break; + } + case ErrorType.UNEXPECTED: { + onError({ + title: i18n.str`Unexpected error doing the registration.`, + debug: JSON.stringify(error.cause), + }); + break; + } + default: { + assertUnreachable(e.cause); + } } - } else if (error instanceof Error) { - onError({ - title: i18n.str`Registration failed, please report`, - description: error.message, - }); } } }} @@ -222,3 +249,7 @@ function RegistrationForm({ ); } + +export function assertUnreachable(x: never): never { + throw new Error("Didn't expect to get here"); +} diff --git a/packages/demobank-ui/src/pages/Routing.tsx b/packages/demobank-ui/src/pages/Routing.tsx index 48f226574..8234d8988 100644 --- a/packages/demobank-ui/src/pages/Routing.tsx +++ b/packages/demobank-ui/src/pages/Routing.tsx @@ -15,6 +15,7 @@ */ import { + ErrorType, HttpResponsePaginated, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,9 +35,9 @@ function handleNotOkResult( safe: string, saveError: (state: PageStateType["error"]) => void, i18n: ReturnType["i18n"], -): (result: HttpResponsePaginated) => VNode { - return function handleNotOkResult2( - result: HttpResponsePaginated, +): (result: HttpResponsePaginated) => VNode { + return function handleNotOkResult2( + result: HttpResponsePaginated, ): VNode { if (result.clientError && result.isUnauthorized) { route(safe); @@ -50,12 +51,45 @@ function handleNotOkResult( } if (result.loading) return ; if (!result.ok) { - saveError({ - title: i18n.str`The backend reported a problem: HTTP status #${result.status}`, - description: i18n.str`Diagnostic from ${result.info?.url} is "${result.message}"`, - debug: JSON.stringify(result.error), - }); - route(safe); + switch (result.type) { + case ErrorType.TIMEOUT: { + saveError({ + title: i18n.str`Request timeout, try again later.`, + }); + break; + } + case ErrorType.CLIENT: { + const errorData = result.error; + saveError({ + title: i18n.str`Could not load due to a client error`, + description: errorData.error.description, + debug: JSON.stringify(result), + }); + break; + } + case ErrorType.SERVER: { + const errorData = result.error; + saveError({ + title: i18n.str`Server returned with error`, + description: errorData.error.description, + debug: JSON.stringify(result), + }); + break; + } + case ErrorType.UNEXPECTED: { + saveError({ + title: i18n.str`Unexpected error.`, + description: `Diagnostic from ${result.info?.url} is "${result.message}"`, + debug: JSON.stringify(result.error), + }); + break; + } + default: + { + assertUnreachable(result); + } + route(safe); + } } return
; }; @@ -137,3 +171,7 @@ function Redirect({ to }: { to: string }): VNode { }, []); return
being redirected to {to}
; } + +export function assertUnreachable(x: never): never { + throw new Error("Didn't expect to get here"); +} diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx index fd91c0e1a..d4c95d830 100644 --- a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx +++ b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx @@ -33,7 +33,9 @@ interface Props { withdrawalId: string; talerWithdrawUri: string; onAbort: () => void; - onLoadNotOk: (error: HttpResponsePaginated) => VNode; + onLoadNotOk: ( + error: HttpResponsePaginated, + ) => VNode; } /** * Offer the QR code (and a clickable taler://-link) to -- cgit v1.2.3