diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/AccountPage')
5 files changed, 338 insertions, 0 deletions
diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts new file mode 100644 index 000000000..9230fb6b1 --- /dev/null +++ b/packages/demobank-ui/src/pages/AccountPage/index.ts @@ -0,0 +1,92 @@ +/* + 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 { HttpError, HttpResponseOk, HttpResponsePaginated, utils } from "@gnu-taler/web-util/browser"; +import { AbsoluteTime, AmountJson, PaytoUriIBAN, PaytoUriTalerBank } from "@gnu-taler/taler-util"; +import { Loading } from "../../components/Loading.js"; +import { useComponentState } from "./state.js"; +import { ReadyView, InvalidIbanView } from "./views.js"; +import { VNode } from "preact"; +import { LoginForm } from "../LoginForm.js"; +import { ErrorLoading } from "../../components/ErrorLoading.js"; + +export interface Props { + account: string; + onLoadNotOk: <T>( + error: HttpResponsePaginated<T, SandboxBackend.SandboxError>, + ) => VNode; + goToBusinessAccount: () => void; + goToConfirmOperation: (id: string) => void; +} + +export type State = State.Loading | State.LoadingError | State.Ready | State.InvalidIban | State.UserNotFound; + +export namespace State { + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface LoadingError { + status: "loading-error"; + error: HttpError<SandboxBackend.SandboxError>; + } + + export interface BaseInfo { + error: undefined; + } + + export interface Ready extends BaseInfo { + status: "ready"; + error: undefined; + account: string, + limit: AmountJson, + goToBusinessAccount: () => void; + goToConfirmOperation: (id: string) => void; + } + + export interface InvalidIban { + status: "invalid-iban", + error: HttpResponseOk<SandboxBackend.CoreBank.AccountData>; + } + + export interface UserNotFound { + status: "error-user-not-found", + error: HttpError<any>; + onRegister?: () => void; + } +} + +export interface Transaction { + negative: boolean; + counterpart: string; + when: AbsoluteTime; + amount: AmountJson | undefined; + subject: string; +} + +const viewMapping: utils.StateViewMap<State> = { + loading: Loading, + "error-user-not-found": LoginForm, + "invalid-iban": InvalidIbanView, + "loading-error": ErrorLoading, + ready: ReadyView, +}; + +export const AccountPage = utils.compose( + (p: Props) => useComponentState(p), + viewMapping, +); diff --git a/packages/demobank-ui/src/pages/AccountPage/state.ts b/packages/demobank-ui/src/pages/AccountPage/state.ts new file mode 100644 index 000000000..ca7e1d447 --- /dev/null +++ b/packages/demobank-ui/src/pages/AccountPage/state.ts @@ -0,0 +1,92 @@ +/* + 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 { Amounts, HttpStatusCode, parsePaytoUri } from "@gnu-taler/taler-util"; +import { ErrorType, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useBackendContext } from "../../context/backend.js"; +import { useAccountDetails } from "../../hooks/access.js"; +import { Props, State } from "./index.js"; + +export function useComponentState({ account, goToBusinessAccount, goToConfirmOperation }: Props): State { + const result = useAccountDetails(account); + const backend = useBackendContext(); + const { i18n } = useTranslationContext(); + + if (result.loading) { + return { + status: "loading", + error: undefined, + }; + } + + if (!result.ok) { + if (result.loading || result.type === ErrorType.TIMEOUT) { + return { + status: "loading-error", + error: result, + }; + } + //logout if there is any error, not if loading + // backend.logOut(); + if (result.status === HttpStatusCode.NotFound) { + notifyError(i18n.str`Username or account label "${account}" not found`, undefined); + return { + status: "error-user-not-found", + error: result, + }; + } + if (result.status === HttpStatusCode.Unauthorized) { + notifyError(i18n.str`Authorization denied`, i18n.str`Maybe the session has expired, login again.`); + return { + status: "error-user-not-found", + error: result, + }; + } + return { + status: "loading-error", + error: result, + }; + } + + const { data } = result; + + const balance = Amounts.parseOrThrow(data.balance.amount); + + const debitThreshold = Amounts.parseOrThrow(data.debit_threshold); + const payto = parsePaytoUri(data.payto_uri); + + if (!payto || !payto.isKnown || (payto.targetType !== "iban" && payto.targetType !== "x-taler-bank")) { + return { + status: "invalid-iban", + error: result + }; + } + + const balanceIsDebit = data.balance.credit_debit_indicator == "debit"; + const limit = balanceIsDebit + ? Amounts.sub(debitThreshold, balance).amount + : Amounts.add(balance, debitThreshold).amount; + + + return { + status: "ready", + goToBusinessAccount, + goToConfirmOperation, + error: undefined, + account, + limit, + }; +} diff --git a/packages/demobank-ui/src/pages/AccountPage/stories.tsx b/packages/demobank-ui/src/pages/AccountPage/stories.tsx new file mode 100644 index 000000000..f3828a5d6 --- /dev/null +++ b/packages/demobank-ui/src/pages/AccountPage/stories.tsx @@ -0,0 +1,29 @@ +/* + 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/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import * as tests from "@gnu-taler/web-util/testing"; +import { ReadyView } from "./views.js"; + +export default { + title: "account page", +}; + +export const Ready = tests.createExample(ReadyView, {}); diff --git a/packages/demobank-ui/src/pages/AccountPage/test.ts b/packages/demobank-ui/src/pages/AccountPage/test.ts new file mode 100644 index 000000000..588b84c35 --- /dev/null +++ b/packages/demobank-ui/src/pages/AccountPage/test.ts @@ -0,0 +1,32 @@ +/* + 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/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import * as tests from "@gnu-taler/web-util/testing"; +import { SwrMockEnvironment } from "@gnu-taler/web-util/testing"; +import { expect } from "chai"; +import { CASHOUT_API_EXAMPLE } from "../../endpoints.js"; +import { Props } from "./index.js"; +import { useComponentState } from "./state.js"; + +describe("Account states", () => { + it("should do some tests", async () => { + }); +}); diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx new file mode 100644 index 000000000..483cb579a --- /dev/null +++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx @@ -0,0 +1,93 @@ +/* + 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 { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Fragment, VNode, h } from "preact"; +import { Attention } from "../../components/Attention.js"; +import { Transactions } from "../../components/Transactions/index.js"; +import { useBusinessAccountDetails } from "../../hooks/circuit.js"; +import { useSettings } from "../../hooks/settings.js"; +import { PaymentOptions } from "../PaymentOptions.js"; +import { State } from "./index.js"; + +export function InvalidIbanView({ error }: State.InvalidIban) { + return ( + <div>Payto from server is not valid "{error.data.payto_uri}"</div> + ); +} + +const IS_PUBLIC_ACCOUNT_ENABLED = false + +function ShowDemoInfo(): VNode { + const { i18n } = useTranslationContext(); + const [settings, updateSettings] = useSettings(); + if (!settings.showDemoDescription) return <Fragment /> + return <Attention title={i18n.str`This is a demo bank`} onClose={() => { + updateSettings("showDemoDescription", false); + }}> + {IS_PUBLIC_ACCOUNT_ENABLED ? ( + <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">Public Accounts</a>. + </i18n.Translate> + ) : ( + <i18n.Translate> + This part of the demo shows how a bank that supports Taler + directly would work. + </i18n.Translate> + )} + </Attention> +} + +export function ReadyView({ account, limit, goToBusinessAccount, goToConfirmOperation }: State.Ready): VNode<{}> { + const { i18n } = useTranslationContext(); + + return <Fragment> + <MaybeBusinessButton account={account} onClick={goToBusinessAccount} /> + + <ShowDemoInfo /> + + <PaymentOptions limit={limit} goToConfirmOperation={goToConfirmOperation} /> + <Transactions account={account} /> + </Fragment>; +} + +function MaybeBusinessButton({ + account, + onClick, +}: { + account: string; + onClick: () => void; +}): VNode { + const { i18n } = useTranslationContext(); + const result = useBusinessAccountDetails(account); + if (!result.ok) return <Fragment />; + return ( + <div class="w-full flex justify-end"> + <button + class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + onClick={(e) => { + e.preventDefault() + onClick() + }} + > + <i18n.Translate>Business Profile</i18n.Translate> + </button> + </div> + ); +} |