diff options
author | Sebastian <sebasjm@gmail.com> | 2023-06-01 14:26:28 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-06-01 14:26:28 -0300 |
commit | 4f726b73e66535a69a961da30cf3dcddbbbd9efc (patch) | |
tree | 97ae4e120a2724a851a780da9714c448080a373b /packages/taler-wallet-webextension/src/components/HistoryItem.tsx | |
parent | 699a7b453b90a117776dbb64a09f4c8b312acd04 (diff) | |
download | wallet-core-4f726b73e66535a69a961da30cf3dcddbbbd9efc.tar.xz |
tx state ui
Diffstat (limited to 'packages/taler-wallet-webextension/src/components/HistoryItem.tsx')
-rw-r--r-- | packages/taler-wallet-webextension/src/components/HistoryItem.tsx | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/packages/taler-wallet-webextension/src/components/HistoryItem.tsx b/packages/taler-wallet-webextension/src/components/HistoryItem.tsx new file mode 100644 index 000000000..a0ce04460 --- /dev/null +++ b/packages/taler-wallet-webextension/src/components/HistoryItem.tsx @@ -0,0 +1,391 @@ +/* + 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 { + AmountJson, + Amounts, + AmountString, + AbsoluteTime, + Transaction, + TransactionType, + WithdrawalType, + TransactionMajorState, +} from "@gnu-taler/taler-util"; +import { h, VNode } from "preact"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Avatar } from "../mui/Avatar.js"; +import { Pages } from "../NavigationBar.js"; +import { assertUnreachable } from "../utils/index.js"; +import { + Column, + ExtraLargeText, + HistoryRow, + LargeText, + LightText, + SmallLightText, +} from "./styled/index.js"; +import { Time } from "./Time.js"; + +export function HistoryItem(props: { tx: Transaction }): VNode { + const tx = props.tx; + const { i18n } = useTranslationContext(); + /** + * + */ + switch (tx.type) { + case TransactionType.Withdrawal: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + title={new URL(tx.exchangeBaseUrl).hostname} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"W"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? tx.withdrawalDetails.type === + WithdrawalType.TalerBankIntegrationApi + ? !tx.withdrawalDetails.confirmed + ? i18n.str`Need approval in the Bank` + : i18n.str`Exchange is waiting the wire transfer` + : tx.withdrawalDetails.type === WithdrawalType.ManualTransfer + ? i18n.str`Exchange is waiting the wire transfer` + : "" //pending but no message + : undefined + } + /> + ); + case TransactionType.InternalWithdrawal: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + title={new URL(tx.exchangeBaseUrl).hostname} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"I"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? tx.withdrawalDetails.type === + WithdrawalType.TalerBankIntegrationApi + ? !tx.withdrawalDetails.confirmed + ? i18n.str`Need approval in the Bank` + : i18n.str`Exchange is waiting the wire transfer` + : tx.withdrawalDetails.type === WithdrawalType.ManualTransfer + ? i18n.str`Exchange is waiting the wire transfer` + : "" //pending but no message + : undefined + } + /> + ); + case TransactionType.Payment: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"debit"} + title={tx.info.merchant.name} + subtitle={tx.info.summary} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"P"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Payment in progress` + : undefined + } + /> + ); + case TransactionType.Refund: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + subtitle={tx.paymentInfo ? tx.paymentInfo.summary : undefined} //FIXME: DD37 wallet-core is not returning this value + title={ + tx.paymentInfo + ? tx.paymentInfo.merchant.name + : "--unknown merchant--" + } //FIXME: DD37 wallet-core is not returning this value + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"R"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Executing refund...` + : undefined + } + /> + ); + case TransactionType.Tip: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + title={new URL(tx.merchantBaseUrl).hostname} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"T"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Grabbing the tipping...` + : undefined + } + /> + ); + case TransactionType.Refresh: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + title={"Refresh"} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"R"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Refreshing coins...` + : undefined + } + /> + ); + case TransactionType.Deposit: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"debit"} + title={tx.targetPaytoUri} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"D"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Deposit in progress` + : undefined + } + /> + ); + case TransactionType.PeerPullCredit: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + title={tx.info.summary || "Invoice"} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"I"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Waiting to be paid` + : undefined + } + /> + ); + case TransactionType.PeerPullDebit: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"debit"} + title={tx.info.summary || "Invoice"} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"I"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Payment in progress` + : undefined + } + /> + ); + case TransactionType.PeerPushCredit: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"credit"} + title={tx.info.summary || "Transfer"} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"T"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Receiving the transfer` + : undefined + } + /> + ); + case TransactionType.PeerPushDebit: + return ( + <Layout + id={tx.transactionId} + amount={tx.amountEffective} + debitCreditIndicator={"debit"} + title={tx.info.summary || "Transfer"} + timestamp={AbsoluteTime.fromPreciseTimestamp(tx.timestamp)} + iconPath={"T"} + currentState={tx.txState.major} + description={ + tx.txState.major === TransactionMajorState.Pending + ? i18n.str`Waiting to be received` + : undefined + } + /> + ); + default: { + assertUnreachable(tx); + } + } +} + +function Layout(props: LayoutProps): VNode { + const { i18n } = useTranslationContext(); + return ( + <HistoryRow + href={Pages.balanceTransaction({ tid: props.id })} + style={{ + backgroundColor: + props.currentState === TransactionMajorState.Pending || + props.currentState === TransactionMajorState.Dialog + ? "lightcyan" + : props.currentState === TransactionMajorState.Failed + ? "#ff000040" + : props.currentState === TransactionMajorState.Aborted || + props.currentState === TransactionMajorState.Aborting + ? "#00000010" + : "inherit", + alignItems: "center", + }} + > + <Avatar + style={{ + border: "solid gray 1px", + color: "gray", + boxSizing: "border-box", + }} + > + {props.iconPath} + </Avatar> + <Column> + <LargeText> + <div>{props.title}</div> + {props.subtitle && ( + <div style={{ color: "gray", fontSize: "medium", marginTop: 5 }}> + {props.subtitle} + </div> + )} + </LargeText> + {props.description && ( + <LightText style={{ marginTop: 5, marginBottom: 5 }}> + <i18n.Translate>{props.description}</i18n.Translate> + </LightText> + )} + <SmallLightText style={{ marginTop: 5 }}> + <Time timestamp={props.timestamp} format="HH:mm" /> + </SmallLightText> + </Column> + <TransactionAmount + currentState={props.currentState} + amount={Amounts.parseOrThrow(props.amount)} + debitCreditIndicator={props.debitCreditIndicator} + /> + </HistoryRow> + ); +} + +interface LayoutProps { + debitCreditIndicator: "debit" | "credit" | "unknown"; + amount: AmountString | "unknown"; + timestamp: AbsoluteTime; + title: string; + subtitle?: string; + id: string; + iconPath: string; + currentState: TransactionMajorState; + description?: string; +} + +interface TransactionAmountProps { + debitCreditIndicator: "debit" | "credit" | "unknown"; + amount: AmountJson; + currentState: TransactionMajorState; +} + +function TransactionAmount(props: TransactionAmountProps): VNode { + const { i18n } = useTranslationContext(); + let sign: string; + switch (props.debitCreditIndicator) { + case "credit": + sign = "+"; + break; + case "debit": + sign = "-"; + break; + case "unknown": + sign = ""; + } + return ( + <Column + style={{ + textAlign: "center", + color: + props.currentState !== TransactionMajorState.Done + ? "gray" + : sign === "+" + ? "darkgreen" + : sign === "-" + ? "darkred" + : undefined, + }} + > + <ExtraLargeText> + {sign} + {Amounts.stringifyValue(props.amount, 2)} + </ExtraLargeText> + {props.currentState === TransactionMajorState.Aborted ? ( + <div + style={{ + color: "black", + border: "1px black solid", + borderRadius: 8, + padding: 4, + }} + > + <i18n.Translate>ABORTED</i18n.Translate> + </div> + ) : props.currentState === TransactionMajorState.Failed ? ( + <div + style={{ + color: "red", + border: "1px darkred solid", + borderRadius: 8, + padding: 4, + }} + > + <i18n.Translate>FAILED</i18n.Translate> + </div> + ) : undefined} + </Column> + ); +} |