/* 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 */ import { Amounts, Balance, NotificationType, Transaction, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { ErrorAlertView } from "../components/CurrentAlerts.js"; import { Loading } from "../components/Loading.js"; import { CenteredBoldText, CenteredText, DateSeparator, NiceSelect, } from "../components/styled/index.js"; import { Time } from "../components/Time.js"; import { TransactionItem } from "../components/TransactionItem.js"; import { alertFromError, useAlertContext } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; import { NoBalanceHelp } from "../popup/NoBalanceHelp.js"; import DownloadIcon from "../svg/download_24px.svg"; import UploadIcon from "../svg/upload_24px.svg"; interface Props { currency?: string; goToWalletDeposit: (currency: string) => Promise; goToWalletManualWithdraw: (currency?: string) => Promise; } export function HistoryPage({ currency, goToWalletManualWithdraw, goToWalletDeposit, }: Props): VNode { const { i18n } = useTranslationContext(); const api = useBackendContext(); const state = useAsyncAsHook(async () => ({ b: await api.wallet.call(WalletApiOperation.GetBalances, {}), tx: await api.wallet.call(WalletApiOperation.GetTransactions, {}), })); useEffect(() => { return api.listener.onUpdateNotification( [NotificationType.WithdrawGroupFinished], state?.retry, ); }); if (!state) { return ; } if (state.hasError) { return ( ); } return ( ); } const term = 1000 * 60 * 60 * 24; function normalizeToDay(x: number): number { return Math.round(x / term) * term; } export function HistoryView({ defaultCurrency, transactions, balances, goToWalletManualWithdraw, goToWalletDeposit, }: { goToWalletDeposit: (currency: string) => Promise; goToWalletManualWithdraw: (currency?: string) => Promise; defaultCurrency?: string; transactions: Transaction[]; balances: Balance[]; }): VNode { const { i18n } = useTranslationContext(); const { pushAlertOnError } = useAlertContext(); const transactionByCurrency = transactions.reduce((prev, cur) => { const c = Amounts.parseOrThrow(cur.amountEffective).currency; if (!prev[c]) { prev[c] = []; } prev[c].push(cur); return prev; }, {} as Record); const currencies = balances .filter((b) => { const av = Amounts.parseOrThrow(b.available); return ( Amounts.isNonZero(av) || (transactionByCurrency[av.currency] && transactionByCurrency[av.currency].length > 0) ); }) .map((b) => b.available.split(":")[0]); const defaultCurrencyIndex = currencies.findIndex( (c) => c === defaultCurrency, ); const [currencyIndex, setCurrencyIndex] = useState( defaultCurrencyIndex === -1 ? 0 : defaultCurrencyIndex, ); const selectedCurrency = currencies.length > 0 ? currencies[currencyIndex] : undefined; const currencyAmount = balances[currencyIndex] ? Amounts.jsonifyAmount(balances[currencyIndex].available) : undefined; const ts = selectedCurrency === undefined ? [] : transactionByCurrency[selectedCurrency] ?? []; const byDate = ts.reduce((rv, x) => { const theDate = x.timestamp.t_s === "never" ? 0 : normalizeToDay(x.timestamp.t_s * 1000); if (theDate) { (rv[theDate] = rv[theDate] || []).push(x); } return rv; }, {} as { [x: string]: Transaction[] }); const datesWithTransaction = Object.keys(byDate); if (balances.length === 0 || !selectedCurrency) { return ( ); } return (
{currencies.length === 1 ? ( {selectedCurrency} ) : ( )} {currencyAmount && ( {Amounts.stringifyValue(currencyAmount, 2)} )}
{currencyAmount && Amounts.isNonZero(currencyAmount) && ( )}
{datesWithTransaction.length === 0 ? (
Your transaction history is empty for this currency.
) : (
{datesWithTransaction.map((d, i) => { return ( {byDate[d].map((tx, i) => ( ))} ); })}
)}
); }