wallet-core/packages/taler-wallet-webextension/src/components/TransactionItem.tsx

285 lines
8.2 KiB
TypeScript
Raw Normal View History

2021-09-13 18:33:13 +02:00
/*
This file is part of GNU Taler
2022-06-06 17:05:26 +02:00
(C) 2022 Taler Systems S.A.
2021-09-13 18:33:13 +02:00
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/>
*/
2021-11-15 15:18:58 +01:00
import {
AmountJson,
Amounts,
2021-11-15 15:18:58 +01:00
AmountString,
2022-03-18 15:32:41 +01:00
AbsoluteTime,
2021-11-15 15:18:58 +01:00
Transaction,
TransactionType,
2022-11-18 17:26:48 +01:00
WithdrawalType,
2021-11-15 15:18:58 +01:00
} from "@gnu-taler/taler-util";
2021-11-16 17:59:53 +01:00
import { h, VNode } from "preact";
2022-03-29 04:41:07 +02:00
import { useTranslationContext } from "../context/translation.js";
import { Avatar } from "../mui/Avatar.js";
import { Pages } from "../NavigationBar.js";
2022-11-25 03:16:01 +01:00
import { assertUnreachable } from "../utils/index.js";
2021-11-15 15:18:58 +01:00
import {
Column,
ExtraLargeText,
HistoryRow,
LargeText,
LightText,
SmallLightText,
2022-03-29 04:41:07 +02:00
} from "./styled/index.js";
import { Time } from "./Time.js";
2021-08-24 17:00:34 +02:00
export function TransactionItem(props: { tx: Transaction }): VNode {
2021-08-24 17:00:34 +02:00
const tx = props.tx;
2022-11-18 17:26:48 +01:00
const { i18n } = useTranslationContext();
2021-08-24 17:00:34 +02:00
switch (tx.type) {
case TransactionType.Withdrawal:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"credit"}
title={new URL(tx.exchangeBaseUrl).hostname}
2022-03-18 15:32:41 +01:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
2022-03-11 20:18:26 +01:00
iconPath={"W"}
2022-11-18 17:26:48 +01:00
pending={
tx.pending
? tx.withdrawalDetails.type ===
WithdrawalType.TalerBankIntegrationApi
? !tx.withdrawalDetails.confirmed
? i18n.str`Need approval in the Bank`
: i18n.str`Exchange is waiting the wire transfer`
2022-11-22 19:43:39 +01:00
: tx.withdrawalDetails.type === WithdrawalType.ManualTransfer
? i18n.str`Exchange is waiting the wire transfer`
: "" //pending but no message
2022-11-18 17:26:48 +01:00
: undefined
}
2021-10-15 01:00:39 +02:00
/>
2021-08-24 17:00:34 +02:00
);
case TransactionType.Payment:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"debit"}
title={tx.info.merchant.name}
2021-10-15 01:00:39 +02:00
subtitle={tx.info.summary}
2022-03-18 15:32:41 +01:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
2022-03-11 20:18:26 +01:00
iconPath={"P"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2021-10-15 01:00:39 +02:00
/>
2021-08-24 17:00:34 +02:00
);
case TransactionType.Refund:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"credit"}
subtitle={tx.info.summary}
2021-08-24 17:00:34 +02:00
title={tx.info.merchant.name}
2022-03-18 15:32:41 +01:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
2022-03-11 20:18:26 +01:00
iconPath={"R"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2021-10-15 01:00:39 +02:00
/>
2021-08-24 17:00:34 +02:00
);
case TransactionType.Tip:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"credit"}
title={new URL(tx.merchantBaseUrl).hostname}
2022-03-18 15:32:41 +01:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
2022-03-11 20:18:26 +01:00
iconPath={"T"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2021-10-15 01:00:39 +02:00
/>
2021-08-24 17:00:34 +02:00
);
case TransactionType.Refresh:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"credit"}
title={new URL(tx.exchangeBaseUrl).hostname}
2022-03-18 15:32:41 +01:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
2022-03-11 20:18:26 +01:00
iconPath={"R"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2021-10-15 01:00:39 +02:00
/>
2021-08-24 17:00:34 +02:00
);
case TransactionType.Deposit:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"debit"}
title={tx.targetPaytoUri}
2022-03-18 15:32:41 +01:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
2022-03-11 20:18:26 +01:00
iconPath={"D"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2021-10-15 01:00:39 +02:00
/>
2021-08-24 17:00:34 +02:00
);
2022-08-31 05:20:35 +02:00
case TransactionType.PeerPullCredit:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"credit"}
2022-09-01 14:20:59 +02:00
title={tx.info.summary || "Invoice"}
2022-08-31 05:20:35 +02:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
iconPath={"I"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2022-08-31 05:20:35 +02:00
/>
);
case TransactionType.PeerPullDebit:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"debit"}
2022-09-01 14:20:59 +02:00
title={tx.info.summary || "Invoice"}
2022-08-31 05:20:35 +02:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
iconPath={"I"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2022-08-31 05:20:35 +02:00
/>
);
case TransactionType.PeerPushCredit:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"credit"}
2022-09-01 14:20:59 +02:00
title={tx.info.summary || "Transfer"}
2022-08-31 05:20:35 +02:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
iconPath={"T"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2022-08-31 05:20:35 +02:00
/>
);
case TransactionType.PeerPushDebit:
return (
<TransactionLayout
id={tx.transactionId}
amount={tx.amountEffective}
debitCreditIndicator={"debit"}
2022-09-01 14:20:59 +02:00
title={tx.info.summary || "Transfer"}
2022-08-31 05:20:35 +02:00
timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)}
iconPath={"T"}
2022-11-18 17:26:48 +01:00
// pending={tx.pending}
2022-08-31 05:20:35 +02:00
/>
);
default: {
2022-11-25 03:16:01 +01:00
assertUnreachable(tx);
2022-08-31 05:20:35 +02:00
}
2021-08-24 17:00:34 +02:00
}
}
2021-11-16 17:59:53 +01:00
function TransactionLayout(props: TransactionLayoutProps): VNode {
const { i18n } = useTranslationContext();
2021-08-24 17:00:34 +02:00
return (
2022-03-11 20:18:26 +01:00
<HistoryRow
2022-06-02 17:20:36 +02:00
href={Pages.balanceTransaction({ tid: props.id })}
2022-03-11 20:18:26 +01:00
style={{
backgroundColor: props.pending ? "lightcyan" : "inherit",
alignItems: "center",
}}
>
<Avatar
style={{
border: "solid gray 1px",
color: "gray",
boxSizing: "border-box",
}}
>
{props.iconPath}
</Avatar>
2021-08-24 17:00:34 +02:00
<Column>
<LargeText>
2021-10-15 01:00:39 +02:00
<div>{props.title}</div>
2021-11-15 15:18:58 +01:00
{props.subtitle && (
<div style={{ color: "gray", fontSize: "medium", marginTop: 5 }}>
{props.subtitle}
</div>
)}
2021-08-24 17:00:34 +02:00
</LargeText>
2021-11-15 15:18:58 +01:00
{props.pending && (
<LightText style={{ marginTop: 5, marginBottom: 5 }}>
2022-11-18 17:26:48 +01:00
<i18n.Translate>{props.pending}</i18n.Translate>
2021-11-15 15:18:58 +01:00
</LightText>
)}
2021-11-16 17:59:53 +01:00
<SmallLightText style={{ marginTop: 5 }}>
2022-09-12 19:32:45 +02:00
<Time timestamp={props.timestamp} format="HH:mm" />
2021-11-16 17:59:53 +01:00
</SmallLightText>
2021-08-24 17:00:34 +02:00
</Column>
<TransactionAmount
2022-11-18 17:26:48 +01:00
pending={props.pending !== undefined}
amount={Amounts.parseOrThrow(props.amount)}
2021-08-24 17:00:34 +02:00
debitCreditIndicator={props.debitCreditIndicator}
/>
</HistoryRow>
);
}
interface TransactionLayoutProps {
debitCreditIndicator: "debit" | "credit" | "unknown";
amount: AmountString | "unknown";
2022-03-18 15:32:41 +01:00
timestamp: AbsoluteTime;
2021-08-24 17:00:34 +02:00
title: string;
2021-10-15 01:00:39 +02:00
subtitle?: string;
2021-08-24 17:00:34 +02:00
id: string;
iconPath: string;
2022-11-18 17:26:48 +01:00
pending?: string;
2021-08-24 17:00:34 +02:00
}
interface TransactionAmountProps {
debitCreditIndicator: "debit" | "credit" | "unknown";
amount: AmountJson;
2021-08-24 17:00:34 +02:00
pending: boolean;
}
2021-11-16 17:59:53 +01:00
function TransactionAmount(props: TransactionAmountProps): VNode {
const { i18n } = useTranslationContext();
2021-08-24 17:00:34 +02:00
let sign: string;
switch (props.debitCreditIndicator) {
case "credit":
sign = "+";
break;
case "debit":
sign = "-";
break;
case "unknown":
sign = "";
}
return (
2021-11-15 15:18:58 +01:00
<Column
style={{
textAlign: "center",
color: props.pending
? "gray"
: sign === "+"
? "darkgreen"
: sign === "-"
? "darkred"
: undefined,
}}
>
2021-08-24 17:00:34 +02:00
<ExtraLargeText>
{sign}
{Amounts.stringifyValue(props.amount, 2)}
2021-08-24 17:00:34 +02:00
</ExtraLargeText>
2022-02-23 19:18:37 +01:00
{props.pending && (
<div>
<i18n.Translate>PENDING</i18n.Translate>
2022-02-23 19:18:37 +01:00
</div>
)}
2021-08-24 17:00:34 +02:00
</Column>
);
}