wallet-core/packages/taler-wallet-webextension/src/wallet/Transaction.tsx

234 lines
9.5 KiB
TypeScript
Raw Normal View History

/*
This file is part of TALER
(C) 2016 GNUnet e.V.
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.
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
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
2021-10-27 20:13:35 +02:00
import { AmountLike, Amounts, i18n, Transaction, TransactionType } from "@gnu-taler/taler-util";
import { format } from "date-fns";
2021-10-27 20:13:35 +02:00
import { JSX, VNode } from "preact";
import { route } from 'preact-router';
import { useEffect, useState } from "preact/hooks";
2021-10-27 20:13:35 +02:00
import emptyImg from "../../static/img/empty.png";
2021-07-13 20:33:28 +02:00
import { ErrorMessage } from "../components/ErrorMessage";
import { Part } from "../components/Part";
2021-10-27 20:13:35 +02:00
import { ButtonBox, ButtonBoxDestructive, ButtonPrimary, FontIcon, ListOfProducts, RowBorderGray, SmallLightText, WalletBox, WarningBox } from "../components/styled";
import { Pages } from "../NavigationBar";
import * as wxApi from "../wxApi";
export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
const [transaction, setTransaction] = useState<
Transaction | undefined
>(undefined);
useEffect(() => {
const fetchData = async (): Promise<void> => {
const res = await wxApi.getTransactions();
const ts = res.transactions.filter(t => t.transactionId === tid);
if (ts.length === 1) {
setTransaction(ts[0]);
} else {
route(Pages.history);
}
};
fetchData();
2021-10-27 20:13:35 +02:00
}, [tid]);
2021-07-13 20:33:28 +02:00
if (!transaction) {
return <div><i18n.Translate>Loading ...</i18n.Translate></div>;
}
return <TransactionView
transaction={transaction}
onDelete={() => wxApi.deleteTransaction(tid).then(_ => history.go(-1))}
onRetry={() => wxApi.retryTransaction(tid).then(_ => history.go(-1))}
2021-09-20 19:05:40 +02:00
onBack={() => { route(Pages.history) }} />;
}
export interface WalletTransactionProps {
2021-10-15 00:37:18 +02:00
transaction: Transaction;
onDelete: () => void;
onRetry: () => void;
onBack: () => void;
}
2021-07-13 20:33:28 +02:00
export function TransactionView({ transaction, onDelete, onRetry, onBack }: WalletTransactionProps) {
2021-08-24 20:16:11 +02:00
function TransactionTemplate({ children }: { children: VNode[] }) {
2021-08-24 18:29:37 +02:00
return <WalletBox>
2021-10-15 00:37:18 +02:00
<section style={{ padding: 8, textAlign: 'center'}}>
2021-07-13 20:33:28 +02:00
<ErrorMessage title={transaction?.error?.hint} />
2021-10-15 00:37:18 +02:00
{transaction.pending && <WarningBox>This transaction is not completed</WarningBox>}
</section>
<section>
2021-08-24 20:16:11 +02:00
<div style={{ textAlign: 'center' }}>
{children}
</div>
2021-07-13 20:33:28 +02:00
</section>
<footer>
2021-08-24 20:16:11 +02:00
<ButtonBox onClick={onBack}><i18n.Translate> <FontIcon>&#x2190;</FontIcon> </i18n.Translate></ButtonBox>
2021-07-13 20:33:28 +02:00
<div>
{transaction?.error ? <ButtonPrimary onClick={onRetry}><i18n.Translate>retry</i18n.Translate></ButtonPrimary> : null}
2021-08-24 20:16:11 +02:00
<ButtonBoxDestructive onClick={onDelete}><i18n.Translate>&#x1F5D1;</i18n.Translate></ButtonBoxDestructive>
2021-07-13 20:33:28 +02:00
</div>
</footer>
2021-08-24 18:29:37 +02:00
</WalletBox>
2021-07-13 20:33:28 +02:00
}
2021-08-24 20:16:11 +02:00
function amountToString(text: AmountLike) {
const aj = Amounts.jsonifyAmount(text)
const amount = Amounts.stringifyValue(aj)
return `${amount} ${aj.currency}`
}
2021-06-21 01:37:35 +02:00
if (transaction.type === TransactionType.Withdrawal) {
2021-06-21 01:37:35 +02:00
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
).amount
2021-08-24 20:16:11 +02:00
return <TransactionTemplate>
2021-10-15 00:37:18 +02:00
<h2>Withdrawal</h2>
<div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
2021-08-24 20:16:11 +02:00
<br />
<Part title="Total withdrawn" text={amountToString(transaction.amountEffective)} kind='positive' />
<Part title="Chosen amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
<Part title="Exchange fee" text={amountToString(fee)} kind='negative' />
<Part title="Exchange" text={new URL(transaction.exchangeBaseUrl).hostname} kind='neutral' />
2021-07-13 20:33:28 +02:00
</TransactionTemplate>
}
2021-06-21 01:37:35 +02:00
const showLargePic = () => {
}
if (transaction.type === TransactionType.Payment) {
2021-06-21 01:37:35 +02:00
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountEffective),
Amounts.parseOrThrow(transaction.amountRaw),
).amount
2021-08-24 20:16:11 +02:00
return <TransactionTemplate>
2021-10-15 00:37:18 +02:00
<h2>Payment </h2>
<div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
2021-08-24 20:16:11 +02:00
<br />
<Part big title="Total paid" text={amountToString(transaction.amountEffective)} kind='negative' />
<Part big title="Purchase amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
<Part big title="Fee" text={amountToString(fee)} kind='negative' />
<Part title="Merchant" text={transaction.info.merchant.name} kind='neutral' />
<Part title="Purchase" text={transaction.info.summary} kind='neutral' />
<Part title="Receipt" text={`#${transaction.info.orderId}`} kind='neutral' />
2021-07-13 20:33:28 +02:00
<div>
{transaction.info.products && transaction.info.products.length > 0 &&
<ListOfProducts>
2021-10-15 00:37:18 +02:00
{transaction.info.products.map((p, k) => <RowBorderGray key={k}>
2021-07-13 20:33:28 +02:00
<a href="#" onClick={showLargePic}>
<img src={p.image ? p.image : emptyImg} />
</a>
<div>
2021-09-06 19:55:55 +02:00
{p.quantity && p.quantity > 0 && <SmallLightText>x {p.quantity} {p.unit}</SmallLightText>}
2021-07-13 20:33:28 +02:00
<div>{p.description}</div>
</div>
</RowBorderGray>)}
</ListOfProducts>
}
</div>
2021-07-13 20:33:28 +02:00
</TransactionTemplate>
}
if (transaction.type === TransactionType.Deposit) {
2021-06-21 01:37:35 +02:00
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
).amount
2021-08-24 20:16:11 +02:00
return <TransactionTemplate>
2021-10-15 00:37:18 +02:00
<h2>Deposit </h2>
<div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
2021-08-24 20:16:11 +02:00
<br />
<Part big title="Total deposit" text={amountToString(transaction.amountEffective)} kind='negative' />
<Part big title="Purchase amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
<Part big title="Fee" text={amountToString(fee)} kind='negative' />
2021-07-13 20:33:28 +02:00
</TransactionTemplate>
}
if (transaction.type === TransactionType.Refresh) {
2021-06-21 01:37:35 +02:00
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
).amount
2021-08-24 20:16:11 +02:00
return <TransactionTemplate>
2021-10-15 00:37:18 +02:00
<h2>Refresh</h2>
<div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
2021-08-24 20:16:11 +02:00
<br />
<Part big title="Total refresh" text={amountToString(transaction.amountEffective)} kind='negative' />
<Part big title="Refresh amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
<Part big title="Fee" text={amountToString(fee)} kind='negative' />
2021-07-13 20:33:28 +02:00
</TransactionTemplate>
}
if (transaction.type === TransactionType.Tip) {
2021-06-21 01:37:35 +02:00
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
).amount
2021-08-24 20:16:11 +02:00
return <TransactionTemplate>
2021-10-15 00:37:18 +02:00
<h2>Tip</h2>
<div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
2021-08-24 20:16:11 +02:00
<br />
<Part big title="Total tip" text={amountToString(transaction.amountEffective)} kind='positive' />
<Part big title="Received amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
<Part big title="Fee" text={amountToString(fee)} kind='negative' />
2021-07-13 20:33:28 +02:00
</TransactionTemplate>
}
if (transaction.type === TransactionType.Refund) {
2021-06-21 01:37:35 +02:00
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
).amount
2021-08-24 20:16:11 +02:00
return <TransactionTemplate>
2021-10-15 00:37:18 +02:00
<h2>Refund</h2>
<div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
2021-08-24 20:16:11 +02:00
<br />
<Part big title="Total refund" text={amountToString(transaction.amountEffective)} kind='positive' />
<Part big title="Refund amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
<Part big title="Fee" text={amountToString(fee)} kind='negative' />
<Part title="Merchant" text={transaction.info.merchant.name} kind='neutral' />
<Part title="Purchase" text={transaction.info.summary} kind='neutral' />
<Part title="Receipt" text={`#${transaction.info.orderId}`} kind='neutral' />
2021-07-13 20:33:28 +02:00
<p>
{transaction.info.summary}
</p>
<div>
{transaction.info.products && transaction.info.products.length > 0 &&
<ListOfProducts>
2021-10-15 00:37:18 +02:00
{transaction.info.products.map((p, k) => <RowBorderGray key={k}>
2021-07-13 20:33:28 +02:00
<a href="#" onClick={showLargePic}>
<img src={p.image ? p.image : emptyImg} />
</a>
<div>
2021-09-06 19:55:55 +02:00
{p.quantity && p.quantity > 0 && <SmallLightText>x {p.quantity} {p.unit}</SmallLightText>}
2021-07-13 20:33:28 +02:00
<div>{p.description}</div>
</div>
</RowBorderGray>)}
</ListOfProducts>
}
</div>
2021-07-13 20:33:28 +02:00
</TransactionTemplate>
}
return <div></div>
}