several minor fixes worked out

This commit is contained in:
Sebastian 2022-10-27 14:27:41 -03:00
parent 4e4f526fa5
commit 3d595ddae2
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
2 changed files with 263 additions and 103 deletions

View File

@ -1,45 +1,49 @@
Urgent TODOs: Urgent TODOs:
- General: - General:
* not only Nora dark-theme, but default light! (CSS)
* auto-focus on input fields is not working well - not only Nora dark-theme, but default light! (CSS)
* buttons should be visibly insensitive - DONE: auto-focus on input fields is not working well
- DONE: buttons should be visibly insensitive
as long as required input fields are not as long as required input fields are not
working working
* next required invalid/missing input field is - DONE: next required invalid/missing input field is
not properly highlighted in red not properly highlighted in red
* Logout button needs more padding to the right (CSS) - Logout button needs more padding to the right (CSS)
- Error bar: - Error bar:
* shows JSON, should only show good error message - DONE: hows JSON, should only show good error message
and numeric code, not JSON syntax and numeric code, not JSON syntax
* should auto-hide after next action, no need for - should auto-hide after next action, no need for
"clear"! "clear"!
* need variant "status bar" in green (or blue) - need variant "status bar" in green (or blue)
which shows status of last operation which shows status of last operation
* H1-Titles: * H1-Titles:
* Center more (currently way on the left) (CSS) - Center more (currently way on the left) (CSS)
- Assets: - Assets:
* Numeric amount needs to be shown MUCH bigger (CSS)
* Center more? (CSS) - Numeric amount needs to be shown MUCH bigger (CSS)
- Center more? (CSS)
- Payments: - Payments:
* Amount to withdraw currently shown in white-on-white (CSS)
* Big frame drawn around notebook-tabs is not nice (CSS) - Amount to withdraw currently shown in white-on-white (CSS)
* Center more? (CSS) - Big frame drawn around notebook-tabs is not nice (CSS)
* "Wire to bank account" - Center more? (CSS)
- "Wire to bank account"
- maybe split two types (payto and IBAN) into - maybe split two types (payto and IBAN) into
two tabs? two tabs?
- currently cannot switch back from payto to IBAN - currently cannot switch back from payto to IBAN
- Withdraw: - Withdraw:
* Should use new 'status' bar at the end, instead
- Should use new 'status' bar at the end, instead
of extra dialog with "close" button of extra dialog with "close" button
* ditto for bank-wire-transfer final stage - ditto for bank-wire-transfer final stage
- Footer: - Footer:
* overlaps with transaction history or other - overlaps with transaction history or other
content, needs to consistently show at the content, needs to consistently show at the
end! => change rendering logic!? (CSS?) end! => change rendering logic!? (CSS?)

View File

@ -31,7 +31,7 @@ import { QR } from "../../components/QR.js";
import { useLocalStorage, useNotNullLocalStorage } from "../../hooks/index.js"; import { useLocalStorage, useNotNullLocalStorage } from "../../hooks/index.js";
import { Translate, useTranslator } from "../../i18n/index.js"; import { Translate, useTranslator } from "../../i18n/index.js";
import "../../scss/main.scss"; import "../../scss/main.scss";
import { parsePaytoUri } from "@gnu-taler/taler-util"; import { Amounts, parsePaytoUri } from "@gnu-taler/taler-util";
/** /**
* If the first argument does not look like a placeholder, return it. * If the first argument does not look like a placeholder, return it.
@ -80,7 +80,22 @@ const UI_BANK_NAME = replacementOrDefault(
* Contexts * * Contexts *
***********/ ***********/
const CurrencyContext = createContext<any>(null); const CurrencyContext = createContext<any>(null);
const PageContext = createContext<any>(null); type PageContextType = [PageStateType, StateUpdater<PageStateType>];
const PageContextDefault: PageContextType = [
{
hasError: false,
hasInfo: false,
isLoggedIn: false,
isRawPayto: false,
showPublicHistories: false,
tryRegister: false,
withdrawalInProgress: false,
},
() => {
null;
},
];
const PageContext = createContext<PageContextType>(PageContextDefault);
/********************************************** /**********************************************
* Type definitions for states and API calls. * * Type definitions for states and API calls. *
@ -91,9 +106,9 @@ const PageContext = createContext<any>(null);
* authenticate at the bank's backend. * authenticate at the bank's backend.
*/ */
interface BackendStateType { interface BackendStateType {
url: string; url?: string;
username: string; username?: string;
password: string; password?: string;
} }
/** /**
@ -112,9 +127,9 @@ interface TransactionRequestType {
* Request body of /register. * Request body of /register.
*/ */
interface CredentialsRequestType { interface CredentialsRequestType {
username: string; username?: string;
password: string; password?: string;
repeatPassword: string; repeatPassword?: string;
} }
/** /**
@ -126,14 +141,9 @@ interface CredentialsRequestType {
// } // }
interface WireTransferRequestType { interface WireTransferRequestType {
iban: string; iban?: string;
subject: string; subject?: string;
amount: string; amount?: string;
}
interface Amount {
value: string;
currency: string;
} }
/** /**
@ -147,7 +157,12 @@ interface PageStateType {
hasError: boolean; hasError: boolean;
hasInfo: boolean; hasInfo: boolean;
withdrawalInProgress: boolean; withdrawalInProgress: boolean;
error?: string; error?: {
description?: string;
title: string;
debug?: string;
};
info?: string; info?: string;
talerWithdrawUri?: string; talerWithdrawUri?: string;
/** /**
@ -225,12 +240,13 @@ function getIbanFromPayto(url: string): string {
/** /**
* Extract value and currency from a $currency:x.y amount. * Extract value and currency from a $currency:x.y amount.
*/ */
function parseAmount(val: string): Amount { // function parseAmount(val: string): Amount {
const format = /^[A-Z]+:[0-9]+(\.[0-9]+)?$/; // Amounts.parse(val)
if (!format.test(val)) throw Error(`Backend gave invalid amount: ${val}.`); // const format = /^[A-Z]+:[0-9]+(\.[0-9]+)?$/;
const amountSplit = val.split(":"); // if (!format.test(val)) throw Error(`Backend gave invalid amount: ${val}.`);
return { value: amountSplit[1], currency: amountSplit[0] }; // const amountSplit = val.split(":");
} // return { value: amountSplit[1], currency: amountSplit[0] };
// }
/** /**
* Get username from the backend state, and throw * Get username from the backend state, and throw
@ -240,6 +256,9 @@ function getUsername(backendState: BackendStateTypeOpt): string {
if (typeof backendState === "undefined") if (typeof backendState === "undefined")
throw Error("Username can't be found in a undefined backend state."); throw Error("Username can't be found in a undefined backend state.");
if (!backendState.username) {
throw Error("No username, must login first.");
}
return backendState.username; return backendState.username;
} }
@ -283,12 +302,14 @@ function useTransactionPageNumber(): [number, StateUpdater<number>] {
/** /**
* Craft headers with Authorization and Content-Type. * Craft headers with Authorization and Content-Type.
*/ */
function prepareHeaders(username: string, password: string): Headers { function prepareHeaders(username?: string, password?: string): Headers {
const headers = new Headers(); const headers = new Headers();
headers.append( if (username && password) {
"Authorization", headers.append(
`Basic ${window.btoa(`${username}:${password}`)}`, "Authorization",
); `Basic ${window.btoa(`${username}:${password}`)}`,
);
}
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
return headers; return headers;
} }
@ -461,13 +482,13 @@ function usePageState(
): [PageStateType, StateUpdater<PageStateType>] { ): [PageStateType, StateUpdater<PageStateType>] {
const ret = useNotNullLocalStorage("page-state", JSON.stringify(state)); const ret = useNotNullLocalStorage("page-state", JSON.stringify(state));
const retObj: PageStateType = JSON.parse(ret[0]); const retObj: PageStateType = JSON.parse(ret[0]);
console.log("Current page state", retObj);
const retSetter: StateUpdater<PageStateType> = function (val) { const retSetter: StateUpdater<PageStateType> = function (val) {
const newVal = const newVal =
val instanceof Function val instanceof Function
? JSON.stringify(val(retObj)) ? JSON.stringify(val(retObj))
: JSON.stringify(val); : JSON.stringify(val);
console.log("Setting new page state", newVal);
ret[1](newVal); ret[1](newVal);
}; };
return [retObj, retSetter]; return [retObj, retSetter];
@ -502,7 +523,9 @@ async function abortWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: "No credentials found.", error: {
title: `No credentials found.`,
},
})); }));
return; return;
} }
@ -511,7 +534,9 @@ async function abortWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: "No withdrawal ID found.", error: {
title: `No withdrawal ID found.`,
},
})); }));
return; return;
} }
@ -541,11 +566,16 @@ async function abortWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Could not abort the withdrawal: ${error}`, error: {
title: `Could not abort the withdrawal.`,
description: (error as any).error.description,
debug: JSON.stringify(error),
},
})); }));
return; return;
} }
if (!res.ok) { if (!res.ok) {
const response = await res.json();
console.log( console.log(
`Withdrawal abort gave response error (${res.status})`, `Withdrawal abort gave response error (${res.status})`,
res.statusText, res.statusText,
@ -553,7 +583,11 @@ async function abortWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Withdrawal abortion gave response error (${res.status})`, error: {
title: `Withdrawal abortion failed.`,
description: response.error.description,
debug: JSON.stringify(res.status),
},
})); }));
return; return;
} }
@ -587,7 +621,9 @@ async function confirmWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: "No credentials found.", error: {
title: "No credentials found.",
},
})); }));
return; return;
} }
@ -596,7 +632,9 @@ async function confirmWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: "No withdrawal ID found.", error: {
title: "No withdrawal ID found.",
},
})); }));
return; return;
} }
@ -629,11 +667,15 @@ async function confirmWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Could not confirm the withdrawal: ${error}`, error: {
title: `Could not confirm the withdrawal`,
description: (error as any).error.description,
debug: JSON.stringify(error),
},
})); }));
return; return;
} }
if (res ? !res.ok : true) { if (!res || !res.ok) {
// assume not ok if res is null // assume not ok if res is null
console.log( console.log(
`Withdrawal confirmation gave response error (${res.status})`, `Withdrawal confirmation gave response error (${res.status})`,
@ -642,7 +684,10 @@ async function confirmWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Withdrawal confirmation gave response error (${res.status})`, error: {
title: `Withdrawal confirmation gave response error`,
debug: JSON.stringify(res.status),
},
})); }));
return; return;
} }
@ -684,20 +729,28 @@ async function createTransactionCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Could not create the wire transfer: ${error}`, error: {
title: `Could not create the wire transfer`,
description: (error as any).error.description,
debug: JSON.stringify(error),
},
})); }));
return; return;
} }
// POST happened, status not sure yet. // POST happened, status not sure yet.
if (!res.ok) { if (!res.ok) {
const responseText = JSON.stringify(await res.json()); const response = await res.json();
console.log( console.log(
`Transfer creation gave response error: ${responseText} (${res.status})`, `Transfer creation gave response error: ${response} (${res.status})`,
); );
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Transfer creation gave response error: ${responseText} (${res.status})`, error: {
title: `Transfer creation gave response error`,
description: response.error.description,
debug: JSON.stringify(response),
},
})); }));
return; return;
} }
@ -733,7 +786,9 @@ async function createWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: "No credentials given.", error: {
title: "No credentials given.",
},
})); }));
return; return;
} }
@ -758,19 +813,27 @@ async function createWithdrawalCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Could not create withdrawal operation: ${error}`, error: {
title: `Could not create withdrawal operation`,
description: (error as any).error.description,
debug: JSON.stringify(error),
},
})); }));
return; return;
} }
if (!res.ok) { if (!res.ok) {
const responseText = await res.text(); const response = await res.text();
console.log( console.log(
`Withdrawal creation gave response error: ${responseText} (${res.status})`, `Withdrawal creation gave response error: ${response} (${res.status})`,
); );
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: `Withdrawal creation gave response error: ${responseText} (${res.status})`, error: {
title: `Withdrawal creation gave response error`,
description: response.error.description,
debug: `${response} (${res.status})`,
},
})); }));
return; return;
} }
@ -853,7 +916,10 @@ async function registrationCall(
pageStateSetter((prevState) => ({ pageStateSetter((prevState) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: "Registration failed, please report.", error: {
title: `Registration failed, please report`,
debug: JSON.stringify(error),
},
})); }));
return; return;
} }
@ -893,7 +959,24 @@ function ErrorBanner(Props: any): VNode | null {
if (!pageState.hasError) return null; if (!pageState.hasError) return null;
const rval = ( const rval = (
<p class="informational informational-fail">{pageState.error}</p> <div class="informational informational-fail" style={{ marginTop: 8 }}>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<p>
<b>{pageState.error.title}</b>
</p>
<div>
<input
type="button"
class="pure-button"
value="Clear"
onClick={async () => {
pageStateSetter((prev) => ({ ...prev, error: undefined }));
}}
/>
</div>
</div>
<p>{pageState.error.description}</p>
</div>
); );
delete pageState.error; delete pageState.error;
pageState.hasError = false; pageState.hasError = false;
@ -1024,7 +1107,11 @@ function ShowInputErrorLabel({
isDirty: boolean; isDirty: boolean;
}): VNode { }): VNode {
if (message && isDirty) if (message && isDirty)
return <p class="informational informational-fail">{message}</p>; return (
<div class="informational informational-fail" style={{ marginTop: 8 }}>
{message}
</div>
);
return <Fragment />; return <Fragment />;
} }
@ -1046,6 +1133,33 @@ function PaytoWireTransfer(Props: any): VNode {
if (focus) ref.current?.focus(); if (focus) ref.current?.focus();
}, [focus, pageState.isRawPayto]); }, [focus, pageState.isRawPayto]);
// typeof submitData === "undefined" ||
// typeof submitData.iban === "undefined" ||
// submitData.iban === "" ||
// typeof submitData.subject === "undefined" ||
// submitData.subject === "" ||
// typeof submitData.amount === "undefined" ||
// submitData.amount === ""
let parsedAmount = undefined;
const errorsWire = !submitData
? undefined
: undefinedIfEmpty({
iban: !submitData.iban
? i18n`Missing IBAN`
: !/^[A-Z0-9]*$/.test(submitData.iban)
? i18n`IBAN should have just uppercased letters and numbers`
: undefined,
subject: !submitData.subject ? i18n`Missing subject` : undefined,
amount: !submitData.amount
? i18n`Missing amount`
: !(parsedAmount = Amounts.parse(`${currency}:${submitData.amount}`))
? i18n`Amount is not valid`
: Amounts.isZero(parsedAmount)
? i18n`Should be greater than 0`
: undefined,
});
if (!pageState.isRawPayto) if (!pageState.isRawPayto)
return ( return (
<div> <div>
@ -1069,6 +1183,10 @@ function PaytoWireTransfer(Props: any): VNode {
}} }}
/> />
<br /> <br />
<ShowInputErrorLabel
message={errorsWire?.iban}
isDirty={submitData?.iban !== undefined}
/>
<br /> <br />
<label for="subject">{i18n`Transfer subject:`}</label>&nbsp; <label for="subject">{i18n`Transfer subject:`}</label>&nbsp;
<input <input
@ -1086,6 +1204,10 @@ function PaytoWireTransfer(Props: any): VNode {
}} }}
/> />
<br /> <br />
<ShowInputErrorLabel
message={errorsWire?.subject}
isDirty={submitData?.subject !== undefined}
/>
<br /> <br />
<label for="amount">{i18n`Amount:`}</label>&nbsp; <label for="amount">{i18n`Amount:`}</label>&nbsp;
<input <input
@ -1099,7 +1221,7 @@ function PaytoWireTransfer(Props: any): VNode {
onInput={(e): void => { onInput={(e): void => {
submitDataSetter((submitData: any) => ({ submitDataSetter((submitData: any) => ({
...submitData, ...submitData,
amount: e.currentTarget.value.replace(",", "."), amount: e.currentTarget.value,
})); }));
}} }}
/> />
@ -1113,11 +1235,17 @@ function PaytoWireTransfer(Props: any): VNode {
tabIndex={-1} tabIndex={-1}
value={currency} value={currency}
/> />
<ShowInputErrorLabel
message={errorsWire?.amount}
isDirty={submitData?.amount !== undefined}
/>
</p> </p>
<p>
<p style={{ display: "flex", justifyContent: "space-between" }}>
<input <input
type="submit" type="submit"
class="pure-button pure-button-primary" class="pure-button pure-button-primary"
disabled={!!errorsWire}
value="Send" value="Send"
onClick={async () => { onClick={async () => {
if ( if (
@ -1133,7 +1261,9 @@ function PaytoWireTransfer(Props: any): VNode {
pageStateSetter((prevState: PageStateType) => ({ pageStateSetter((prevState: PageStateType) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: i18n`Field(s) missing.`, error: {
title: i18n`Field(s) missing.`,
},
})); }));
return; return;
} }
@ -1147,15 +1277,18 @@ function PaytoWireTransfer(Props: any): VNode {
transactionData, transactionData,
backendState, backendState,
pageStateSetter, pageStateSetter,
() => () => submitDataSetter((p) => ({})),
submitDataSetter((p) => ({
amount: "",
iban: "",
subject: "",
})),
); );
}} }}
/> />
<input
type="button"
class="pure-button"
value="Clear"
onClick={async () => {
submitDataSetter((p) => ({}));
}}
/>
</p> </p>
</div> </div>
<p> <p>
@ -1175,7 +1308,7 @@ function PaytoWireTransfer(Props: any): VNode {
</div> </div>
); );
const errors = undefinedIfEmpty({ const errorsPayto = undefinedIfEmpty({
rawPaytoInput: !rawPaytoInput rawPaytoInput: !rawPaytoInput
? i18n`Missing payto address` ? i18n`Missing payto address`
: !parsePaytoUri(rawPaytoInput) : !parsePaytoUri(rawPaytoInput)
@ -1204,7 +1337,7 @@ function PaytoWireTransfer(Props: any): VNode {
}} }}
/> />
<ShowInputErrorLabel <ShowInputErrorLabel
message={errors?.rawPaytoInput} message={errorsPayto?.rawPaytoInput}
isDirty={rawPaytoInputDirty} isDirty={rawPaytoInputDirty}
/> />
<br /> <br />
@ -1220,7 +1353,7 @@ function PaytoWireTransfer(Props: any): VNode {
<input <input
class="pure-button pure-button-primary" class="pure-button pure-button-primary"
type="submit" type="submit"
disabled={!!errors} disabled={!!errorsPayto}
value={i18n`Send`} value={i18n`Send`}
onClick={async () => { onClick={async () => {
// empty string evaluates to false. // empty string evaluates to false.
@ -1323,7 +1456,9 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode {
pageStateSetter((prevState: PageStateType) => ({ pageStateSetter((prevState: PageStateType) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: i18n`Answer is wrong.`, error: {
title: i18n`Answer is wrong.`,
},
})); }));
}} }}
> >
@ -1366,7 +1501,7 @@ function QrCodeSection({
}: { }: {
talerWithdrawUri: string; talerWithdrawUri: string;
abortButton: h.JSX.Element; abortButton: h.JSX.Element;
}) { }): VNode {
const i18n = useTranslator(); const i18n = useTranslator();
useEffect(() => { useEffect(() => {
//Taler Wallet WebExtension is listening to headers response and tab updates. //Taler Wallet WebExtension is listening to headers response and tab updates.
@ -1405,8 +1540,12 @@ function TalerWithdrawalQRCode(Props: any): VNode {
class="pure-button" class="pure-button"
onClick={() => { onClick={() => {
pageStateSetter((prevState: PageStateType) => { pageStateSetter((prevState: PageStateType) => {
const { withdrawalId, talerWithdrawUri, ...rest } = prevState; return {
return { ...rest, withdrawalInProgress: false }; ...prevState,
withdrawalId: undefined,
talerWithdrawUri: undefined,
withdrawalInProgress: false,
};
}); });
}} }}
>{i18n`Abort`}</a> >{i18n`Abort`}</a>
@ -1415,8 +1554,9 @@ function TalerWithdrawalQRCode(Props: any): VNode {
console.log(`Showing withdraw URI: ${talerWithdrawUri}`); console.log(`Showing withdraw URI: ${talerWithdrawUri}`);
// waiting for the wallet: // waiting for the wallet:
const { data, error, mutate } = useSWR( const { data, error } = useSWR(
`integration-api/withdrawal-operation/${withdrawalId}`, `integration-api/withdrawal-operation/${withdrawalId}`,
{ refreshInterval: 1000 },
); );
if (typeof error !== "undefined") { if (typeof error !== "undefined") {
@ -1427,7 +1567,9 @@ function TalerWithdrawalQRCode(Props: any): VNode {
pageStateSetter((prevState: PageStateType) => ({ pageStateSetter((prevState: PageStateType) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
error: i18n`withdrawal (${withdrawalId}) was never (correctly) created at the bank...`, error: {
title: i18n`withdrawal (${withdrawalId}) was never (correctly) created at the bank...`,
},
})); }));
return ( return (
<Fragment> <Fragment>
@ -1453,12 +1595,13 @@ function TalerWithdrawalQRCode(Props: any): VNode {
...rest, ...rest,
withdrawalInProgress: false, withdrawalInProgress: false,
hasError: true, hasError: true,
error: i18n`This withdrawal was aborted!`, error: {
title: i18n`This withdrawal was aborted!`,
},
}; };
}); });
if (!data.selection_done) { if (!data.selection_done) {
setTimeout(() => mutate(), 1000); // check again after 1 second.
return ( return (
<QrCodeSection <QrCodeSection
talerWithdrawUri={talerWithdrawUri} talerWithdrawUri={talerWithdrawUri}
@ -1699,10 +1842,7 @@ function LoginForm(Props: any): VNode {
console.log("login data is undefined", submitData); console.log("login data is undefined", submitData);
return; return;
} }
if ( if (!submitData.password || !submitData.username) {
submitData.password.length == 0 ||
submitData.username.length == 0
) {
console.log( console.log(
"username or password is the empty string", "username or password is the empty string",
submitData, submitData,
@ -1716,7 +1856,7 @@ function LoginForm(Props: any): VNode {
backendStateSetter, backendStateSetter,
pageStateSetter, pageStateSetter,
); );
submitDataSetter(undefined); submitDataSetter({});
}} }}
> >
{i18n`Login`} {i18n`Login`}
@ -1963,7 +2103,13 @@ function Account(Props: any): VNode {
const { accountLabel, backendState } = Props; const { accountLabel, backendState } = Props;
// Getting the bank account balance: // Getting the bank account balance:
const endpoint = `access-api/accounts/${accountLabel}`; const endpoint = `access-api/accounts/${accountLabel}`;
const { data, error } = useSWR(endpoint); const { data, error } = useSWR(endpoint, {
// refreshInterval: 0,
// revalidateIfStale: false,
// revalidateOnMount: false,
// revalidateOnFocus: false,
// revalidateOnReconnect: false,
});
const [pageState, pageStateSetter] = useContext(PageContext); const [pageState, pageStateSetter] = useContext(PageContext);
const { withdrawalInProgress, withdrawalId, isLoggedIn, talerWithdrawUri } = const { withdrawalInProgress, withdrawalId, isLoggedIn, talerWithdrawUri } =
pageState; pageState;
@ -1978,7 +2124,7 @@ function Account(Props: any): VNode {
txsPages.push(<Transactions accountLabel={accountLabel} pageNumber={i} />); txsPages.push(<Transactions accountLabel={accountLabel} pageNumber={i} />);
if (typeof error !== "undefined") { if (typeof error !== "undefined") {
console.log("account error", error); console.log("account error", error, endpoint);
/** /**
* FIXME: to minimize the code, try only one invocation * FIXME: to minimize the code, try only one invocation
* of pageStateSetter, after having decided the error * of pageStateSetter, after having decided the error
@ -1990,7 +2136,9 @@ function Account(Props: any): VNode {
...prevState, ...prevState,
hasError: true, hasError: true,
isLoggedIn: false, isLoggedIn: false,
error: i18n`Username or account label '${accountLabel}' not found. Won't login.`, error: {
title: i18n`Username or account label '${accountLabel}' not found. Won't login.`,
},
})); }));
/** /**
@ -2014,7 +2162,9 @@ function Account(Props: any): VNode {
...prevState, ...prevState,
hasError: true, hasError: true,
isLoggedIn: false, isLoggedIn: false,
error: i18n`Wrong credentials given.`, error: {
title: i18n`Wrong credentials given.`,
},
})); }));
return <p>Wrong credentials...</p>; return <p>Wrong credentials...</p>;
} }
@ -2022,8 +2172,11 @@ function Account(Props: any): VNode {
pageStateSetter((prevState: PageStateType) => ({ pageStateSetter((prevState: PageStateType) => ({
...prevState, ...prevState,
hasError: true, hasError: true,
isLoggedIn: false, // isLoggedIn: false,
error: i18n`Account information could not be retrieved.`, error: {
title: i18n`Account information could not be retrieved.`,
debug: JSON.stringify(error),
},
})); }));
return <p>Unknown problem...</p>; return <p>Unknown problem...</p>;
} }
@ -2057,7 +2210,8 @@ function Account(Props: any): VNode {
</BankFrame> </BankFrame>
); );
} }
const balance = parseAmount(data.balance.amount); const balance = Amounts.parseOrThrow(data.balance.amount);
const balanceValue = Amounts.stringifyValue(balance);
return ( return (
<BankFrame> <BankFrame>
@ -2073,7 +2227,7 @@ function Account(Props: any): VNode {
<h2>{i18n`Bank account balance`}</h2> <h2>{i18n`Bank account balance`}</h2>
{data.balance.credit_debit_indicator == "debit" ? <b>-</b> : null} {data.balance.credit_debit_indicator == "debit" ? <b>-</b> : null}
<div class="large-amount amount"> <div class="large-amount amount">
<span class="value">{`${balance.value}`}</span>&nbsp; <span class="value">{`${balanceValue}`}</span>&nbsp;
<span class="currency">{`${balance.currency}`}</span> <span class="currency">{`${balance.currency}`}</span>
</div> </div>
</div> </div>
@ -2292,7 +2446,9 @@ export function BankHome(): VNode {
...prevState, ...prevState,
hasError: true, hasError: true,
isLoggedIn: false, isLoggedIn: false,
error: i18n`Page has a problem: logged in but backend state is lost.`, error: {
title: i18n`Page has a problem: logged in but backend state is lost.`,
},
})); }));
return <p>Error: waiting for details...</p>; return <p>Error: waiting for details...</p>;
} }