diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/home')
10 files changed, 155 insertions, 193 deletions
diff --git a/packages/demobank-ui/src/pages/home/AccountPage.tsx b/packages/demobank-ui/src/pages/home/AccountPage.tsx index 2bc05c332..16ff601ec 100644 --- a/packages/demobank-ui/src/pages/home/AccountPage.tsx +++ b/packages/demobank-ui/src/pages/home/AccountPage.tsx @@ -16,14 +16,15 @@ import { Amounts, HttpStatusCode } from "@gnu-taler/taler-util"; import { hooks } from "@gnu-taler/web-util/lib/index.browser"; -import { h, Fragment, VNode } from "preact"; -import { StateUpdater, useEffect, useState } from "preact/hooks"; +import { ComponentChildren, Fragment, h, VNode } from "preact"; +import { StateUpdater, useEffect } from "preact/hooks"; import useSWR, { SWRConfig, useSWRConfig } from "swr"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; -import { useBackendState } from "../../hooks/backend.js"; +import { BackendInfo } from "../../hooks/backend.js"; import { bankUiSettings } from "../../settings.js"; -import { getIbanFromPayto } from "../../utils.js"; +import { getIbanFromPayto, prepareHeaders } from "../../utils.js"; import { BankFrame } from "./BankFrame.js"; import { LoginForm } from "./LoginForm.js"; import { PaymentOptions } from "./PaymentOptions.js"; @@ -31,11 +32,10 @@ import { TalerWithdrawalQRCode } from "./TalerWithdrawalQRCode.js"; import { Transactions } from "./Transactions.js"; export function AccountPage(): VNode { - const [backendState, backendStateSetter] = useBackendState(); + const backend = useBackendContext(); const { i18n } = useTranslationContext(); - const { pageState, pageStateSetter } = usePageContext(); - if (!pageState.isLoggedIn) { + if (backend.state.status === "loggedOut") { return ( <BankFrame> <h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1> @@ -44,28 +44,9 @@ export function AccountPage(): VNode { ); } - if (typeof backendState === "undefined") { - pageStateSetter((prevState) => ({ - ...prevState, - - isLoggedIn: false, - error: { - title: i18n.str`Page has a problem: logged in but backend state is lost.`, - }, - })); - return <p>Error: waiting for details...</p>; - } - console.log("Showing the profile page.."); return ( - <SWRWithCredentials - username={backendState.username} - password={backendState.password} - backendUrl={backendState.url} - > - <Account - accountLabel={backendState.username} - backendState={backendState} - /> + <SWRWithCredentials info={backend.state}> + <Account accountLabel={backend.state.username} /> </SWRWithCredentials> ); } @@ -73,16 +54,20 @@ export function AccountPage(): VNode { /** * Factor out login credentials. */ -function SWRWithCredentials(props: any): VNode { - const { username, password, backendUrl } = props; - const headers = new Headers(); - headers.append("Authorization", `Basic ${btoa(`${username}:${password}`)}`); - console.log("Likely backend base URL", backendUrl); +function SWRWithCredentials({ + children, + info, +}: { + children: ComponentChildren; + info: BackendInfo; +}): VNode { + const { username, password, url: backendUrl } = info; + const headers = prepareHeaders(username, password); return ( <SWRConfig value={{ fetcher: (url: string) => { - return fetch(backendUrl + url || "", { headers }).then((r) => { + return fetch(new URL(url, backendUrl).href, { headers }).then((r) => { if (!r.ok) throw { status: r.status, json: r.json() }; return r.json(); @@ -90,7 +75,7 @@ function SWRWithCredentials(props: any): VNode { }, }} > - {props.children} + {children as any} </SWRConfig> ); } @@ -100,9 +85,9 @@ function SWRWithCredentials(props: any): VNode { * is mostly needed to provide the user's credentials to POST * to the bank. */ -function Account(Props: any): VNode { +function Account({ accountLabel }: { accountLabel: string }): VNode { const { cache } = useSWRConfig(); - const { accountLabel, backendState } = Props; + // Getting the bank account balance: const endpoint = `access-api/accounts/${accountLabel}`; const { data, error, mutate } = useSWR(endpoint, { @@ -112,14 +97,9 @@ function Account(Props: any): VNode { // revalidateOnFocus: false, // revalidateOnReconnect: false, }); + const backend = useBackendContext(); const { pageState, pageStateSetter: setPageState } = usePageContext(); - const { - withdrawalInProgress, - withdrawalId, - isLoggedIn, - talerWithdrawUri, - timestamp, - } = pageState; + const { withdrawalId, talerWithdrawUri, timestamp } = pageState; const { i18n } = useTranslationContext(); useEffect(() => { mutate(); @@ -129,10 +109,11 @@ function Account(Props: any): VNode { * This part shows a list of transactions: with 5 elements by * default and offers a "load more" button. */ - const [txPageNumber, setTxPageNumber] = useTransactionPageNumber(); - const txsPages = []; - for (let i = 0; i <= txPageNumber; i++) - txsPages.push(<Transactions accountLabel={accountLabel} pageNumber={i} />); + // const [txPageNumber, setTxPageNumber] = useTransactionPageNumber(); + // const txsPages = []; + // for (let i = 0; i <= txPageNumber; i++) { + // txsPages.push(<Transactions accountLabel={accountLabel} pageNumber={i} />); + // } if (typeof error !== "undefined") { console.log("account error", error, endpoint); @@ -143,10 +124,10 @@ function Account(Props: any): VNode { */ switch (error.status) { case 404: { + backend.clear(); setPageState((prevState: PageStateType) => ({ ...prevState, - isLoggedIn: false, error: { title: i18n.str`Username or account label '${accountLabel}' not found. Won't login.`, }, @@ -170,10 +151,9 @@ function Account(Props: any): VNode { } case HttpStatusCode.Unauthorized: case HttpStatusCode.Forbidden: { + backend.clear(); setPageState((prevState: PageStateType) => ({ ...prevState, - - isLoggedIn: false, error: { title: i18n.str`Wrong credentials given.`, }, @@ -181,10 +161,9 @@ function Account(Props: any): VNode { return <p>Wrong credentials...</p>; } default: { + backend.clear(); setPageState((prevState: PageStateType) => ({ ...prevState, - - isLoggedIn: false, error: { title: i18n.str`Account information could not be retrieved.`, debug: JSON.stringify(error), @@ -211,13 +190,11 @@ function Account(Props: any): VNode { * the outcome. */ console.log(`maybe new withdrawal ${talerWithdrawUri}`); - if (talerWithdrawUri) { + if (talerWithdrawUri && withdrawalId) { console.log("Bank created a new Taler withdrawal"); return ( <BankFrame> <TalerWithdrawalQRCode - accountLabel={accountLabel} - backendState={backendState} withdrawalId={withdrawalId} talerWithdrawUri={talerWithdrawUri} /> @@ -266,7 +243,7 @@ function Account(Props: any): VNode { <h2>{i18n.str`Latest transactions:`}</h2> <Transactions balanceValue={balanceValue} - pageNumber="0" + pageNumber={0} accountLabel={accountLabel} /> </article> diff --git a/packages/demobank-ui/src/pages/home/BankFrame.tsx b/packages/demobank-ui/src/pages/home/BankFrame.tsx index 3b099e34b..f6b8fbd96 100644 --- a/packages/demobank-ui/src/pages/home/BankFrame.tsx +++ b/packages/demobank-ui/src/pages/home/BankFrame.tsx @@ -14,15 +14,21 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Fragment, h, VNode } from "preact"; +import { ComponentChildren, Fragment, h, VNode } from "preact"; import talerLogo from "../../assets/logo-white.svg"; import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector.js"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; import { bankUiSettings } from "../../settings.js"; -export function BankFrame(Props: any): VNode { +export function BankFrame({ + children, +}: { + children: ComponentChildren; +}): VNode { const { i18n } = useTranslationContext(); + const backend = useBackendContext(); const { pageState, pageStateSetter } = usePageContext(); console.log("BankFrame state", pageState); const logOut = ( @@ -33,9 +39,9 @@ export function BankFrame(Props: any): VNode { onClick={() => { pageStateSetter((prevState: PageStateType) => { const { talerWithdrawUri, withdrawalId, ...rest } = prevState; + backend.clear(); return { ...rest, - isLoggedIn: false, withdrawalInProgress: false, error: undefined, info: undefined, @@ -98,10 +104,10 @@ export function BankFrame(Props: any): VNode { </nav> </div> <section id="main" class="content"> - <ErrorBanner pageState={[pageState, pageStateSetter]} /> - <StatusBanner pageState={[pageState, pageStateSetter]} /> - {pageState.isLoggedIn ? logOut : null} - {Props.children} + <ErrorBanner /> + <StatusBanner /> + {backend.state.status === "loggedIn" ? logOut : null} + {children} </section> <section id="footer" class="footer"> <div class="footer"> @@ -127,9 +133,9 @@ function maybeDemoContent(content: VNode): VNode { return <Fragment />; } -function ErrorBanner(Props: any): VNode | null { - const [pageState, pageStateSetter] = Props.pageState; - // const { i18n } = useTranslationContext(); +function ErrorBanner(): VNode | null { + const { pageState, pageStateSetter } = usePageContext(); + if (!pageState.error) return null; const rval = ( @@ -144,7 +150,7 @@ function ErrorBanner(Props: any): VNode | null { class="pure-button" value="Clear" onClick={async () => { - pageStateSetter((prev: any) => ({ ...prev, error: undefined })); + pageStateSetter((prev) => ({ ...prev, error: undefined })); }} /> </div> @@ -156,8 +162,8 @@ function ErrorBanner(Props: any): VNode | null { return rval; } -function StatusBanner(Props: any): VNode | null { - const [pageState, pageStateSetter] = Props.pageState; +function StatusBanner(): VNode | null { + const { pageState, pageStateSetter } = usePageContext(); if (!pageState.info) return null; const rval = ( @@ -172,7 +178,7 @@ function StatusBanner(Props: any): VNode | null { class="pure-button" value="Clear" onClick={async () => { - pageStateSetter((prev: any) => ({ ...prev, info: undefined })); + pageStateSetter((prev) => ({ ...prev, info: undefined })); }} /> </div> diff --git a/packages/demobank-ui/src/pages/home/LoginForm.tsx b/packages/demobank-ui/src/pages/home/LoginForm.tsx index f60c9f600..f31f91190 100644 --- a/packages/demobank-ui/src/pages/home/LoginForm.tsx +++ b/packages/demobank-ui/src/pages/home/LoginForm.tsx @@ -16,10 +16,10 @@ import { h, VNode } from "preact"; import { route } from "preact-router"; -import { StateUpdater, useEffect, useRef, useState } from "preact/hooks"; -import { PageStateType, usePageContext } from "../../context/pageState.js"; +import { useEffect, useRef, useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useTranslationContext } from "../../context/translation.js"; -import { BackendStateType, useBackendState } from "../../hooks/backend.js"; +import { BackendStateHandler } from "../../hooks/backend.js"; import { bankUiSettings } from "../../settings.js"; import { getBankBackendBaseUrl, undefinedIfEmpty } from "../../utils.js"; import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js"; @@ -28,8 +28,7 @@ import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js"; * Collect and submit login data. */ export function LoginForm(): VNode { - const [backendState, backendStateSetter] = useBackendState(); - const { pageState, pageStateSetter } = usePageContext(); + const backend = useBackendContext(); const [username, setUsername] = useState<string | undefined>(); const [password, setPassword] = useState<string | undefined>(); const { i18n } = useTranslationContext(); @@ -93,11 +92,7 @@ export function LoginForm(): VNode { disabled={!!errors} onClick={() => { if (!username || !password) return; - loginCall( - { username, password }, - backendStateSetter, - pageStateSetter, - ); + loginCall({ username, password }, backend); setUsername(undefined); setPassword(undefined); }} @@ -129,21 +124,16 @@ async function loginCall( * FIXME: figure out if the two following * functions can be retrieved from the state. */ - backendStateSetter: StateUpdater<BackendStateType | undefined>, - pageStateSetter: StateUpdater<PageStateType>, + backend: BackendStateHandler, ): Promise<void> { /** * Optimistically setting the state as 'logged in', and * let the Account component request the balance to check * whether the credentials are valid. */ - pageStateSetter((prevState) => ({ ...prevState, isLoggedIn: true })); - let baseUrl = getBankBackendBaseUrl(); - if (!baseUrl.endsWith("/")) baseUrl += "/"; - backendStateSetter((prevState) => ({ - ...prevState, - url: baseUrl, + backend.save({ + url: getBankBackendBaseUrl(), username: req.username, password: req.password, - })); + }); } diff --git a/packages/demobank-ui/src/pages/home/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/home/PaytoWireTransferForm.tsx index 45e7cf5ca..e4fe386ff 100644 --- a/packages/demobank-ui/src/pages/home/PaytoWireTransferForm.tsx +++ b/packages/demobank-ui/src/pages/home/PaytoWireTransferForm.tsx @@ -18,9 +18,10 @@ import { Amounts, parsePaytoUri } from "@gnu-taler/taler-util"; import { hooks } from "@gnu-taler/web-util/lib/index.browser"; import { h, VNode } from "preact"; import { StateUpdater, useEffect, useRef, useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; -import { BackendStateType, useBackendState } from "../../hooks/backend.js"; +import { BackendState } from "../../hooks/backend.js"; import { prepareHeaders, undefinedIfEmpty } from "../../utils.js"; import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js"; @@ -31,7 +32,7 @@ export function PaytoWireTransferForm({ focus?: boolean; currency?: string; }): VNode { - const [backendState, backendStateSetter] = useBackendState(); + const backend = useBackendContext(); const { pageState, pageStateSetter } = usePageContext(); // NOTE: used for go-back button? const [submitData, submitDataSetter] = useWireTransferRequestType(); @@ -81,7 +82,7 @@ export function PaytoWireTransferForm({ required pattern={ibanRegex} onInput={(e): void => { - submitDataSetter((submitData: any) => ({ + submitDataSetter((submitData) => ({ ...submitData, iban: e.currentTarget.value, })); @@ -102,7 +103,7 @@ export function PaytoWireTransferForm({ value={submitData?.subject ?? ""} required onInput={(e): void => { - submitDataSetter((submitData: any) => ({ + submitDataSetter((submitData) => ({ ...submitData, subject: e.currentTarget.value, })); @@ -133,7 +134,7 @@ export function PaytoWireTransferForm({ required value={submitData?.amount ?? ""} onInput={(e): void => { - submitDataSetter((submitData: any) => ({ + submitDataSetter((submitData) => ({ ...submitData, amount: e.currentTarget.value, })); @@ -179,7 +180,7 @@ export function PaytoWireTransferForm({ }; return await createTransactionCall( transactionData, - backendState, + backend.state, pageStateSetter, () => submitDataSetter((p) => ({ @@ -209,7 +210,7 @@ export function PaytoWireTransferForm({ href="/account" onClick={() => { console.log("switch to raw payto form"); - pageStateSetter((prevState: any) => ({ + pageStateSetter((prevState) => ({ ...prevState, isRawPayto: true, })); @@ -283,7 +284,7 @@ export function PaytoWireTransferForm({ return await createTransactionCall( transactionData, - backendState, + backend.state, pageStateSetter, () => rawPaytoInputSetter(undefined), ); @@ -295,7 +296,7 @@ export function PaytoWireTransferForm({ href="/account" onClick={() => { console.log("switch to wire-transfer-form"); - pageStateSetter((prevState: any) => ({ + pageStateSetter((prevState) => ({ ...prevState, isRawPayto: false, })); @@ -345,7 +346,7 @@ function useWireTransferRequestType( */ async function createTransactionCall( req: TransactionRequestType, - backendState: BackendStateType | undefined, + backendState: BackendState, pageStateSetter: StateUpdater<PageStateType>, /** * Optional since the raw payto form doesn't have @@ -353,13 +354,30 @@ async function createTransactionCall( */ cleanUpForm: () => void, ): Promise<void> { - let res: any; + if (backendState.status === "loggedOut") { + console.log("No credentials found."); + pageStateSetter((prevState) => ({ + ...prevState, + + error: { + title: "No credentials found.", + }, + })); + return; + } + let res: Response; try { - res = await postToBackend( - `access-api/accounts/${getUsername(backendState)}/transactions`, - backendState, - JSON.stringify(req), + const { username, password } = backendState; + const headers = prepareHeaders(username, password); + const url = new URL( + `access-api/accounts/${backendState.username}/transactions`, + backendState.url, ); + res = await fetch(url.href, { + method: "POST", + headers, + body: JSON.stringify(req), + }); } catch (error) { console.log("Could not POST transaction request to the bank", error); pageStateSetter((prevState) => ({ @@ -402,41 +420,3 @@ async function createTransactionCall( // be discarded. cleanUpForm(); } - -/** - * Get username from the backend state, and throw - * exception if not found. - */ -function getUsername(backendState: BackendStateType | undefined): string { - if (typeof backendState === "undefined") - 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; -} - -/** - * Helps extracting the credentials from the state - * and wraps the actual call to 'fetch'. Should be - * enclosed in a try-catch block by the caller. - */ -async function postToBackend( - uri: string, - backendState: BackendStateType | undefined, - body: string, -): Promise<any> { - if (typeof backendState === "undefined") - throw Error("Credentials can't be found in a undefined backend state."); - - const { username, password } = backendState; - const headers = prepareHeaders(username, password); - // Backend URL must have been stored _with_ a final slash. - const url = new URL(uri, backendState.url); - return await fetch(url.href, { - method: "POST", - headers, - body, - }); -} diff --git a/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx b/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx index 215dc7321..a8028f3bf 100644 --- a/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx +++ b/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx @@ -15,7 +15,7 @@ */ import { hooks } from "@gnu-taler/web-util/lib/index.browser"; -import { Fragment, h, VNode } from "preact"; +import { ComponentChildren, Fragment, h, VNode } from "preact"; import { route } from "preact-router"; import { StateUpdater } from "preact/hooks"; import useSWR, { SWRConfig } from "swr"; @@ -35,8 +35,13 @@ export function PublicHistoriesPage(): VNode { ); } -function SWRWithoutCredentials(Props: any): VNode { - const { baseUrl } = Props; +function SWRWithoutCredentials({ + baseUrl, + children, +}: { + children: ComponentChildren; + baseUrl: string; +}): VNode { console.log("Base URL", baseUrl); return ( <SWRConfig @@ -49,7 +54,7 @@ function SWRWithoutCredentials(Props: any): VNode { }), }} > - {Props.children} + {children as any} </SWRConfig> ); } @@ -93,7 +98,7 @@ function PublicHistories(): VNode { } } if (!data) return <p>Waiting public accounts list...</p>; - const txs: any = {}; + const txs: Record<string, h.JSX.Element> = {}; const accountsBar = []; /** diff --git a/packages/demobank-ui/src/pages/home/RegistrationPage.tsx b/packages/demobank-ui/src/pages/home/RegistrationPage.tsx index 9a120cb4f..08e9bd480 100644 --- a/packages/demobank-ui/src/pages/home/RegistrationPage.tsx +++ b/packages/demobank-ui/src/pages/home/RegistrationPage.tsx @@ -16,9 +16,10 @@ import { Fragment, h, VNode } from "preact"; import { route } from "preact-router"; import { StateUpdater, useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; -import { BackendStateType, useBackendState } from "../../hooks/backend.js"; +import { BackendStateHandler } from "../../hooks/backend.js"; import { bankUiSettings } from "../../settings.js"; import { getBankBackendBaseUrl, undefinedIfEmpty } from "../../utils.js"; import { BankFrame } from "./BankFrame.js"; @@ -44,7 +45,7 @@ export function RegistrationPage(): VNode { * Collect and submit registration data. */ function RegistrationForm(): VNode { - const [backendState, backendStateSetter] = useBackendState(); + const backend = useBackendContext(); const { pageState, pageStateSetter } = usePageContext(); const [username, setUsername] = useState<string | undefined>(); const [password, setPassword] = useState<string | undefined>(); @@ -132,7 +133,7 @@ function RegistrationForm(): VNode { if (!username || !password) return; registrationCall( { username, password }, - backendStateSetter, // will store BE URL, if OK. + backend, // will store BE URL, if OK. pageStateSetter, ); @@ -177,23 +178,17 @@ async function registrationCall( * functions can be retrieved somewhat from * the state. */ - backendStateSetter: StateUpdater<BackendStateType | undefined>, + backend: BackendStateHandler, pageStateSetter: StateUpdater<PageStateType>, ): Promise<void> { - let baseUrl = getBankBackendBaseUrl(); - /** - * If the base URL doesn't end with slash and the path - * is not empty, then the concatenation made by URL() - * drops the last path element. - */ - if (!baseUrl.endsWith("/")) baseUrl += "/"; + const url = getBankBackendBaseUrl(); const headers = new Headers(); headers.append("Content-Type", "application/json"); - const url = new URL("access-api/testing/register", baseUrl); + const registerEndpoint = new URL("access-api/testing/register", url); let res: Response; try { - res = await fetch(url.href, { + res = await fetch(registerEndpoint.href, { method: "POST", body: JSON.stringify({ username: req.username, @@ -203,7 +198,7 @@ async function registrationCall( }); } catch (error) { console.log( - `Could not POST new registration to the bank (${url.href})`, + `Could not POST new registration to the bank (${registerEndpoint.href})`, error, ); pageStateSetter((prevState) => ({ @@ -239,16 +234,11 @@ async function registrationCall( } } else { // registration was ok - pageStateSetter((prevState) => ({ - ...prevState, - isLoggedIn: true, - })); - backendStateSetter((prevState) => ({ - ...prevState, - url: baseUrl, + backend.save({ + url, username: req.username, password: req.password, - })); + }); route("/account"); } } diff --git a/packages/demobank-ui/src/pages/home/TalerWithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/home/TalerWithdrawalConfirmationQuestion.tsx index e3d8957b8..4fd46878b 100644 --- a/packages/demobank-ui/src/pages/home/TalerWithdrawalConfirmationQuestion.tsx +++ b/packages/demobank-ui/src/pages/home/TalerWithdrawalConfirmationQuestion.tsx @@ -1,17 +1,18 @@ import { Fragment, h, VNode } from "preact"; import { StateUpdater } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; -import { BackendStateType } from "../../hooks/backend.js"; +import { BackendState } from "../../hooks/backend.js"; import { prepareHeaders } from "../../utils.js"; /** * Additional authentication required to complete the operation. * Not providing a back button, only abort. */ -export function TalerWithdrawalConfirmationQuestion(Props: any): VNode { +export function TalerWithdrawalConfirmationQuestion(): VNode { const { pageState, pageStateSetter } = usePageContext(); - const { backendState } = Props; + const backend = useBackendContext(); const { i18n } = useTranslationContext(); const captchaNumbers = { a: Math.floor(Math.random() * 10), @@ -57,7 +58,7 @@ export function TalerWithdrawalConfirmationQuestion(Props: any): VNode { (captchaNumbers.a + captchaNumbers.b).toString() ) { confirmWithdrawalCall( - backendState, + backend.state, pageState.withdrawalId, pageStateSetter, ); @@ -79,7 +80,7 @@ export function TalerWithdrawalConfirmationQuestion(Props: any): VNode { class="pure-button pure-button-secondary btn-cancel" onClick={async () => await abortWithdrawalCall( - backendState, + backend.state, pageState.withdrawalId, pageStateSetter, ) @@ -116,11 +117,11 @@ export function TalerWithdrawalConfirmationQuestion(Props: any): VNode { * 'page state' and let the related components refresh. */ async function confirmWithdrawalCall( - backendState: BackendStateType | undefined, + backendState: BackendState, withdrawalId: string | undefined, pageStateSetter: StateUpdater<PageStateType>, ): Promise<void> { - if (typeof backendState === "undefined") { + if (backendState.status === "loggedOut") { console.log("No credentials found."); pageStateSetter((prevState) => ({ ...prevState, @@ -211,11 +212,11 @@ async function confirmWithdrawalCall( * Abort a withdrawal operation via the Access API's /abort. */ async function abortWithdrawalCall( - backendState: BackendStateType | undefined, + backendState: BackendState, withdrawalId: string | undefined, pageStateSetter: StateUpdater<PageStateType>, ): Promise<void> { - if (typeof backendState === "undefined") { + if (backendState.status === "loggedOut") { console.log("No credentials found."); pageStateSetter((prevState) => ({ ...prevState, @@ -237,7 +238,7 @@ async function abortWithdrawalCall( })); return; } - let res: any; + let res: Response; try { const { username, password } = backendState; const headers = prepareHeaders(username, password); diff --git a/packages/demobank-ui/src/pages/home/TalerWithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/home/TalerWithdrawalQRCode.tsx index da4ccc45e..848a9c45c 100644 --- a/packages/demobank-ui/src/pages/home/TalerWithdrawalQRCode.tsx +++ b/packages/demobank-ui/src/pages/home/TalerWithdrawalQRCode.tsx @@ -1,5 +1,6 @@ import { Fragment, h, VNode } from "preact"; import useSWR from "swr"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; import { QrCodeSection } from "./QrCodeSection.js"; @@ -10,10 +11,15 @@ import { TalerWithdrawalConfirmationQuestion } from "./TalerWithdrawalConfirmati * permit the passing of exchange and reserve details to * the bank. Poll the backend until such operation is done. */ -export function TalerWithdrawalQRCode(Props: any): VNode { +export function TalerWithdrawalQRCode({ + withdrawalId, + talerWithdrawUri, +}: { + withdrawalId: string; + talerWithdrawUri: string; +}): VNode { // turns true when the wallet POSTed the reserve details: const { pageState, pageStateSetter } = usePageContext(); - const { withdrawalId, talerWithdrawUri, backendState } = Props; const { i18n } = useTranslationContext(); const abortButton = ( <a @@ -93,5 +99,5 @@ export function TalerWithdrawalQRCode(Props: any): VNode { * Wallet POSTed the withdrawal details! Ask the * user to authorize the operation (here CAPTCHA). */ - return <TalerWithdrawalConfirmationQuestion backendState={backendState} />; + return <TalerWithdrawalConfirmationQuestion />; } diff --git a/packages/demobank-ui/src/pages/home/Transactions.tsx b/packages/demobank-ui/src/pages/home/Transactions.tsx index eb344403f..c0bb86024 100644 --- a/packages/demobank-ui/src/pages/home/Transactions.tsx +++ b/packages/demobank-ui/src/pages/home/Transactions.tsx @@ -10,14 +10,20 @@ export function Transactions({ pageNumber, accountLabel, balanceValue, -}: any): VNode { +}: { + pageNumber: number; + accountLabel: string; + balanceValue?: string; +}): VNode { const { i18n } = useTranslationContext(); const { data, error, mutate } = useSWR( `access-api/accounts/${accountLabel}/transactions?page=${pageNumber}`, ); useEffect(() => { - mutate(); - }, [balanceValue]); + if (balanceValue) { + mutate(); + } + }, [balanceValue ?? ""]); if (typeof error !== "undefined") { console.log("transactions not found error", error); switch (error.status) { diff --git a/packages/demobank-ui/src/pages/home/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/home/WalletWithdrawForm.tsx index 842f14a5f..ee43d2006 100644 --- a/packages/demobank-ui/src/pages/home/WalletWithdrawForm.tsx +++ b/packages/demobank-ui/src/pages/home/WalletWithdrawForm.tsx @@ -16,9 +16,10 @@ import { h, VNode } from "preact"; import { StateUpdater, useEffect, useRef } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; -import { BackendStateType, useBackendState } from "../../hooks/backend.js"; +import { BackendState } from "../../hooks/backend.js"; import { prepareHeaders, validateAmount } from "../../utils.js"; export function WalletWithdrawForm({ @@ -28,10 +29,10 @@ export function WalletWithdrawForm({ currency?: string; focus?: boolean; }): VNode { - const [backendState, backendStateSetter] = useBackendState(); + const backend = useBackendContext(); const { pageState, pageStateSetter } = usePageContext(); const { i18n } = useTranslationContext(); - let submitAmount = "5.00"; + let submitAmount: string | undefined = "5.00"; const ref = useRef<HTMLInputElement>(null); useEffect(() => { @@ -83,7 +84,7 @@ export function WalletWithdrawForm({ if (!submitAmount && currency) return; createWithdrawalCall( `${currency}:${submitAmount}`, - backendState, + backend.state, pageStateSetter, ); }} @@ -105,10 +106,10 @@ export function WalletWithdrawForm({ * the user about the operation's outcome. (2) use POST helper. */ async function createWithdrawalCall( amount: string, - backendState: BackendStateType | undefined, + backendState: BackendState, pageStateSetter: StateUpdater<PageStateType>, ): Promise<void> { - if (typeof backendState === "undefined") { + if (backendState?.status === "loggedOut") { console.log("Page has a problem: no credentials found in the state."); pageStateSetter((prevState) => ({ ...prevState, @@ -120,7 +121,7 @@ async function createWithdrawalCall( return; } - let res: any; + let res: Response; try { const { username, password } = backendState; const headers = prepareHeaders(username, password); |