diff options
author | Sebastian <sebasjm@gmail.com> | 2024-01-23 18:00:42 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-01-24 17:14:02 -0300 |
commit | 236d4347f5884bb1d9ca1d3bb4ad0ba776577fd2 (patch) | |
tree | a38823a73006c38bd54cb438da81f13bb513dce5 /packages/demobank-ui/src/components | |
parent | 579128ce40c7e56f390cadaf2fc2fd4cc6290d68 (diff) | |
download | wallet-core-236d4347f5884bb1d9ca1d3bb4ad0ba776577fd2.tar.xz |
many changes
activate eslint
update file headers
removed history and preact-router
remove eslint errors and more applied prettier
Diffstat (limited to 'packages/demobank-ui/src/components')
11 files changed, 399 insertions, 220 deletions
diff --git a/packages/demobank-ui/src/components/Cashouts/index.ts b/packages/demobank-ui/src/components/Cashouts/index.ts index 2ee9237f8..2c6bf681c 100644 --- a/packages/demobank-ui/src/components/Cashouts/index.ts +++ b/packages/demobank-ui/src/components/Cashouts/index.ts @@ -15,17 +15,28 @@ */ import { Loading, utils } from "@gnu-taler/web-util/browser"; -import { AbsoluteTime, AmountJson, TalerCoreBankErrorsByMethod, TalerCorebankApi, TalerError } from "@gnu-taler/taler-util"; +import { + AbsoluteTime, + AmountJson, + TalerCoreBankErrorsByMethod, + TalerCorebankApi, + TalerError, +} from "@gnu-taler/taler-util"; import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js"; import { useComponentState } from "./state.js"; import { FailedView, ReadyView } from "./views.js"; +import { RouteDefinition } from "../../route.js"; export interface Props { account: string; - onSelected: (id: number) => void; + routeCashoutDetails: RouteDefinition<{ cid: string }>; } -export type State = State.Loading | State.Failed | State.LoadingUriError | State.Ready; +export type State = + | State.Loading + | State.Failed + | State.LoadingUriError + | State.Ready; export namespace State { export interface Loading { @@ -50,7 +61,7 @@ export namespace State { status: "ready"; error: undefined; cashouts: (TalerCorebankApi.CashoutStatusResponse & { id: number })[]; - onSelected: (id: number) => void; + routeCashoutDetails: RouteDefinition<{ cid: string }>; } } @@ -65,7 +76,7 @@ export interface Transaction { const viewMapping: utils.StateViewMap<State> = { loading: Loading, "loading-error": ErrorLoadingWithDebug, - "failed": FailedView, + failed: FailedView, ready: ReadyView, }; diff --git a/packages/demobank-ui/src/components/Cashouts/state.ts b/packages/demobank-ui/src/components/Cashouts/state.ts index 0be7221b6..344b93e14 100644 --- a/packages/demobank-ui/src/components/Cashouts/state.ts +++ b/packages/demobank-ui/src/components/Cashouts/state.ts @@ -18,7 +18,10 @@ import { TalerError } from "@gnu-taler/taler-util"; import { useCashouts } from "../../hooks/circuit.js"; import { Props, State } from "./index.js"; -export function useComponentState({ account, onSelected }: Props): State { +export function useComponentState({ + account, + routeCashoutDetails, +}: Props): State { const result = useCashouts(account); if (!result) { return { @@ -35,14 +38,14 @@ export function useComponentState({ account, onSelected }: Props): State { if (result.type === "fail") { return { status: "failed", - error: result - } + error: result, + }; } return { status: "ready", error: undefined, cashouts: result.body.cashouts, - onSelected, + routeCashoutDetails, }; } diff --git a/packages/demobank-ui/src/components/Cashouts/test.ts b/packages/demobank-ui/src/components/Cashouts/test.ts index 031794b96..569cbc6f0 100644 --- a/packages/demobank-ui/src/components/Cashouts/test.ts +++ b/packages/demobank-ui/src/components/Cashouts/test.ts @@ -25,6 +25,7 @@ import { expect } from "chai"; import { CASHOUT_API_EXAMPLE } from "../../endpoints.js"; import { Props } from "./index.js"; import { useComponentState } from "./state.js"; +import { buildNullRoutDefinition } from "../../route.js"; describe("Cashout states", () => { it.skip("should query backend and render transactions", async () => { @@ -32,9 +33,7 @@ describe("Cashout states", () => { const props: Props = { account: "123", - onSelected: () => { - null; - }, + routeCashoutDetails: buildNullRoutDefinition(), }; env.addRequestExpectation(CASHOUT_API_EXAMPLE.LIST_FIRST_PAGE, { diff --git a/packages/demobank-ui/src/components/Cashouts/views.tsx b/packages/demobank-ui/src/components/Cashouts/views.tsx index d01187835..d036ec7d2 100644 --- a/packages/demobank-ui/src/components/Cashouts/views.tsx +++ b/packages/demobank-ui/src/components/Cashouts/views.tsx @@ -14,8 +14,17 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Amounts, HttpStatusCode, TalerError, assertUnreachable } from "@gnu-taler/taler-util"; -import { Attention, Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { + Amounts, + HttpStatusCode, + TalerError, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { + Attention, + Loading, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useConversionInfo } from "../../hooks/circuit.js"; @@ -26,87 +35,132 @@ import { State } from "./index.js"; export function FailedView({ error }: State.Failed) { const { i18n } = useTranslationContext(); switch (error.case) { - case HttpStatusCode.NotImplemented: return <Attention type="danger" - title={i18n.str`Cashout not supported.`}> - <div class="mt-2 text-sm text-red-700"> - {error.detail.hint} - </div> - </Attention> case HttpStatusCode.NotImplemented: { - return <Attention type="danger" title={i18n.str`Cashout not implemented`}> - </Attention>; + return ( + <Attention + type="danger" + title={i18n.str`Cashout not implemented`} + ></Attention> + ); } - default: assertUnreachable(error.case) + default: + assertUnreachable(error.case); } } -export function ReadyView({ cashouts, onSelected }: State.Ready): VNode { +export function ReadyView({ + cashouts, + routeCashoutDetails, +}: State.Ready): VNode { const { i18n, dateLocale } = useTranslationContext(); const resp = useConversionInfo(); if (!resp) { - return <Loading /> + return <Loading />; } if (resp instanceof TalerError) { - return <ErrorLoadingWithDebug error={resp} /> + return <ErrorLoadingWithDebug error={resp} />; } if (resp.type === "fail") { switch (resp.case) { case HttpStatusCode.NotImplemented: { - return <Attention type="danger" title={i18n.str`Cashout not implemented`}> - </Attention>; + return ( + <Attention + type="danger" + title={i18n.str`Cashout not implemented`} + ></Attention> + ); } - default: assertUnreachable(resp.case) + default: + assertUnreachable(resp.case); } } - if (!cashouts.length) return <div /> - const txByDate = cashouts.reduce((prev, cur) => { - const d = cur.creation_time.t_s === "never" - ? "" - : format(cur.creation_time.t_s * 1000, "dd/MM/yyyy", { locale: dateLocale }) - if (!prev[d]) { - prev[d] = [] - } - prev[d].push(cur) - return prev - }, {} as Record<string, typeof cashouts>) + if (!cashouts.length) return <div />; + const txByDate = cashouts.reduce( + (prev, cur) => { + const d = + cur.creation_time.t_s === "never" + ? "" + : format(cur.creation_time.t_s * 1000, "dd/MM/yyyy", { + locale: dateLocale, + }); + if (!prev[d]) { + prev[d] = []; + } + prev[d].push(cur); + return prev; + }, + {} as Record<string, typeof cashouts>, + ); return ( <div class="px-4 mt-4"> <div class="sm:flex sm:items-center"> <div class="sm:flex-auto"> - <h1 class="text-base font-semibold leading-6 text-gray-900"><i18n.Translate>Latest cashouts</i18n.Translate></h1> + <h1 class="text-base font-semibold leading-6 text-gray-900"> + <i18n.Translate>Latest cashouts</i18n.Translate> + </h1> </div> </div> <div class="-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white"> <table class="min-w-full divide-y divide-gray-300"> <thead> <tr> - <th scope="col" class=" pl-2 py-3.5 text-left text-sm font-semibold text-gray-900">{i18n.str`Created`}</th> - <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900">{i18n.str`Total debit`}</th> - <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900">{i18n.str`Total credit`}</th> - <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900">{i18n.str`Subject`}</th> + <th + scope="col" + class=" pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Created`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Total debit`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Total credit`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900" + >{i18n.str`Subject`}</th> </tr> </thead> <tbody> {Object.entries(txByDate).map(([date, txs], idx) => { - return <Fragment key={idx}> - <tr class="border-t border-gray-200"> - <th colSpan={6} scope="colgroup" class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3"> - {date} - </th> - </tr> - {txs.map(item => { - const creationTime = item.creation_time.t_s === "never" ? "" : format(item.creation_time.t_s * 1000, "HH:mm:ss", { locale: dateLocale }) - return (<tr key={idx} class="border-b border-gray-200 hover:bg-gray-200 last:border-none"> - - <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }} class="relative py-2 pl-2 pr-2 text-sm "> - <div class="font-medium text-gray-900">{creationTime}</div> - {//FIXME: implement responsive view - } - {/* <dl class="font-normal sm:hidden"> + return ( + <Fragment key={idx}> + <tr class="border-t border-gray-200"> + <th + colSpan={6} + scope="colgroup" + class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3" + > + {date} + </th> + </tr> + {txs.map((item) => { + const creationTime = + item.creation_time.t_s === "never" + ? "" + : format(item.creation_time.t_s * 1000, "HH:mm:ss", { + locale: dateLocale, + }); + return ( + <tr + key={idx} + class="border-b border-gray-200 hover:bg-gray-200 last:border-none" + > + <a + href={routeCashoutDetails.url({ + cid: String(item.id), + })} + > + <td class="relative py-2 pl-2 pr-2 text-sm "> + <div class="font-medium text-gray-900"> + {creationTime} + </div> + { + //FIXME: implement responsive view + } + {/* <dl class="font-normal sm:hidden"> <dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt> <dd class="mt-1 truncate text-gray-700"> {item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? ( @@ -127,34 +181,33 @@ export function ReadyView({ cashouts, onSelected }: State.Ready): VNode { </pre> </dd> </dl> */} - </td> - <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer"><RenderAmount value={Amounts.parseOrThrow(item.amount_debit)} spec={resp.body.regional_currency_specification} /></td> - <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-green-600 cursor-pointer"><RenderAmount value={Amounts.parseOrThrow(item.amount_credit)} spec={resp.body.fiat_currency_specification} /></td> - - <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md"> - {item.subject} - </td> - </tr>) - })} - </Fragment> + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer"> + <RenderAmount + value={Amounts.parseOrThrow(item.amount_debit)} + spec={resp.body.regional_currency_specification} + /> + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-green-600 cursor-pointer"> + <RenderAmount + value={Amounts.parseOrThrow(item.amount_credit)} + spec={resp.body.fiat_currency_specification} + /> + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md"> + {item.subject} + </td> + </a> + </tr> + ); + })} + </Fragment> + ); })} </tbody> - </table> - - </div> </div> ); - } diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/state.ts b/packages/demobank-ui/src/components/EmptyComponentExample/state.ts index c63f7d3ab..057664983 100644 --- a/packages/demobank-ui/src/components/EmptyComponentExample/state.ts +++ b/packages/demobank-ui/src/components/EmptyComponentExample/state.ts @@ -17,7 +17,7 @@ // import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; -export function useComponentState({ p }: Props): State { +export function useComponentState({ p: _p }: Props): State { return { status: "ready", error: undefined, diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx b/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx index c32e25b50..457933a5f 100644 --- a/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx +++ b/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx @@ -15,20 +15,11 @@ */ import { h, VNode } from "preact"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { State } from "./index.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - <div> - </div> - ); +export function LoadingUriView(): VNode { + return <div></div>; } -export function ReadyView({ error }: State.Ready): VNode { - const { i18n } = useTranslationContext(); - +export function ReadyView(): VNode { return <div />; } diff --git a/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx b/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx index 25e79e9e0..8679af050 100644 --- a/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx +++ b/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx @@ -1,3 +1,18 @@ +/* + This file is part of GNU Taler + (C) 2022-2024 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 { TalerError } from "@gnu-taler/taler-util"; import { ErrorLoading } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; @@ -5,5 +20,5 @@ import { usePreferences } from "../hooks/preferences.js"; export function ErrorLoadingWithDebug({ error }: { error: TalerError }): VNode { const [pref] = usePreferences(); - return <ErrorLoading error={error} showDetail={pref.showDebugInfo} /> + return <ErrorLoading error={error} showDetail={pref.showDebugInfo} />; } diff --git a/packages/demobank-ui/src/components/Transactions/state.ts b/packages/demobank-ui/src/components/Transactions/state.ts index 721fede45..56eaefb8d 100644 --- a/packages/demobank-ui/src/components/Transactions/state.ts +++ b/packages/demobank-ui/src/components/Transactions/state.ts @@ -14,7 +14,12 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AbsoluteTime, Amounts, TalerError, parsePaytoUri } from "@gnu-taler/taler-util"; +import { + AbsoluteTime, + Amounts, + TalerError, + parsePaytoUri, +} from "@gnu-taler/taler-util"; import { useTransactions } from "../../hooks/access.js"; import { Props, State, Transaction } from "./index.js"; @@ -33,29 +38,38 @@ export function useComponentState({ account }: Props): State { }; } - const transactions = result.data.type === "fail" ? [] : result.data.body.transactions - .map((tx) => { + const transactions = + result.data.type === "fail" + ? [] + : result.data.body.transactions + .map((tx) => { + const negative = tx.direction === "debit"; + const cp = parsePaytoUri( + negative ? tx.creditor_payto_uri : tx.debtor_payto_uri, + ); + const counterpart = + (cp === undefined || !cp.isKnown + ? undefined + : cp.targetType === "iban" + ? cp.iban + : cp.targetType === "x-taler-bank" + ? cp.account + : cp.targetType === "bitcoin" + ? `${cp.targetPath.substring(0, 6)}...` + : undefined) ?? "unkown"; - const negative = tx.direction === "debit"; - const cp = parsePaytoUri(negative ? tx.creditor_payto_uri : tx.debtor_payto_uri); - const counterpart = (cp === undefined || !cp.isKnown ? undefined : - cp.targetType === "iban" ? cp.iban : - cp.targetType === "x-taler-bank" ? cp.account : - cp.targetType === "bitcoin" ? `${cp.targetPath.substring(0, 6)}...` : undefined) ?? - "unkown"; - - const when = AbsoluteTime.fromProtocolTimestamp(tx.date); - const amount = Amounts.parse(tx.amount); - const subject = tx.subject; - return { - negative, - counterpart, - when, - amount, - subject, - }; - }) - .filter((x): x is Transaction => x !== undefined); + const when = AbsoluteTime.fromProtocolTimestamp(tx.date); + const amount = Amounts.parse(tx.amount); + const subject = tx.subject; + return { + negative, + counterpart, + when, + amount, + subject, + }; + }) + .filter((x): x is Transaction => x !== undefined); return { status: "ready", diff --git a/packages/demobank-ui/src/components/Transactions/test.ts b/packages/demobank-ui/src/components/Transactions/test.ts index 0b5e2bfbf..cf33a0b1c 100644 --- a/packages/demobank-ui/src/components/Transactions/test.ts +++ b/packages/demobank-ui/src/components/Transactions/test.ts @@ -19,14 +19,13 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { ErrorType } from "@gnu-taler/web-util/browser"; +import { TalerErrorCode } from "@gnu-taler/taler-util"; import * as tests from "@gnu-taler/web-util/testing"; import { SwrMockEnvironment } from "@gnu-taler/web-util/testing"; import { expect } from "chai"; import { TRANSACTION_API_EXAMPLE } from "../../endpoints.js"; import { Props } from "./index.js"; import { useComponentState } from "./state.js"; -import { HttpStatusCode, TalerError, TalerErrorCode } from "@gnu-taler/taler-util"; describe("Transaction states", () => { it.skip("should query backend and render transactions", async () => { @@ -36,7 +35,6 @@ describe("Transaction states", () => { account: "myAccount", }; - //@ts-ignore env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_FIRST_PAGE, { response: { data: { @@ -183,10 +181,15 @@ describe("Transaction states", () => { }, ({ status, error }) => { expect(status).equals("loading-error"); - if (error === undefined || !error.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED)) { + if ( + error === undefined || + !error.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED) + ) { throw Error("not the expected error"); } - expect(error.errorDetail.code).deep.equal(TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED); + expect(error.errorDetail.code).deep.equal( + TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, + ); }, ], env.buildTestingContext(), diff --git a/packages/demobank-ui/src/components/Transactions/views.tsx b/packages/demobank-ui/src/components/Transactions/views.tsx index 7b3c77fa2..1d63cc2cb 100644 --- a/packages/demobank-ui/src/components/Transactions/views.tsx +++ b/packages/demobank-ui/src/components/Transactions/views.tsx @@ -20,99 +20,179 @@ import { Fragment, h, VNode } from "preact"; import { useBankCoreApiContext } from "../../context/config.js"; import { RenderAmount } from "../../pages/PaytoWireTransferForm.js"; import { State } from "./index.js"; +import { privatePages } from "../../Routing.js"; - -export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode { +export function ReadyView({ + transactions, + onNext, + onPrev, +}: State.Ready): VNode { const { i18n, dateLocale } = useTranslationContext(); const { config } = useBankCoreApiContext(); - if (!transactions.length) return <div /> - const txByDate = transactions.reduce((prev, cur) => { - const d = cur.when.t_ms === "never" - ? "" - : format(cur.when.t_ms, "dd/MM/yyyy", { locale: dateLocale }) - if (!prev[d]) { - prev[d] = [] - } - prev[d].push(cur) - return prev - }, {} as Record<string, typeof transactions>) + if (!transactions.length) return <div />; + const txByDate = transactions.reduce( + (prev, cur) => { + const d = + cur.when.t_ms === "never" + ? "" + : format(cur.when.t_ms, "dd/MM/yyyy", { locale: dateLocale }); + if (!prev[d]) { + prev[d] = []; + } + prev[d].push(cur); + return prev; + }, + {} as Record<string, typeof transactions>, + ); return ( <div class="px-4 mt-4"> <div class="sm:flex sm:items-center"> <div class="sm:flex-auto"> - <h1 class="text-base font-semibold leading-6 text-gray-900"><i18n.Translate>Latest transactions</i18n.Translate></h1> + <h1 class="text-base font-semibold leading-6 text-gray-900"> + <i18n.Translate>Latest transactions</i18n.Translate> + </h1> </div> </div> <div class="-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white"> <table class="min-w-full divide-y divide-gray-300"> <thead> <tr> - <th scope="col" class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Date`}</th> - <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Amount`}</th> - <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Counterpart`}</th> - <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 ">{i18n.str`Subject`}</th> + <th + scope="col" + class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 " + >{i18n.str`Date`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 " + >{i18n.str`Amount`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 " + >{i18n.str`Counterpart`}</th> + <th + scope="col" + class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 " + >{i18n.str`Subject`}</th> </tr> </thead> <tbody> {Object.entries(txByDate).map(([date, txs], idx) => { - return <Fragment> - <tr class="border-t border-gray-200"> - <th colSpan={4} scope="colgroup" class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3"> - {date} - </th> - </tr> - {txs.map(item => { - const time = item.when.t_ms === "never" ? "" : format(item.when.t_ms, "HH:mm:ss", { locale: dateLocale }) - return (<tr key={idx} class="border-b border-gray-200 last:border-none"> - <td class="relative py-2 pl-2 pr-2 text-sm "> - <div class="font-medium text-gray-900">{time}</div> - <dl class="font-normal sm:hidden"> - <dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt> - <dd class="mt-1 truncate text-gray-700"> - {item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? ( - <span data-negative={item.negative ? "true" : "false"} class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"> - <RenderAmount value={item.amount} spec={config.currency_specification} /> - </span> - ) : ( - <span style={{ color: "grey" }}><{i18n.str`invalid value`}></span> - )}</dd> + return ( + <Fragment key={idx}> + <tr class="border-t border-gray-200"> + <th + colSpan={4} + scope="colgroup" + class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3" + > + {date} + </th> + </tr> + {txs.map((item) => { + const time = + item.when.t_ms === "never" + ? "" + : format(item.when.t_ms, "HH:mm:ss", { + locale: dateLocale, + }); + return ( + <tr + key={idx} + class="border-b border-gray-200 last:border-none" + > + <td class="relative py-2 pl-2 pr-2 text-sm "> + <div class="font-medium text-gray-900">{time}</div> + <dl class="font-normal sm:hidden"> + <dt class="sr-only sm:hidden"> + <i18n.Translate>Amount</i18n.Translate> + </dt> + <dd class="mt-1 truncate text-gray-700"> + {item.negative + ? i18n.str`sent` + : i18n.str`received`}{" "} + {item.amount ? ( + <span + data-negative={ + item.negative ? "true" : "false" + } + class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600" + > + <RenderAmount + value={item.amount} + spec={config.currency_specification} + /> + </span> + ) : ( + <span style={{ color: "grey" }}> + <{i18n.str`invalid value`}> + </span> + )} + </dd> - <dt class="sr-only sm:hidden"><i18n.Translate>Counterpart</i18n.Translate></dt> - <dd class="mt-1 truncate text-gray-500 sm:hidden"> - {item.negative ? i18n.str`to` : i18n.str`from`} <a href={`#/wire-transfer/${item.counterpart}`} class="text-indigo-600 hover:text-indigo-900"> + <dt class="sr-only sm:hidden"> + <i18n.Translate>Counterpart</i18n.Translate> + </dt> + <dd class="mt-1 truncate text-gray-500 sm:hidden"> + {item.negative ? i18n.str`to` : i18n.str`from`}{" "} + <a + href={privatePages.wireTranserCreate.url({ + destination: item.counterpart, + })} + class="text-indigo-600 hover:text-indigo-900" + > + {item.counterpart} + </a> + </dd> + <dd class="mt-1 text-gray-500 sm:hidden"> + <pre class="break-words w-56 whitespace-break-spaces p-2 rounded-md mx-auto my-2 bg-gray-100"> + {item.subject} + </pre> + </dd> + </dl> + </td> + <td + data-negative={item.negative ? "true" : "false"} + class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 " + > + {item.amount ? ( + <RenderAmount + value={item.amount} + negative={item.negative} + withColor + spec={config.currency_specification} + /> + ) : ( + <span style={{ color: "grey" }}> + <{i18n.str`invalid value`}> + </span> + )} + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500"> + <a + href={privatePages.wireTranserCreate.url({ + destination: item.counterpart, + })} + class="text-indigo-600 hover:text-indigo-900" + > {item.counterpart} </a> - </dd> - <dd class="mt-1 text-gray-500 sm:hidden" > - <pre class="break-words w-56 whitespace-break-spaces p-2 rounded-md mx-auto my-2 bg-gray-100"> - {item.subject} - </pre> - </dd> - </dl> - </td> - <td data-negative={item.negative ? "true" : "false"} - class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 "> - {item.amount ? (<RenderAmount value={item.amount} negative={item.negative} withColor spec={config.currency_specification} /> - ) : ( - <span style={{ color: "grey" }}><{i18n.str`invalid value`}></span> - )} - </td> - <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500"> - <a href={`#/wire-transfer/${item.counterpart}`} class="text-indigo-600 hover:text-indigo-900"> - {item.counterpart} - </a> - </td> - <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md">{item.subject}</td> - </tr>) - })} - </Fragment> - + </td> + <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md"> + {item.subject} + </td> + </tr> + ); + })} + </Fragment> + ); })} </tbody> - </table> - <nav class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg" aria-label="Pagination"> + <nav + class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg" + aria-label="Pagination" + > <div class="flex flex-1 justify-between sm:justify-end"> <button class="relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0" diff --git a/packages/demobank-ui/src/components/app.tsx b/packages/demobank-ui/src/components/app.tsx index 484813ea9..49508965b 100644 --- a/packages/demobank-ui/src/components/app.tsx +++ b/packages/demobank-ui/src/components/app.tsx @@ -17,32 +17,38 @@ import { canonicalizeBaseUrl, getGlobalLogLevel, - setGlobalLogLevelFromString + setGlobalLogLevelFromString, } from "@gnu-taler/taler-util"; import { Loading, TranslationProvider } from "@gnu-taler/web-util/browser"; -import { Fragment, FunctionalComponent, h } from "preact"; +import { FunctionalComponent, h } from "preact"; +import { useEffect, useState } from "preact/hooks"; import { SWRConfig } from "swr"; +import { Routing } from "../Routing.js"; import { BackendStateProvider } from "../context/backend.js"; import { BankCoreApiProvider } from "../context/config.js"; -import { strings, StringsType } from "../i18n/strings.js"; -import { BankUiSettings, fetchSettings } from "../settings.js"; -import { Routing } from "../Routing.js"; -import { BankFrame } from "../pages/BankFrame.js"; -import { useEffect, useState } from "preact/hooks"; import { SettingsProvider } from "../context/settings.js"; +import { strings } from "../i18n/strings.js"; +import { BankFrame } from "../pages/BankFrame.js"; +import { BankUiSettings, fetchSettings } from "../settings.js"; const WITH_LOCAL_STORAGE_CACHE = false; const App: FunctionalComponent = () => { - const [settings, setSettings] = useState<BankUiSettings>() + const [settings, setSettings] = useState<BankUiSettings>(); useEffect(() => { - fetchSettings(setSettings) - }, []) + fetchSettings(setSettings); + }, []); if (!settings) return <Loading />; const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL); return ( <SettingsProvider value={settings}> - <TranslationProvider source={strings} completness={{ "es": strings["es"].completeness, "de": strings["de"].completeness }}> + <TranslationProvider + source={strings} + completness={{ + es: strings["es"].completeness, + de: strings["de"].completeness, + }} + > <BackendStateProvider> <BankCoreApiProvider baseUrl={baseUrl} frameOnError={BankFrame}> <SWRConfig @@ -63,7 +69,7 @@ const App: FunctionalComponent = () => { refreshWhenHidden: false, refreshWhenOffline: false, - //ignore errors + // ignore errors shouldRetryOnError: false, errorRetryCount: 0, errorRetryInterval: undefined, @@ -76,13 +82,15 @@ const App: FunctionalComponent = () => { </SWRConfig> </BankCoreApiProvider> </BackendStateProvider> - </TranslationProvider > + </TranslationProvider> </SettingsProvider> ); }; -(window as any).setGlobalLogLevelFromString = setGlobalLogLevelFromString; -(window as any).getGlobalLevel = getGlobalLogLevel; +// @ts-expect-error creating a new property for window object +window.setGlobalLogLevelFromString = setGlobalLogLevelFromString; +// @ts-expect-error creating a new property for window object +window.getGlobalLevel = getGlobalLogLevel; function localStorageProvider(): Map<unknown, unknown> { const map = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]")); @@ -96,7 +104,9 @@ function localStorageProvider(): Map<unknown, unknown> { export default App; -function getInitialBackendBaseURL(backendFromSettings: string | undefined): string { +function getInitialBackendBaseURL( + backendFromSettings: string | undefined, +): string { const overrideUrl = typeof localStorage !== "undefined" ? localStorage.getItem("corebank-api-base-url") @@ -104,23 +114,23 @@ function getInitialBackendBaseURL(backendFromSettings: string | undefined): stri let result: string; if (!overrideUrl) { - //normal path + // normal path if (!backendFromSettings) { console.error( "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'", ); - result = window.origin + result = window.origin; } else { result = backendFromSettings; } } else { // testing/development path - result = overrideUrl + result = overrideUrl; } try { - return canonicalizeBaseUrl(result) + return canonicalizeBaseUrl(result); } catch (e) { - //fall back - return canonicalizeBaseUrl(window.origin) + // fall back + return canonicalizeBaseUrl(window.origin); } -}
\ No newline at end of file +} |