summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet/History.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet/History.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx257
1 files changed, 181 insertions, 76 deletions
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 233bd8f28..f81e6db9f 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -20,7 +20,7 @@ import {
NotificationType,
ScopeType,
Transaction,
- WalletBalance
+ WalletBalance,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
@@ -45,31 +45,39 @@ import { Button } from "../mui/Button.js";
import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
import DownloadIcon from "../svg/download_24px.inline.svg";
import UploadIcon from "../svg/upload_24px.inline.svg";
+import { TextField } from "../mui/TextField.js";
+import { TextFieldHandler } from "../mui/handlers.js";
interface Props {
currency?: string;
+ search?: boolean;
goToWalletDeposit: (currency: string) => Promise<void>;
goToWalletManualWithdraw: (currency?: string) => Promise<void>;
}
export function HistoryPage({
- currency,
+ currency: _c,
+ search: showSearch,
goToWalletManualWithdraw,
goToWalletDeposit,
}: Props): VNode {
const { i18n } = useTranslationContext();
const api = useBackendContext();
const [balanceIndex, setBalanceIndex] = useState<number>(0);
+ const [search, setSearch] = useState<string>();
+
const [settings] = useSettings();
const state = useAsyncAsHook(async () => {
- const b = await api.wallet.call(WalletApiOperation.GetBalances, {})
- const balance = b.balances.length > 0 ? b.balances[balanceIndex] : undefined
+ const b = await api.wallet.call(WalletApiOperation.GetBalances, {});
+ const balance =
+ b.balances.length > 0 ? b.balances[balanceIndex] : undefined;
const tx = await api.wallet.call(WalletApiOperation.GetTransactions, {
- scopeInfo: balance?.scopeInfo,
+ scopeInfo: showSearch ? undefined : balance?.scopeInfo,
sort: "descending",
includeRefreshes: settings.showRefeshTransactions,
- })
- return { b, tx }
- }, [balanceIndex]);
+ search,
+ });
+ return { b, tx };
+ }, [balanceIndex, search]);
useEffect(() => {
return api.listener.onUpdateNotification(
@@ -104,14 +112,48 @@ export function HistoryPage({
/>
);
}
+
+ const byDate = state.response.tx.transactions.reduce(
+ (rv, x) => {
+ const startDay =
+ x.timestamp.t_s === "never"
+ ? 0
+ : startOfDay(x.timestamp.t_s * 1000).getTime();
+ if (startDay) {
+ if (!rv[startDay]) {
+ rv[startDay] = [];
+ // datesWithTransaction.push(String(startDay));
+ }
+ rv[startDay].push(x);
+ }
+
+ return rv;
+ },
+ {} as { [x: string]: Transaction[] },
+ );
+
+ if (showSearch) {
+ return (
+ <FilteredHistoryView
+ search={{
+ value: search ?? "",
+ onInput: pushAlertOnError(async (d: string) => {
+ setSearch(d);
+ }),
+ }}
+ transactionsByDate={byDate}
+ />
+ );
+ }
+
return (
<HistoryView
balanceIndex={balanceIndex}
- changeBalanceIndex={b => setBalanceIndex(b)}
+ changeBalanceIndex={(b) => setBalanceIndex(b)}
balances={state.response.b.balances}
goToWalletManualWithdraw={goToWalletManualWithdraw}
goToWalletDeposit={goToWalletDeposit}
- transactions={state.response.tx.transactions}
+ transactionsByDate={byDate}
/>
);
}
@@ -120,15 +162,15 @@ export function HistoryView({
balances,
balanceIndex,
changeBalanceIndex,
- transactions,
+ transactionsByDate,
goToWalletManualWithdraw,
goToWalletDeposit,
}: {
- balanceIndex: number,
+ balanceIndex: number;
changeBalanceIndex: (s: number) => void;
goToWalletDeposit: (currency: string) => Promise<void>;
goToWalletManualWithdraw: (currency?: string) => Promise<void>;
- transactions: Transaction[];
+ transactionsByDate: Record<string, Transaction[]>;
balances: WalletBalance[];
}): VNode {
const { i18n } = useTranslationContext();
@@ -139,20 +181,7 @@ export function HistoryView({
? Amounts.jsonifyAmount(balance.available)
: undefined;
- const datesWithTransaction: string[] = [];
- const byDate = transactions.reduce((rv, x) => {
- const startDay =
- x.timestamp.t_s === "never" ? 0 : startOfDay(x.timestamp.t_s * 1000).getTime();
- if (startDay) {
- if (!rv[startDay]) {
- rv[startDay] = [];
- datesWithTransaction.push(String(startDay));
- }
- rv[startDay].push(x);
- }
-
- return rv;
- }, {} as { [x: string]: Transaction[] });
+ const datesWithTransaction: string[] = Object.keys(transactionsByDate);
return (
<Fragment>
@@ -163,62 +192,19 @@ export function HistoryView({
flexWrap: "wrap",
alignItems: "center",
justifyContent: "space-between",
+ marginRight: 20,
}}
>
- <div
- style={{
- width: "fit-content",
- display: "flex",
- }}
- >
- {balances.length === 1 ? (
- <CenteredText style={{ fontSize: "x-large", margin: 8 }}>
- {balance.scopeInfo.currency}
- </CenteredText>
- ) : (
- <NiceSelect style={{ flexDirection: "column" }}>
- <select
- style={{
- fontSize: "x-large",
- }}
- value={balanceIndex}
- onChange={(e) => {
- changeBalanceIndex(Number.parseInt(e.currentTarget.value, 10));
- }}
- >
- {balances.map((entry, index) => {
- return (
- <option value={index} key={entry.scopeInfo.currency}>
- {entry.scopeInfo.currency}
- </option>
- );
- })}
- </select>
- <div style={{ fontSize: "small", color: "grey" }}>
- {balance.scopeInfo.type === ScopeType.Exchange || balance.scopeInfo.type === ScopeType.Auditor ? balance.scopeInfo.url : undefined}
- </div>
- </NiceSelect>
- )}
- {available && (
- <CenteredBoldText
- style={{
- display: "inline-block",
- fontSize: "x-large",
- margin: 8,
- }}
- >
- {Amounts.stringifyValue(available, 2)}
- </CenteredBoldText>
- )}
- </div>
<div>
<Button
tooltip="Transfer money to the wallet"
startIcon={DownloadIcon}
variant="contained"
- onClick={() => goToWalletManualWithdraw(balance.scopeInfo.currency)}
+ onClick={() =>
+ goToWalletManualWithdraw(balance.scopeInfo.currency)
+ }
>
- <i18n.Translate>Add</i18n.Translate>
+ <i18n.Translate>Receive</i18n.Translate>
</Button>
{available && Amounts.isNonZero(available) && (
<Button
@@ -232,6 +218,125 @@ export function HistoryView({
</Button>
)}
</div>
+ <div style={{ display: "flex", flexDirection: "column" }}>
+ <h3 style={{ marginBottom: 0 }}>Balance</h3>
+ <div
+ style={{
+ width: "fit-content",
+ display: "flex",
+ }}
+ >
+ {balances.length === 1 ? (
+ <CenteredText style={{ fontSize: "x-large", margin: 8 }}>
+ {balance.scopeInfo.currency}
+ </CenteredText>
+ ) : (
+ <NiceSelect style={{ flexDirection: "column" }}>
+ <select
+ style={{
+ fontSize: "x-large",
+ }}
+ value={balanceIndex}
+ onChange={(e) => {
+ changeBalanceIndex(
+ Number.parseInt(e.currentTarget.value, 10),
+ );
+ }}
+ >
+ {balances.map((entry, index) => {
+ return (
+ <option value={index} key={entry.scopeInfo.currency}>
+ {entry.scopeInfo.currency}
+ </option>
+ );
+ })}
+ </select>
+ <div style={{ fontSize: "small", color: "grey" }}>
+ {balance.scopeInfo.type === ScopeType.Exchange ||
+ balance.scopeInfo.type === ScopeType.Auditor
+ ? balance.scopeInfo.url
+ : undefined}
+ </div>
+ </NiceSelect>
+ )}
+ {available && (
+ <CenteredBoldText
+ style={{
+ display: "inline-block",
+ fontSize: "x-large",
+ margin: 8,
+ }}
+ >
+ {Amounts.stringifyValue(available, 2)}
+ </CenteredBoldText>
+ )}
+ </div>
+ </div>
+ </div>
+ </section>
+ {datesWithTransaction.length === 0 ? (
+ <section>
+ <i18n.Translate>
+ Your transaction history is empty for this currency.
+ </i18n.Translate>
+ </section>
+ ) : (
+ <section>
+ {datesWithTransaction.map((d, i) => {
+ return (
+ <Fragment key={i}>
+ <DateSeparator>
+ <Time
+ timestamp={AbsoluteTime.fromMilliseconds(
+ Number.parseInt(d, 10),
+ )}
+ format="dd MMMM yyyy"
+ />
+ </DateSeparator>
+ {transactionsByDate[d].map((tx, i) => (
+ <HistoryItem key={i} tx={tx} />
+ ))}
+ </Fragment>
+ );
+ })}
+ </section>
+ )}
+ </Fragment>
+ );
+}
+
+export function FilteredHistoryView({
+ search,
+ transactionsByDate,
+}: {
+ search: TextFieldHandler;
+ transactionsByDate: Record<string, Transaction[]>;
+}): VNode {
+ const { i18n } = useTranslationContext();
+
+ const datesWithTransaction: string[] = Object.keys(transactionsByDate);
+
+ return (
+ <Fragment>
+ <section>
+ <div
+ style={{
+ display: "flex",
+ flexWrap: "wrap",
+ alignItems: "center",
+ justifyContent: "space-between",
+ marginRight: 20,
+ }}
+ >
+ <TextField
+ label="Search"
+ variant="filled"
+ error={search.error}
+ required
+ fullWidth
+ value={search.value}
+ onChange={search.onInput}
+ />
</div>
</section>
{datesWithTransaction.length === 0 ? (
@@ -253,7 +358,7 @@ export function HistoryView({
format="dd MMMM yyyy"
/>
</DateSeparator>
- {byDate[d].map((tx, i) => (
+ {transactionsByDate[d].map((tx, i) => (
<HistoryItem key={i} tx={tx} />
))}
</Fragment>