aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/pages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-02-10 09:51:37 -0300
committerSebastian <sebasjm@gmail.com>2023-02-10 09:52:02 -0300
commitba8b40c9150586982e42e76d364d76202627bd6f (patch)
treeebeed7551aad62a03954945de72320b6c1bc1f01 /packages/demobank-ui/src/pages
parent53af8b486fd8a538c1f54a2ce66ed5f74b2b46ed (diff)
downloadwallet-core-ba8b40c9150586982e42e76d364d76202627bd6f.tar.xz
business account
Diffstat (limited to 'packages/demobank-ui/src/pages')
-rw-r--r--packages/demobank-ui/src/pages/AccountPage.tsx81
-rw-r--r--packages/demobank-ui/src/pages/AdminPage.tsx117
-rw-r--r--packages/demobank-ui/src/pages/BankFrame.tsx81
-rw-r--r--packages/demobank-ui/src/pages/BusinessAccount.tsx90
-rw-r--r--packages/demobank-ui/src/pages/HomePage.tsx4
-rw-r--r--packages/demobank-ui/src/pages/Routing.tsx23
6 files changed, 281 insertions, 115 deletions
diff --git a/packages/demobank-ui/src/pages/AccountPage.tsx b/packages/demobank-ui/src/pages/AccountPage.tsx
index 769e85804..370605871 100644
--- a/packages/demobank-ui/src/pages/AccountPage.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage.tsx
@@ -104,49 +104,48 @@ export function AccountPage({ account, onLoadNotOk }: Props): VNode {
)}
<section style={{ marginTop: "2em" }}>
- <Moves account={account} />
+ <div class="active">
+ <h3>{i18n.str`Latest transactions`}</h3>
+ <Transactions account={account} />
+ </div>
</section>
</Fragment>
);
}
-function Moves({ account }: { account: string }): VNode {
- const [tab, setTab] = useState<"transactions" | "cashouts">("transactions");
- const { i18n } = useTranslationContext();
- return (
- <article>
- <div class="payments">
- <div class="tab">
- <button
- class={tab === "transactions" ? "tablinks active" : "tablinks"}
- onClick={(): void => {
- setTab("transactions");
- }}
- >
- {i18n.str`Transactions`}
- </button>
- <button
- class={tab === "cashouts" ? "tablinks active" : "tablinks"}
- onClick={(): void => {
- setTab("cashouts");
- }}
- >
- {i18n.str`Cashouts`}
- </button>
- </div>
- {tab === "transactions" && (
- <div class="active">
- <h3>{i18n.str`Latest transactions`}</h3>
- <Transactions account={account} />
- </div>
- )}
- {tab === "cashouts" && (
- <div class="active">
- <h3>{i18n.str`Latest cashouts`}</h3>
- <Cashouts account={account} />
- </div>
- )}
- </div>
- </article>
- );
-}
+// function Moves({ account }: { account: string }): VNode {
+// const [tab, setTab] = useState<"transactions" | "cashouts">("transactions");
+// const { i18n } = useTranslationContext();
+// return (
+// <article>
+// <div class="payments">
+// <div class="tab">
+// <button
+// class={tab === "transactions" ? "tablinks active" : "tablinks"}
+// onClick={(): void => {
+// setTab("transactions");
+// }}
+// >
+// {i18n.str`Transactions`}
+// </button>
+// <button
+// class={tab === "cashouts" ? "tablinks active" : "tablinks"}
+// onClick={(): void => {
+// setTab("cashouts");
+// }}
+// >
+// {i18n.str`Cashouts`}
+// </button>
+// </div>
+// {tab === "transactions" && (
+// )}
+// {tab === "cashouts" && (
+// <div class="active">
+// <h3>{i18n.str`Latest cashouts`}</h3>
+// <Cashouts account={account} />
+// </div>
+// )}
+// </div>
+// </article>
+// );
+// }
diff --git a/packages/demobank-ui/src/pages/AdminPage.tsx b/packages/demobank-ui/src/pages/AdminPage.tsx
index 9efd37f12..f8efddd80 100644
--- a/packages/demobank-ui/src/pages/AdminPage.tsx
+++ b/packages/demobank-ui/src/pages/AdminPage.tsx
@@ -24,8 +24,8 @@ import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { ErrorMessage, usePageContext } from "../context/pageState.js";
import {
- useAccountDetails,
- useAccounts,
+ useBusinessAccountDetails,
+ useBusinessAccounts,
useAdminAccountAPI,
} from "../hooks/circuit.js";
import {
@@ -71,7 +71,7 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
}));
}
- const result = useAccounts({ account });
+ const result = useBusinessAccounts({ account });
const { i18n } = useTranslationContext();
if (result.loading) return <div />;
@@ -86,6 +86,10 @@ export function AdminPage({ onLoadNotOk }: Props): VNode {
<ShowAccountDetails
account={showDetails}
onLoadNotOk={onLoadNotOk}
+ onChangePassword={() => {
+ setUpdatePassword(showDetails);
+ setShowDetails(undefined);
+ }}
onUpdateSuccess={() => {
showInfoMessage(i18n.str`Account updated`);
setShowDetails(undefined);
@@ -230,7 +234,7 @@ function initializeFromTemplate(
return initial as any;
}
-function UpdateAccountPassword({
+export function UpdateAccountPassword({
account,
onClear,
onUpdateSuccess,
@@ -242,7 +246,7 @@ function UpdateAccountPassword({
account: string;
}): VNode {
const { i18n } = useTranslationContext();
- const result = useAccountDetails(account);
+ const result = useBusinessAccountDetails(account);
const { changePassword } = useAdminAccountAPI();
const [password, setPassword] = useState<string | undefined>();
const [repeat, setRepeat] = useState<string | undefined>();
@@ -268,7 +272,7 @@ function UpdateAccountPassword({
<div>
<div>
<h1 class="nav welcome-text">
- <i18n.Translate>Admin panel</i18n.Translate>
+ <i18n.Translate>Update password for {account}</i18n.Translate>
</h1>
</div>
{error && (
@@ -277,10 +281,6 @@ function UpdateAccountPassword({
<form class="pure-form">
<fieldset>
- <label for="username">{i18n.str`Username`}</label>
- <input name="username" type="text" readOnly value={account} />
- </fieldset>
- <fieldset>
<label>{i18n.str`Password`}</label>
<input
type="password"
@@ -366,7 +366,7 @@ function CreateNewAccount({
<div>
<div>
<h1 class="nav welcome-text">
- <i18n.Translate>Admin panel</i18n.Translate>
+ <i18n.Translate>New account</i18n.Translate>
</h1>
</div>
{error && (
@@ -428,19 +428,21 @@ function CreateNewAccount({
);
}
-function ShowAccountDetails({
+export function ShowAccountDetails({
account,
onClear,
onUpdateSuccess,
onLoadNotOk,
+ onChangePassword,
}: {
onLoadNotOk: <T, E>(error: HttpResponsePaginated<T, E>) => VNode;
- onClear: () => void;
+ onClear?: () => void;
+ onChangePassword: () => void;
onUpdateSuccess: () => void;
account: string;
}): VNode {
const { i18n } = useTranslationContext();
- const result = useAccountDetails(account);
+ const result = useBusinessAccountDetails(account);
const { updateAccount } = useAdminAccountAPI();
const [update, setUpdate] = useState(false);
const [submitAccount, setSubmitAccount] = useState<
@@ -459,7 +461,7 @@ function ShowAccountDetails({
<div>
<div>
<h1 class="nav welcome-text">
- <i18n.Translate>Admin panel</i18n.Translate>
+ <i18n.Translate>Business account details</i18n.Translate>
</h1>
</div>
{error && (
@@ -474,42 +476,59 @@ function ShowAccountDetails({
<p>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div>
- <input
- class="pure-button"
- type="submit"
- value={i18n.str`Close`}
- onClick={async (e) => {
- e.preventDefault();
- onClear();
- }}
- />
+ {onClear ? (
+ <input
+ class="pure-button"
+ type="submit"
+ value={i18n.str`Close`}
+ onClick={async (e) => {
+ e.preventDefault();
+ onClear();
+ }}
+ />
+ ) : undefined}
</div>
- <div>
- <input
- id="select-exchange"
- class="pure-button pure-button-primary content"
- disabled={update && !submitAccount}
- type="submit"
- value={update ? i18n.str`Confirm` : i18n.str`Update`}
- onClick={async (e) => {
- e.preventDefault();
-
- if (!update) {
- setUpdate(true);
- } else {
- if (!submitAccount) return;
- try {
- await updateAccount(account, {
- cashout_address: submitAccount.cashout_address,
- contact_data: submitAccount.contact_data,
- });
- onUpdateSuccess();
- } catch (error) {
- handleError(error, saveError, i18n);
+ <div style={{ display: "flex" }}>
+ <div>
+ <input
+ id="select-exchange"
+ class="pure-button pure-button-primary content"
+ disabled={update && !submitAccount}
+ type="submit"
+ value={i18n.str`Change password`}
+ onClick={async (e) => {
+ e.preventDefault();
+ onChangePassword();
+ }}
+ />
+ </div>
+ <div>
+ <input
+ id="select-exchange"
+ class="pure-button pure-button-primary content"
+ disabled={update && !submitAccount}
+ type="submit"
+ value={update ? i18n.str`Confirm` : i18n.str`Update`}
+ onClick={async (e) => {
+ e.preventDefault();
+
+ if (!update) {
+ setUpdate(true);
+ } else {
+ if (!submitAccount) return;
+ try {
+ await updateAccount(account, {
+ cashout_address: submitAccount.cashout_address,
+ contact_data: submitAccount.contact_data,
+ });
+ onUpdateSuccess();
+ } catch (error) {
+ handleError(error, saveError, i18n);
+ }
}
- }
- }}
- />
+ }}
+ />
+ </div>
</div>
</div>
</p>
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index ed36daa21..0fb75b87b 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -15,6 +15,7 @@
*/
import { Logger } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser";
import { ComponentChildren, Fragment, h, VNode } from "preact";
import talerLogo from "../assets/logo-white.svg";
import { LangSelectorLikePy as LangSelector } from "../components/LangSelector.js";
@@ -24,41 +25,46 @@ import {
PageStateType,
usePageContext,
} from "../context/pageState.js";
-import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser";
+import { useBusinessAccountDetails } from "../hooks/circuit.js";
import { bankUiSettings } from "../settings.js";
const logger = new Logger("BankFrame");
+function MaybeBusinessButton({
+ account,
+ onClick,
+}: {
+ account: string;
+ onClick: () => void;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const result = useBusinessAccountDetails(account);
+ if (!result.ok) return <Fragment />;
+ return (
+ <div class="some-space">
+ <a
+ href="#"
+ class="pure-button pure-button-primary"
+ onClick={(e) => {
+ e.preventDefault();
+ onClick();
+ }}
+ >{i18n.str`Business Profile`}</a>
+ </div>
+ );
+}
+
export function BankFrame({
children,
+ goToBusinessAccount,
}: {
children: ComponentChildren;
+ goToBusinessAccount?: () => void;
}): VNode {
const { i18n } = useTranslationContext();
const backend = useBackendContext();
const { pageState, pageStateSetter } = usePageContext();
logger.trace("state", pageState);
- const logOut = (
- <div class="logout">
- <a
- href="#"
- class="pure-button logout-button"
- onClick={() => {
- pageStateSetter((prevState: PageStateType) => {
- const { talerWithdrawUri, withdrawalId, ...rest } = prevState;
- backend.logOut();
- return {
- ...rest,
- withdrawalInProgress: false,
- error: undefined,
- info: undefined,
- isRawPayto: false,
- };
- });
- }}
- >{i18n.str`Logout`}</a>
- </div>
- );
const demo_sites = [];
for (const i in bankUiSettings.demoSites)
@@ -120,7 +126,36 @@ export function BankFrame({
/>
)}
<StatusBanner />
- {backend.state.status === "loggedIn" ? logOut : null}
+ {backend.state.status === "loggedIn" ? (
+ <div class="top-right">
+ {goToBusinessAccount ? (
+ <MaybeBusinessButton
+ account={backend.state.username}
+ onClick={goToBusinessAccount}
+ />
+ ) : undefined}
+ <div class="some-space">
+ <a
+ href="#"
+ class="pure-button logout-button"
+ onClick={() => {
+ pageStateSetter((prevState: PageStateType) => {
+ const { talerWithdrawUri, withdrawalId, ...rest } =
+ prevState;
+ backend.logOut();
+ return {
+ ...rest,
+ withdrawalInProgress: false,
+ error: undefined,
+ info: undefined,
+ isRawPayto: false,
+ };
+ });
+ }}
+ >{i18n.str`Logout`}</a>
+ </div>
+ </div>
+ ) : null}
{children}
</section>
<section id="footer" class="footer">
diff --git a/packages/demobank-ui/src/pages/BusinessAccount.tsx b/packages/demobank-ui/src/pages/BusinessAccount.tsx
new file mode 100644
index 000000000..d845c2fa0
--- /dev/null
+++ b/packages/demobank-ui/src/pages/BusinessAccount.tsx
@@ -0,0 +1,90 @@
+/*
+ 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 { TranslatedString } from "@gnu-taler/taler-util";
+import {
+ HttpResponsePaginated,
+ useTranslationContext,
+} from "@gnu-taler/web-util/lib/index.browser";
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Cashouts } from "../components/Cashouts/index.js";
+import { useBackendContext } from "../context/backend.js";
+import { usePageContext } from "../context/pageState.js";
+import { ShowAccountDetails, UpdateAccountPassword } from "./AdminPage.js";
+import { LoginForm } from "./LoginForm.js";
+
+interface Props {
+ onClose: () => void;
+ onRegister: () => void;
+ onLoadNotOk: <T, E>(error: HttpResponsePaginated<T, E>) => VNode;
+}
+export function BusinessAccount({
+ onClose,
+ onLoadNotOk,
+ onRegister,
+}: Props): VNode {
+ const { i18n } = useTranslationContext();
+ const { pageStateSetter } = usePageContext();
+ const backend = useBackendContext();
+ const [updatePassword, setUpdatePassword] = useState(false);
+ function showInfoMessage(info: TranslatedString): void {
+ pageStateSetter((prev) => ({
+ ...prev,
+ info,
+ }));
+ }
+
+ if (backend.state.status === "loggedOut") {
+ return <LoginForm onRegister={onRegister} />;
+ }
+
+ if (updatePassword) {
+ return (
+ <UpdateAccountPassword
+ account={backend.state.username}
+ onLoadNotOk={onLoadNotOk}
+ onUpdateSuccess={() => {
+ showInfoMessage(i18n.str`Password changed`);
+ setUpdatePassword(false);
+ }}
+ onClear={() => {
+ setUpdatePassword(false);
+ }}
+ />
+ );
+ }
+ return (
+ <div>
+ <ShowAccountDetails
+ account={backend.state.username}
+ onLoadNotOk={onLoadNotOk}
+ onUpdateSuccess={() => {
+ showInfoMessage(i18n.str`Account updated`);
+ }}
+ onChangePassword={() => {
+ setUpdatePassword(true);
+ }}
+ onClear={onClose}
+ />
+ <section style={{ marginTop: "2em" }}>
+ <div class="active">
+ <h3>{i18n.str`Latest cashouts`}</h3>
+ <Cashouts />
+ </div>
+ </section>
+ </div>
+ );
+}
diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx
index e60732d42..76eb8d515 100644
--- a/packages/demobank-ui/src/pages/HomePage.tsx
+++ b/packages/demobank-ui/src/pages/HomePage.tsx
@@ -50,6 +50,7 @@ export function HomePage({ onRegister }: { onRegister: () => void }): VNode {
}
function saveErrorAndLogout(error: PageStateType["error"]): void {
+ console.log("rrot", error);
saveError(error);
backend.logOut();
}
@@ -123,6 +124,7 @@ function handleNotOkResult(
return function handleNotOkResult2<T, E>(
result: HttpResponsePaginated<T, E>,
): VNode {
+ console.log("qweqwe", JSON.stringify(result, undefined, 2));
if (result.clientError && result.isUnauthorized) {
onErrorHandler({
title: i18n.str`Wrong credentials for "${account}"`,
@@ -139,7 +141,7 @@ function handleNotOkResult(
if (!result.ok) {
onErrorHandler({
title: i18n.str`The backend reported a problem: HTTP status #${result.status}`,
- description: `Diagnostic from ${result.info?.url.href} is "${result.message}"`,
+ description: `Diagnostic from ${result.info?.url} is "${result.message}"`,
debug: JSON.stringify(result.error),
});
return <LoginForm onRegister={onRegister} />;
diff --git a/packages/demobank-ui/src/pages/Routing.tsx b/packages/demobank-ui/src/pages/Routing.tsx
index a88af9b0b..cff561aac 100644
--- a/packages/demobank-ui/src/pages/Routing.tsx
+++ b/packages/demobank-ui/src/pages/Routing.tsx
@@ -28,6 +28,7 @@ import { HomePage } from "./HomePage.js";
import { BankFrame } from "./BankFrame.js";
import { PublicHistoriesPage } from "./PublicHistoriesPage.js";
import { RegistrationPage } from "./RegistrationPage.js";
+import { BusinessAccount } from "./BusinessAccount.js";
function handleNotOkResult(
safe: string,
@@ -96,7 +97,11 @@ export function Routing(): VNode {
<Route
path="/account"
component={() => (
- <BankFrame>
+ <BankFrame
+ goToBusinessAccount={() => {
+ route("/business");
+ }}
+ >
<HomePage
onRegister={() => {
route("/register");
@@ -105,6 +110,22 @@ export function Routing(): VNode {
</BankFrame>
)}
/>
+ <Route
+ path="/business"
+ component={() => (
+ <BankFrame>
+ <BusinessAccount
+ onClose={() => {
+ route("/account");
+ }}
+ onRegister={() => {
+ route("/register");
+ }}
+ onLoadNotOk={handleNotOkResult("/account", saveError, i18n)}
+ />
+ </BankFrame>
+ )}
+ />
<Route default component={Redirect} to="/account" />
</Router>
);