118 lines
3.9 KiB
TypeScript
118 lines
3.9 KiB
TypeScript
/*
|
|
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,
|
|
HttpResponsePaginated,
|
|
useTranslationContext,
|
|
} from "@gnu-taler/web-util/browser";
|
|
import { Fragment, VNode, h } from "preact";
|
|
import { Transactions } from "../components/Transactions/index.js";
|
|
import { useBackendContext } from "../context/backend.js";
|
|
import { useAccountDetails } from "../hooks/access.js";
|
|
import { LoginForm } from "./LoginForm.js";
|
|
import { PaymentOptions } from "./PaymentOptions.js";
|
|
import { notifyError } from "../hooks/notification.js";
|
|
|
|
interface Props {
|
|
account: string;
|
|
onLoadNotOk: <T>(
|
|
error: HttpResponsePaginated<T, SandboxBackend.SandboxError>,
|
|
) => VNode;
|
|
}
|
|
/**
|
|
* Query account information and show QR code if there is pending withdrawal
|
|
*/
|
|
export function AccountPage({ account, onLoadNotOk }: Props): VNode {
|
|
const result = useAccountDetails(account);
|
|
const backend = useBackendContext();
|
|
const { i18n } = useTranslationContext();
|
|
|
|
if (!result.ok) {
|
|
if (result.loading || result.type === ErrorType.TIMEOUT) {
|
|
return onLoadNotOk(result);
|
|
}
|
|
//logout if there is any error, not if loading
|
|
backend.logOut();
|
|
if (result.status === HttpStatusCode.NotFound) {
|
|
notifyError({
|
|
title: i18n.str`Username or account label "${account}" not found`,
|
|
});
|
|
return <LoginForm />;
|
|
}
|
|
return onLoadNotOk(result);
|
|
}
|
|
|
|
const { data } = result;
|
|
const balance = Amounts.parseOrThrow(data.balance.amount);
|
|
const debitThreshold = Amounts.parseOrThrow(data.debitThreshold);
|
|
const payto = parsePaytoUri(data.paytoUri);
|
|
if (!payto || !payto.isKnown || payto.targetType !== "iban") {
|
|
return (
|
|
<div>Payto from server is not valid "{data.paytoUri}"</div>
|
|
);
|
|
}
|
|
const accountNumber = payto.iban;
|
|
const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
|
|
const limit = balanceIsDebit
|
|
? Amounts.sub(debitThreshold, balance).amount
|
|
: Amounts.add(balance, debitThreshold).amount;
|
|
return (
|
|
<Fragment>
|
|
<div>
|
|
<h1 class="nav welcome-text">
|
|
<i18n.Translate>
|
|
Welcome, {accountNumber ? `${account} (${accountNumber})` : account}
|
|
!
|
|
</i18n.Translate>
|
|
</h1>
|
|
</div>
|
|
|
|
<section id="assets">
|
|
<div class="asset-summary">
|
|
<h2>{i18n.str`Bank account balance`}</h2>
|
|
{!balance ? (
|
|
<div class="large-amount" style={{ color: "gray" }}>
|
|
Waiting server response...
|
|
</div>
|
|
) : (
|
|
<div class="large-amount amount">
|
|
{balanceIsDebit ? <b>-</b> : null}
|
|
<span class="value">{`${Amounts.stringifyValue(balance)}`}</span>
|
|
|
|
<span class="currency">{`${balance.currency}`}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
<section id="payments">
|
|
<div class="payments">
|
|
<h2>{i18n.str`Payments`}</h2>
|
|
<PaymentOptions limit={limit} />
|
|
</div>
|
|
</section>
|
|
|
|
<section style={{ marginTop: "2em" }}>
|
|
<div class="active">
|
|
<h3>{i18n.str`Latest transactions`}</h3>
|
|
<Transactions account={account} />
|
|
</div>
|
|
</section>
|
|
</Fragment>
|
|
);
|
|
}
|