/*
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
*/
import {
AbsoluteTime,
AmountLike,
Amounts,
NotificationType,
parsePaytoUri,
Transaction,
TransactionType,
WithdrawalType,
} from "@gnu-taler/taler-util";
import { differenceInSeconds } from "date-fns";
import { ComponentChildren, Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import emptyImg from "../../static/img/empty.png";
import { Amount } from "../components/Amount.js";
import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType.js";
import { ErrorTalerOperation } from "../components/ErrorTalerOperation.js";
import { Loading } from "../components/Loading.js";
import { LoadingError } from "../components/LoadingError.js";
import { Part } from "../components/Part.js";
import {
Button,
ButtonDestructive,
ButtonPrimary,
CenteredDialog,
InfoBox,
ListOfProducts,
Overlay,
RowBorderGray,
SmallLightText,
SubTitle,
WarningBox,
} from "../components/styled/index.js";
import { Time } from "../components/Time.js";
import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import * as wxApi from "../wxApi.js";
interface Props {
tid: string;
goToWalletHistory: (currency?: string) => void;
}
export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
const { i18n } = useTranslationContext();
async function getTransaction(): Promise {
const res = await wxApi.getTransactions();
const ts = res.transactions.filter((t) => t.transactionId === tid);
if (ts.length > 1) throw Error("more than one transaction with this id");
if (ts.length === 1) {
return ts[0];
}
throw Error("no transaction found");
}
const state = useAsyncAsHook(getTransaction, [
NotificationType.WithdrawGroupFinished,
]);
if (!state) {
return ;
}
if (state.hasError) {
return (
Could not load the transaction information
}
error={state}
/>
);
}
const currency = Amounts.parse(state.response.amountRaw)?.currency;
return (
wxApi.deleteTransaction(tid).then(() => goToWalletHistory(currency))
}
onRetry={() =>
wxApi.retryTransaction(tid).then(() => goToWalletHistory(currency))
}
onBack={() => goToWalletHistory(currency)}
/>
);
}
export interface WalletTransactionProps {
transaction: Transaction;
onDelete: () => void;
onRetry: () => void;
onBack: () => void;
}
export function TransactionView({
transaction,
onDelete,
onRetry,
onBack,
}: WalletTransactionProps): VNode {
const [confirmBeforeForget, setConfirmBeforeForget] = useState(false);
function doCheckBeforeForget(): void {
if (
transaction.pending &&
transaction.type === TransactionType.Withdrawal
) {
setConfirmBeforeForget(true);
} else {
onDelete();
}
}
const { i18n } = useTranslationContext();
function TransactionTemplate({
children,
}: {
children: ComponentChildren;
}): VNode {
const showRetry =
transaction.error !== undefined ||
transaction.timestamp.t_s === "never" ||
(transaction.pending &&
differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) > 10);
return (
There was an error trying to complete the transaction
}
error={transaction?.error}
/>
{transaction.pending && (
This transaction is not completed
)}
{children}
);
}
if (transaction.type === TransactionType.Withdrawal) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
).amount;
return (
{confirmBeforeForget ? (
Caution!
If you have already wired money to the exchange you will loose
the chance to get the coins form it.
) : undefined}
Withdrawal
{transaction.pending ? (
transaction.withdrawalDetails.type ===
WithdrawalType.ManualTransfer ? (
}
exchangeBaseUrl={transaction.exchangeBaseUrl}
payto={parsePaytoUri(
transaction.withdrawalDetails.exchangePaytoUris[0],
)}
subject={transaction.withdrawalDetails.reservePub}
/>
Make sure to use the correct subject, otherwise the money
will not arrive in this wallet.
Total withdrawn}
text={}
kind="positive"
/>
Exchange fee}
text={}
kind="negative"
/>
) : (
{!transaction.withdrawalDetails.confirmed &&
transaction.withdrawalDetails.bankConfirmationUrl ? (
The bank is waiting for confirmation. Go to the
bank site
) : undefined}
{transaction.withdrawalDetails.confirmed && (
Waiting for the coins to arrive
)}
Total withdrawn}
text={}
kind="positive"
/>
Chosen amount}
text={}
kind="neutral"
/>
Exchange fee}
text={}
kind="negative"
/>
)
) : (
Total withdrawn}
text={}
kind="positive"
/>
Chosen amount}
text={}
kind="neutral"
/>
Exchange fee}
text={}
kind="negative"
/>
)}
Exchange}
text={new URL(transaction.exchangeBaseUrl).hostname}
kind="neutral"
/>
);
}
const showLargePic = (): void => {
return;
};
if (transaction.type === TransactionType.Payment) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountEffective),
Amounts.parseOrThrow(transaction.amountRaw),
).amount;
return (
Payment Total paid}
text={}
kind="negative"
/>
Purchase amount}
text={}
kind="neutral"
/>
Fee}
text={}
kind="negative"
/>
Merchant}
text={transaction.info.merchant.name}
kind="neutral"
/>
Purchase}
text={
transaction.info.fulfillmentUrl ? (
{transaction.info.summary}
) : (
transaction.info.summary
)
}
kind="neutral"
/>
Receipt}
text={`#${transaction.info.orderId}`}
kind="neutral"
/>