diff options
author | Sebastian <sebasjm@gmail.com> | 2022-12-07 11:22:21 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2022-12-07 16:08:16 -0300 |
commit | 5d5b63416bbbf8bfefe5ee8d5a5adfdc8c361e31 (patch) | |
tree | 95189d0f484abe5152fedc1ecdbb9b508cfffe60 | |
parent | 0fa3b8ddb93e2d0352da82a6f2b07304ea239c28 (diff) |
no-fix: moving out public histories page
-rw-r--r-- | packages/demobank-ui/src/pages/Routing.tsx | 7 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/home/BankFrame.tsx | 201 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx | 187 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/home/Transactions.tsx | 82 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/home/index.tsx | 421 |
5 files changed, 475 insertions, 423 deletions
diff --git a/packages/demobank-ui/src/pages/Routing.tsx b/packages/demobank-ui/src/pages/Routing.tsx index cfc6a4bd8..ed9bb2cb3 100644 --- a/packages/demobank-ui/src/pages/Routing.tsx +++ b/packages/demobank-ui/src/pages/Routing.tsx @@ -2,11 +2,8 @@ import { createHashHistory } from "history"; import { h, VNode } from "preact"; import Router, { route, Route } from "preact-router"; import { useEffect } from "preact/hooks"; -import { - AccountPage, - PublicHistoriesPage, - RegistrationPage, -} from "./home/index.js"; +import { AccountPage, RegistrationPage } from "./home/index.js"; +import { PublicHistoriesPage } from "./home/PublicHistoriesPage.js"; export function Routing(): VNode { const history = createHashHistory(); diff --git a/packages/demobank-ui/src/pages/home/BankFrame.tsx b/packages/demobank-ui/src/pages/home/BankFrame.tsx new file mode 100644 index 000000000..9b4bc4567 --- /dev/null +++ b/packages/demobank-ui/src/pages/home/BankFrame.tsx @@ -0,0 +1,201 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { Fragment, h, VNode } from "preact"; +import { PageStateType, usePageContext } from "../../context/pageState.js"; +import { useTranslationContext } from "../../context/translation.js"; +import { bankUiSettings } from "../../settings.js"; +import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector.js"; +import { StateUpdater } from "preact/hooks"; +import talerLogo from "../../assets/logo-white.svg"; + +export function BankFrame(Props: any): VNode { + const { i18n } = useTranslationContext(); + const { pageState, pageStateSetter } = usePageContext(); + console.log("BankFrame state", pageState); + const logOut = ( + <div class="logout"> + <a + href="#" + class="pure-button logout-button" + onClick={() => { + pageStateSetter((prevState: PageStateType) => { + const { talerWithdrawUri, withdrawalId, ...rest } = prevState; + return { + ...rest, + isLoggedIn: false, + withdrawalInProgress: false, + error: undefined, + info: undefined, + isRawPayto: false, + }; + }); + }} + >{i18n.str`Logout`}</a> + </div> + ); + + const demo_sites = []; + for (const i in bankUiSettings.demoSites) + demo_sites.push( + <a href={bankUiSettings.demoSites[i][1]}> + {bankUiSettings.demoSites[i][0]} + </a>, + ); + + return ( + <Fragment> + <header + class="demobar" + style="display: flex; flex-direction: row; justify-content: space-between;" + > + <a href="#main" class="skip">{i18n.str`Skip to main content`}</a> + <div style="max-width: 50em; margin-left: 2em;"> + <h1> + <span class="it"> + <a href="/">{bankUiSettings.bankName}</a> + </span> + </h1> + {maybeDemoContent( + <p> + <i18n.Translate> + This part of the demo shows how a bank that supports Taler + directly would work. In addition to using your own bank account, + you can also see the transaction history of some{" "} + <a + href="/public-accounts" + onClick={goPublicAccounts(pageStateSetter)} + > + Public Accounts + </a> + . + </i18n.Translate> + </p>, + )} + </div> + <a href="https://taler.net/"> + <img + src={talerLogo} + alt={i18n.str`Taler logo`} + height="100" + width="224" + style="margin: 2em 2em" + /> + </a> + </header> + <div style="display:flex; flex-direction: column;" class="navcontainer"> + <nav class="demolist"> + {maybeDemoContent(<Fragment>{demo_sites}</Fragment>)} + <div class="right"> + <LangSelector /> + </div> + </nav> + </div> + <section id="main" class="content"> + <ErrorBanner pageState={[pageState, pageStateSetter]} /> + <StatusBanner pageState={[pageState, pageStateSetter]} /> + {pageState.isLoggedIn ? logOut : null} + {Props.children} + </section> + <section id="footer" class="footer"> + <div class="footer"> + <hr /> + <div> + <p> + You can learn more about GNU Taler on our{" "} + <a href="https://taler.net">main website</a>. + </p> + </div> + <div style="flex-grow:1" /> + <p>Copyright © 2014—2022 Taler Systems SA</p> + </div> + </section> + </Fragment> + ); +} + +function maybeDemoContent(content: VNode): VNode { + if (bankUiSettings.showDemoNav) { + return content; + } + return <Fragment />; +} + +/** + * Bring the state to show the public accounts page. + */ +function goPublicAccounts(pageStateSetter: StateUpdater<PageStateType>) { + return () => + pageStateSetter((prevState) => ({ + ...prevState, + showPublicHistories: true, + })); +} + +function ErrorBanner(Props: any): VNode | null { + const [pageState, pageStateSetter] = Props.pageState; + // const { i18n } = useTranslationContext(); + if (!pageState.error) return null; + + const rval = ( + <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: any) => ({ ...prev, error: undefined })); + }} + /> + </div> + </div> + <p>{pageState.error.description}</p> + </div> + ); + delete pageState.error; + return rval; +} + +function StatusBanner(Props: any): VNode | null { + const [pageState, pageStateSetter] = Props.pageState; + if (!pageState.info) return null; + + const rval = ( + <div class="informational informational-ok" style={{ marginTop: 8 }}> + <div style={{ display: "flex", justifyContent: "space-between" }}> + <p> + <b>{pageState.info}</b> + </p> + <div> + <input + type="button" + class="pure-button" + value="Clear" + onClick={async () => { + pageStateSetter((prev: any) => ({ ...prev, info: undefined })); + }} + /> + </div> + </div> + </div> + ); + return rval; +} diff --git a/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx b/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx new file mode 100644 index 000000000..216808e5c --- /dev/null +++ b/packages/demobank-ui/src/pages/home/PublicHistoriesPage.tsx @@ -0,0 +1,187 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { hooks } from "@gnu-taler/web-util/lib/index.browser"; +import { Fragment, h, VNode } from "preact"; +import { StateUpdater } from "preact/hooks"; +import useSWR, { SWRConfig } from "swr"; +import { PageStateType, usePageContext } from "../../context/pageState.js"; +import { useTranslationContext } from "../../context/translation.js"; +import { getBankBackendBaseUrl } from "../../utils.js"; +import { BankFrame } from "./BankFrame.js"; +import { Transactions } from "./Transactions.js"; + +export function PublicHistoriesPage(): VNode { + const { pageState, pageStateSetter } = usePageContext(); + // const { i18n } = useTranslationContext(); + return ( + <SWRWithoutCredentials baseUrl={getBankBackendBaseUrl()}> + <BankFrame> + <PublicHistories pageStateSetter={pageStateSetter}> + <br /> + <a + class="pure-button" + onClick={() => { + pageStateSetter((prevState: PageStateType) => ({ + ...prevState, + showPublicHistories: false, + })); + }} + > + Go back + </a> + </PublicHistories> + </BankFrame> + </SWRWithoutCredentials> + ); +} + +function SWRWithoutCredentials(Props: any): VNode { + const { baseUrl } = Props; + console.log("Base URL", baseUrl); + return ( + <SWRConfig + value={{ + fetcher: (url: string) => + fetch(baseUrl + url || "").then((r) => { + if (!r.ok) throw { status: r.status, json: r.json() }; + + return r.json(); + }), + }} + > + {Props.children} + </SWRConfig> + ); +} + +/** + * Show histories of public accounts. + */ +function PublicHistories(Props: any): VNode { + const [showAccount, setShowAccount] = useShowPublicAccount(); + const { data, error } = useSWR("access-api/public-accounts"); + const { i18n } = useTranslationContext(); + + if (typeof error !== "undefined") { + console.log("account error", error); + switch (error.status) { + case 404: + console.log("public accounts: 404", error); + Props.pageStateSetter((prevState: PageStateType) => ({ + ...prevState, + + showPublicHistories: false, + error: { + title: i18n.str`List of public accounts was not found.`, + debug: JSON.stringify(error), + }, + })); + break; + default: + console.log("public accounts: non-404 error", error); + Props.pageStateSetter((prevState: PageStateType) => ({ + ...prevState, + + showPublicHistories: false, + error: { + title: i18n.str`List of public accounts could not be retrieved.`, + debug: JSON.stringify(error), + }, + })); + break; + } + } + if (!data) return <p>Waiting public accounts list...</p>; + const txs: any = {}; + const accountsBar = []; + + /** + * Show the account specified in the props, or just one + * from the list if that's not given. + */ + if (typeof showAccount === "undefined" && data.publicAccounts.length > 0) + setShowAccount(data.publicAccounts[1].accountLabel); + console.log(`Public history tab: ${showAccount}`); + + // Ask story of all the public accounts. + for (const account of data.publicAccounts) { + console.log("Asking transactions for", account.accountLabel); + const isSelected = account.accountLabel == showAccount; + accountsBar.push( + <li + class={ + isSelected + ? "pure-menu-selected pure-menu-item" + : "pure-menu-item pure-menu" + } + > + <a + href="#" + class="pure-menu-link" + onClick={() => setShowAccount(account.accountLabel)} + > + {account.accountLabel} + </a> + </li>, + ); + txs[account.accountLabel] = ( + <Transactions accountLabel={account.accountLabel} pageNumber={0} /> + ); + } + + return ( + <Fragment> + <h1 class="nav">{i18n.str`History of public accounts`}</h1> + <section id="main"> + <article> + <div class="pure-menu pure-menu-horizontal" name="accountMenu"> + <ul class="pure-menu-list">{accountsBar}</ul> + {typeof showAccount !== "undefined" ? ( + txs[showAccount] + ) : ( + <p>No public transactions found.</p> + )} + {Props.children} + </div> + </article> + </section> + </Fragment> + ); +} + +/** + * Stores in the state a object containing a 'username' + * and 'password' field, in order to avoid losing the + * handle of the data entered by the user in <input> fields. + */ +function useShowPublicAccount( + state?: string, +): [string | undefined, StateUpdater<string | undefined>] { + const ret = hooks.useLocalStorage( + "show-public-account", + JSON.stringify(state), + ); + const retObj: string | undefined = ret[0] ? JSON.parse(ret[0]) : ret[0]; + const retSetter: StateUpdater<string | undefined> = function (val) { + const newVal = + val instanceof Function + ? JSON.stringify(val(retObj)) + : JSON.stringify(val); + ret[1](newVal); + }; + return [retObj, retSetter]; +} diff --git a/packages/demobank-ui/src/pages/home/Transactions.tsx b/packages/demobank-ui/src/pages/home/Transactions.tsx new file mode 100644 index 000000000..eb344403f --- /dev/null +++ b/packages/demobank-ui/src/pages/home/Transactions.tsx @@ -0,0 +1,82 @@ +import { h, VNode } from "preact"; +import { useEffect } from "preact/hooks"; +import useSWR from "swr"; +import { useTranslationContext } from "../../context/translation.js"; + +/** + * Show one page of transactions. + */ +export function Transactions({ + pageNumber, + accountLabel, + balanceValue, +}: any): VNode { + const { i18n } = useTranslationContext(); + const { data, error, mutate } = useSWR( + `access-api/accounts/${accountLabel}/transactions?page=${pageNumber}`, + ); + useEffect(() => { + mutate(); + }, [balanceValue]); + if (typeof error !== "undefined") { + console.log("transactions not found error", error); + switch (error.status) { + case 404: { + return <p>Transactions page {pageNumber} was not found.</p>; + } + case 401: { + return <p>Wrong credentials given.</p>; + } + default: { + return <p>Transaction page {pageNumber} could not be retrieved.</p>; + } + } + } + if (!data) { + console.log(`History data of ${accountLabel} not arrived`); + return <p>Transactions page loading...</p>; + } + console.log(`History data of ${accountLabel}`, data); + return ( + <div class="results"> + <table class="pure-table pure-table-striped"> + <thead> + <tr> + <th>{i18n.str`Date`}</th> + <th>{i18n.str`Amount`}</th> + <th>{i18n.str`Counterpart`}</th> + <th>{i18n.str`Subject`}</th> + </tr> + </thead> + <tbody> + {data.transactions.map((item: any, idx: number) => { + const sign = item.direction == "DBIT" ? "-" : ""; + const counterpart = + item.direction == "DBIT" ? item.creditorIban : item.debtorIban; + // Pattern: + // + // DD/MM YYYY subject -5 EUR + // DD/MM YYYY subject 5 EUR + const dateRegex = /^([0-9]{4})-([0-9]{2})-([0-9]{1,2})/; + const dateParse = dateRegex.exec(item.date); + const date = + dateParse !== null + ? `${dateParse[3]}/${dateParse[2]} ${dateParse[1]}` + : "date not found"; + return ( + <tr key={idx}> + <td>{date}</td> + <td> + {sign} + {item.amount} {item.currency} + </td> + <td>{counterpart}</td> + <td>{item.subject}</td> + </tr> + ); + })} + </tbody> + </table> + </div> + ); +} diff --git a/packages/demobank-ui/src/pages/home/index.tsx b/packages/demobank-ui/src/pages/home/index.tsx index 64ceedf66..e05ace2e0 100644 --- a/packages/demobank-ui/src/pages/home/index.tsx +++ b/packages/demobank-ui/src/pages/home/index.tsx @@ -20,11 +20,8 @@ import useSWR, { SWRConfig, useSWRConfig } from "swr"; import { Amounts, HttpStatusCode, parsePaytoUri } from "@gnu-taler/taler-util"; import { hooks } from "@gnu-taler/web-util/lib/index.browser"; -import { createHashHistory } from "history"; -import Router, { Route, route } from "preact-router"; +import { route } from "preact-router"; import { StateUpdater, useEffect, useRef, useState } from "preact/hooks"; -import talerLogo from "../../assets/logo-white.svg"; -import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector.js"; import { PageStateType, usePageContext } from "../../context/pageState.js"; import { useTranslationContext } from "../../context/translation.js"; import { BackendStateType, useBackendState } from "../../hooks/backend.js"; @@ -35,6 +32,8 @@ import { getIbanFromPayto, validateAmount, } from "../../utils.js"; +import { BankFrame } from "./BankFrame.js"; +import { Transactions } from "./Transactions.js"; /** * FIXME: @@ -57,24 +56,6 @@ import { * Helpers. * ***********/ -function maybeDemoContent(content: VNode): VNode { - if (bankUiSettings.showDemoNav) { - return content; - } - return <Fragment />; -} - -/** - * Bring the state to show the public accounts page. - */ -function goPublicAccounts(pageStateSetter: StateUpdater<PageStateType>) { - return () => - pageStateSetter((prevState) => ({ - ...prevState, - showPublicHistories: true, - })); -} - /** * Get username from the backend state, and throw * exception if not found. @@ -146,29 +127,6 @@ function prepareHeaders(username?: string, password?: string): Headers { ******************/ /** - * Stores in the state a object containing a 'username' - * and 'password' field, in order to avoid losing the - * handle of the data entered by the user in <input> fields. - */ -function useShowPublicAccount( - state?: string, -): [string | undefined, StateUpdater<string | undefined>] { - const ret = hooks.useLocalStorage( - "show-public-account", - JSON.stringify(state), - ); - const retObj: string | undefined = ret[0] ? JSON.parse(ret[0]) : ret[0]; - const retSetter: StateUpdater<string | undefined> = function (val) { - const newVal = - val instanceof Function - ? JSON.stringify(val(retObj)) - : JSON.stringify(val); - ret[1](newVal); - }; - return [retObj, retSetter]; -} - -/** * Stores the raw Payto value entered by the user in the state. */ type RawPaytoInputType = string; @@ -689,165 +647,6 @@ async function registrationCall( * Functional components. * *************************/ -function ErrorBanner(Props: any): VNode | null { - const [pageState, pageStateSetter] = Props.pageState; - // const { i18n } = useTranslationContext(); - if (!pageState.error) return null; - - const rval = ( - <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: any) => ({ ...prev, error: undefined })); - }} - /> - </div> - </div> - <p>{pageState.error.description}</p> - </div> - ); - delete pageState.error; - return rval; -} - -function StatusBanner(Props: any): VNode | null { - const [pageState, pageStateSetter] = Props.pageState; - if (!pageState.info) return null; - - const rval = ( - <div class="informational informational-ok" style={{ marginTop: 8 }}> - <div style={{ display: "flex", justifyContent: "space-between" }}> - <p> - <b>{pageState.info}</b> - </p> - <div> - <input - type="button" - class="pure-button" - value="Clear" - onClick={async () => { - pageStateSetter((prev: any) => ({ ...prev, info: undefined })); - }} - /> - </div> - </div> - </div> - ); - return rval; -} - -function BankFrame(Props: any): VNode { - const { i18n } = useTranslationContext(); - const { pageState, pageStateSetter } = usePageContext(); - console.log("BankFrame state", pageState); - const logOut = ( - <div class="logout"> - <a - href="#" - class="pure-button logout-button" - onClick={() => { - pageStateSetter((prevState: PageStateType) => { - const { talerWithdrawUri, withdrawalId, ...rest } = prevState; - return { - ...rest, - isLoggedIn: false, - withdrawalInProgress: false, - error: undefined, - info: undefined, - isRawPayto: false, - }; - }); - }} - >{i18n.str`Logout`}</a> - </div> - ); - - const demo_sites = []; - for (const i in bankUiSettings.demoSites) - demo_sites.push( - <a href={bankUiSettings.demoSites[i][1]}> - {bankUiSettings.demoSites[i][0]} - </a>, - ); - - return ( - <Fragment> - <header - class="demobar" - style="display: flex; flex-direction: row; justify-content: space-between;" - > - <a href="#main" class="skip">{i18n.str`Skip to main content`}</a> - <div style="max-width: 50em; margin-left: 2em;"> - <h1> - <span class="it"> - <a href="/">{bankUiSettings.bankName}</a> - </span> - </h1> - {maybeDemoContent( - <p> - <i18n.Translate> - This part of the demo shows how a bank that supports Taler - directly would work. In addition to using your own bank account, - you can also see the transaction history of some{" "} - <a - href="/public-accounts" - onClick={goPublicAccounts(pageStateSetter)} - > - Public Accounts - </a> - . - </i18n.Translate> - </p>, - )} - </div> - <a href="https://taler.net/"> - <img - src={talerLogo} - alt={i18n.str`Taler logo`} - height="100" - width="224" - style="margin: 2em 2em" - /> - </a> - </header> - <div style="display:flex; flex-direction: column;" class="navcontainer"> - <nav class="demolist"> - {maybeDemoContent(<Fragment>{demo_sites}</Fragment>)} - <div class="right"> - <LangSelector /> - </div> - </nav> - </div> - <section id="main" class="content"> - <ErrorBanner pageState={[pageState, pageStateSetter]} /> - <StatusBanner pageState={[pageState, pageStateSetter]} /> - {pageState.isLoggedIn ? logOut : null} - {Props.children} - </section> - <section id="footer" class="footer"> - <div class="footer"> - <hr /> - <div> - <p> - You can learn more about GNU Taler on our{" "} - <a href="https://taler.net">main website</a>. - </p> - </div> - <div style="flex-grow:1" /> - <p>Copyright © 2014—2022 Taler Systems SA</p> - </div> - </section> - </Fragment> - ); -} function ShowInputErrorLabel({ isDirty, message, @@ -1686,81 +1485,6 @@ function RegistrationForm(): VNode { } /** - * Show one page of transactions. - */ -function Transactions(Props: any): VNode { - const { pageNumber, accountLabel, balanceValue } = Props; - const { i18n } = useTranslationContext(); - const { data, error, mutate } = useSWR( - `access-api/accounts/${accountLabel}/transactions?page=${pageNumber}`, - ); - useEffect(() => { - mutate(); - }, [balanceValue]); - if (typeof error !== "undefined") { - console.log("transactions not found error", error); - switch (error.status) { - case 404: { - return <p>Transactions page {pageNumber} was not found.</p>; - } - case 401: { - return <p>Wrong credentials given.</p>; - } - default: { - return <p>Transaction page {pageNumber} could not be retrieved.</p>; - } - } - } - if (!data) { - console.log(`History data of ${accountLabel} not arrived`); - return <p>Transactions page loading...</p>; - } - console.log(`History data of ${accountLabel}`, data); - return ( - <div class="results"> - <table class="pure-table pure-table-striped"> - <thead> - <tr> - <th>{i18n.str`Date`}</th> - <th>{i18n.str`Amount`}</th> - <th>{i18n.str`Counterpart`}</th> - <th>{i18n.str`Subject`}</th> - </tr> - </thead> - <tbody> - {data.transactions.map((item: any, idx: number) => { - const sign = item.direction == "DBIT" ? "-" : ""; - const counterpart = - item.direction == "DBIT" ? item.creditorIban : item.debtorIban; - // Pattern: - // - // DD/MM YYYY subject -5 EUR - // DD/MM YYYY subject 5 EUR - const dateRegex = /^([0-9]{4})-([0-9]{2})-([0-9]{1,2})/; - const dateParse = dateRegex.exec(item.date); - const date = - dateParse !== null - ? `${dateParse[3]}/${dateParse[2]} ${dateParse[1]}` - : "date not found"; - return ( - <tr key={idx}> - <td>{date}</td> - <td> - {sign} - {item.amount} {item.currency} - </td> - <td>{counterpart}</td> - <td>{item.subject}</td> - </tr> - ); - })} - </tbody> - </table> - </div> - ); -} - -/** * Show only the account's balance. NOTE: the backend state * is mostly needed to provide the user's credentials to POST * to the bank. @@ -1965,145 +1689,6 @@ function SWRWithCredentials(props: any): VNode { ); } -function SWRWithoutCredentials(Props: any): VNode { - const { baseUrl } = Props; - console.log("Base URL", baseUrl); - return ( - <SWRConfig - value={{ - fetcher: (url: string) => - fetch(baseUrl + url || "").then((r) => { - if (!r.ok) throw { status: r.status, json: r.json() }; - - return r.json(); - }), - }} - > - {Props.children} - </SWRConfig> - ); -} - -/** - * Show histories of public accounts. - */ -function PublicHistories(Props: any): VNode { - const [showAccount, setShowAccount] = useShowPublicAccount(); - const { data, error } = useSWR("access-api/public-accounts"); - const { i18n } = useTranslationContext(); - - if (typeof error !== "undefined") { - console.log("account error", error); - switch (error.status) { - case 404: - console.log("public accounts: 404", error); - Props.pageStateSetter((prevState: PageStateType) => ({ - ...prevState, - - showPublicHistories: false, - error: { - title: i18n.str`List of public accounts was not found.`, - debug: JSON.stringify(error), - }, - })); - break; - default: - console.log("public accounts: non-404 error", error); - Props.pageStateSetter((prevState: PageStateType) => ({ - ...prevState, - - showPublicHistories: false, - error: { - title: i18n.str`List of public accounts could not be retrieved.`, - debug: JSON.stringify(error), - }, - })); - break; - } - } - if (!data) return <p>Waiting public accounts list...</p>; - const txs: any = {}; - const accountsBar = []; - - /** - * Show the account specified in the props, or just one - * from the list if that's not given. - */ - if (typeof showAccount === "undefined" && data.publicAccounts.length > 0) - setShowAccount(data.publicAccounts[1].accountLabel); - console.log(`Public history tab: ${showAccount}`); - - // Ask story of all the public accounts. - for (const account of data.publicAccounts) { - console.log("Asking transactions for", account.accountLabel); - const isSelected = account.accountLabel == showAccount; - accountsBar.push( - <li - class={ - isSelected - ? "pure-menu-selected pure-menu-item" - : "pure-menu-item pure-menu" - } - > - <a - href="#" - class="pure-menu-link" - onClick={() => setShowAccount(account.accountLabel)} - > - {account.accountLabel} - </a> - </li>, - ); - txs[account.accountLabel] = ( - <Transactions accountLabel={account.accountLabel} pageNumber={0} /> - ); - } - - return ( - <Fragment> - <h1 class="nav">{i18n.str`History of public accounts`}</h1> - <section id="main"> - <article> - <div class="pure-menu pure-menu-horizontal" name="accountMenu"> - <ul class="pure-menu-list">{accountsBar}</ul> - {typeof showAccount !== "undefined" ? ( - txs[showAccount] - ) : ( - <p>No public transactions found.</p> - )} - {Props.children} - </div> - </article> - </section> - </Fragment> - ); -} - -export function PublicHistoriesPage(): VNode { - const { pageState, pageStateSetter } = usePageContext(); - // const { i18n } = useTranslationContext(); - return ( - <SWRWithoutCredentials baseUrl={getBankBackendBaseUrl()}> - <BankFrame> - <PublicHistories pageStateSetter={pageStateSetter}> - <br /> - <a - class="pure-button" - onClick={() => { - pageStateSetter((prevState: PageStateType) => ({ - ...prevState, - showPublicHistories: false, - })); - }} - > - Go back - </a> - </PublicHistories> - </BankFrame> - </SWRWithoutCredentials> - ); -} - export function RegistrationPage(): VNode { const { i18n } = useTranslationContext(); if (!bankUiSettings.allowRegistrations) { |