towards a nicer transaction history
This commit is contained in:
parent
d6409f185d
commit
9cd1062f1b
@ -332,6 +332,7 @@ export async function getTransactions(
|
||||
TransactionType.Tip,
|
||||
tipRecord.walletTipId,
|
||||
),
|
||||
merchantBaseUrl: tipRecord.merchantBaseUrl,
|
||||
error: tipRecord.lastError,
|
||||
});
|
||||
});
|
||||
|
@ -288,6 +288,8 @@ interface TransactionTip extends TransactionCommon {
|
||||
|
||||
// Amount will be (or was) added to the wallet's balance after fees and refreshing
|
||||
amountEffective: AmountString;
|
||||
|
||||
merchantBaseUrl: string;
|
||||
}
|
||||
|
||||
// A transaction shown for refreshes that are not associated to other transactions
|
||||
|
@ -36,6 +36,8 @@ import {
|
||||
TransactionsResponse,
|
||||
Transaction,
|
||||
TransactionType,
|
||||
AmountString,
|
||||
Timestamp,
|
||||
} from "taler-wallet-core";
|
||||
|
||||
import { abbrev, renderAmount, PageLink } from "../renderHtml";
|
||||
@ -301,19 +303,161 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
}
|
||||
}
|
||||
|
||||
function Icon({ l }: { l: string }): JSX.Element {
|
||||
return <div className={"icon"}>{l}</div>;
|
||||
interface TransactionAmountProps {
|
||||
debitCreditIndicator: "debit" | "credit" | "unknown";
|
||||
amount: AmountString | "unknown";
|
||||
pending: boolean;
|
||||
}
|
||||
|
||||
function formatAndCapitalize(text: string): string {
|
||||
text = text.replace("-", " ");
|
||||
text = text.replace(/^./, text[0].toUpperCase());
|
||||
return text;
|
||||
function TransactionAmount(props: TransactionAmountProps): JSX.Element {
|
||||
const [currency, amount] = props.amount.split(":");
|
||||
let sign: string;
|
||||
switch (props.debitCreditIndicator) {
|
||||
case "credit":
|
||||
sign = "+";
|
||||
break;
|
||||
case "debit":
|
||||
sign = "-";
|
||||
break;
|
||||
case "unknown":
|
||||
sign = "";
|
||||
}
|
||||
const style: React.CSSProperties = {
|
||||
marginLeft: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
alignSelf: "center"
|
||||
};
|
||||
if (props.pending) {
|
||||
style.color = "gray";
|
||||
}
|
||||
return (
|
||||
<div style={{ ...style }}>
|
||||
<div style={{ fontSize: "x-large" }}>
|
||||
{sign}
|
||||
{amount}
|
||||
</div>
|
||||
<div>{currency}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface TransactionLayoutProps {
|
||||
debitCreditIndicator: "debit" | "credit" | "unknown";
|
||||
amount: AmountString | "unknown";
|
||||
timestamp: Timestamp;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
iconPath: string;
|
||||
pending: boolean;
|
||||
}
|
||||
|
||||
function TransactionLayout(props: TransactionLayoutProps): JSX.Element {
|
||||
const date = new Date(props.timestamp.t_ms);
|
||||
const dateStr = date.toLocaleString([], {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
} as any);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
border: "1px solid gray",
|
||||
borderRadius: "0.5em",
|
||||
margin: "0.5em 0",
|
||||
justifyContent: "space-between",
|
||||
padding: "0.5em",
|
||||
}}
|
||||
>
|
||||
<img src={props.iconPath} />
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", marginLeft: "1em" }}
|
||||
>
|
||||
<div style={{ fontSize: "small", color: "gray" }}>{dateStr}</div>
|
||||
<div style={{ fontVariant: "small-caps", fontSize: "x-large" }}>
|
||||
<span>{props.title}</span>
|
||||
{props.pending ? (
|
||||
<span style={{ color: "darkblue" }}> (Pending)</span>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div>{props.subtitle}</div>
|
||||
</div>
|
||||
<TransactionAmount
|
||||
pending={props.pending}
|
||||
amount={props.amount}
|
||||
debitCreditIndicator={props.debitCreditIndicator}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
const tx = props.tx;
|
||||
return <pre>{JSON.stringify(tx)}</pre>
|
||||
switch (tx.type) {
|
||||
case TransactionType.Withdrawal:
|
||||
return (
|
||||
<TransactionLayout
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Withdrawal"
|
||||
subtitle={`via ${tx.exchangeBaseUrl}`}
|
||||
timestamp={tx.timestamp}
|
||||
iconPath="/static/img/ri-bank-line.svg"
|
||||
pending={tx.pending}
|
||||
></TransactionLayout>
|
||||
);
|
||||
case TransactionType.Payment:
|
||||
return (
|
||||
<TransactionLayout
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"debit"}
|
||||
title="Payment"
|
||||
subtitle={tx.info.summary}
|
||||
timestamp={tx.timestamp}
|
||||
iconPath="/static/img/ri-shopping-cart-line.svg"
|
||||
pending={tx.pending}
|
||||
></TransactionLayout>
|
||||
);
|
||||
case TransactionType.Refund:
|
||||
return (
|
||||
<TransactionLayout
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Refund"
|
||||
subtitle={tx.info.summary}
|
||||
timestamp={tx.timestamp}
|
||||
iconPath="/static/img/ri-refund-2-line.svg"
|
||||
pending={tx.pending}
|
||||
></TransactionLayout>
|
||||
);
|
||||
case TransactionType.Tip:
|
||||
return (
|
||||
<TransactionLayout
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Tip"
|
||||
subtitle={`from ${new URL(tx.merchantBaseUrl).hostname}`}
|
||||
timestamp={tx.timestamp}
|
||||
iconPath="/static/img/ri-hand-heart-line.svg"
|
||||
pending={tx.pending}
|
||||
></TransactionLayout>
|
||||
);
|
||||
case TransactionType.Refresh:
|
||||
return (
|
||||
<TransactionLayout
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Refresh"
|
||||
subtitle={`via exchange ${tx.exchangeBaseUrl}`}
|
||||
timestamp={tx.timestamp}
|
||||
iconPath="/static/img/ri-refresh-line.svg"
|
||||
pending={tx.pending}
|
||||
></TransactionLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function WalletHistory(props: any): JSX.Element {
|
||||
@ -334,9 +478,11 @@ function WalletHistory(props: any): JSX.Element {
|
||||
return <div>Loading ...</div>;
|
||||
}
|
||||
|
||||
const txs = [...transactions.transactions].reverse();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{transactions.transactions.map((tx) => (
|
||||
{txs.map((tx) => (
|
||||
<TransactionItem tx={tx} />
|
||||
))}
|
||||
</div>
|
||||
@ -379,10 +525,7 @@ function WalletDebug(props: any): JSX.Element {
|
||||
return (
|
||||
<div>
|
||||
<p>Debug tools:</p>
|
||||
<button onClick={openExtensionPage("/popup.html")}>wallet tab</button>
|
||||
<button onClick={openExtensionPage("/benchmark.html")}>benchmark</button>
|
||||
<button onClick={openExtensionPage("/show-db.html")}>show db</button>
|
||||
<button onClick={openExtensionPage("/tree.html")}>show tree</button>
|
||||
<button onClick={openExtensionPage("/static/popup.html")}>wallet tab</button>
|
||||
<br />
|
||||
<button onClick={confirmReset}>reset</button>
|
||||
<button onClick={reload}>reload chrome extension</button>
|
||||
|
15
packages/taler-wallet-webextension/static/img/COPYRIGHT
Normal file
15
packages/taler-wallet-webextension/static/img/COPYRIGHT
Normal file
@ -0,0 +1,15 @@
|
||||
# Icon Copyright Info
|
||||
|
||||
## Remix Icons
|
||||
|
||||
https://github.com/Remix-Design/RemixIcon
|
||||
|
||||
Remix Icon is licensed under the Apache License Version 2.0. Feel free to use
|
||||
these icons in your products and distribute them. We would be very grateful if
|
||||
you mention "Remix Icon" in your product info, but it's not required. The only
|
||||
thing we ask is that these icons are not for sale.
|
||||
|
||||
|
||||
### Used Icons
|
||||
|
||||
* ri-*.svg
|
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2 20h20v2H2v-2zm2-8h2v7H4v-7zm5 0h2v7H9v-7zm4 0h2v7h-2v-7zm5 0h2v7h-2v-7zM2 7l10-5 10 5v4H2V7zm2 1.236V9h16v-.764l-8-4-8 4zM12 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></svg>
|
After Width: | Height: | Size: 297 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 15h2v2h-2v-2zm2-1.645V14h-2v-1.5a1 1 0 0 1 1-1 1.5 1.5 0 1 0-1.471-1.794l-1.962-.393A3.501 3.501 0 1 1 13 13.355zM15 4H5v16h14V8h-4V4zM3 2.992C3 2.444 3.447 2 3.999 2H16l5 5v13.993A1 1 0 0 1 20.007 22H3.993A1 1 0 0 1 3 21.008V2.992z"/></svg>
|
After Width: | Height: | Size: 375 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 9a1 1 0 0 1 1 1 6.97 6.97 0 0 1 4.33 1.5h2.17c1.332 0 2.53.579 3.353 1.499L19 13a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.79 0-5.15-.603-7.06-1.658A.998.998 0 0 1 5 20H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h3zm1.001 3L6 17.021l.045.033C7.84 18.314 10.178 19 13 19c3.004 0 5.799-1.156 7.835-3.13l.133-.133-.12-.1a2.994 2.994 0 0 0-1.643-.63L19 15l-2.112-.001c.073.322.112.657.112 1.001v1H8v-2l6.79-.001-.034-.078a2.501 2.501 0 0 0-2.092-1.416L12.5 13.5H9.57A4.985 4.985 0 0 0 6.002 12zM4 11H3v7h1v-7zm9.646-7.425L14 3.93l.354-.354a2.5 2.5 0 1 1 3.535 3.536L14 11l-3.89-3.89a2.5 2.5 0 1 1 3.536-3.535zm-2.12 1.415a.5.5 0 0 0-.06.637l.058.069L14 8.17l2.476-2.474a.5.5 0 0 0 .058-.638l-.058-.07a.5.5 0 0 0-.638-.057l-.07.058-1.769 1.768-1.767-1.77-.068-.056a.5.5 0 0 0-.638.058z"/></svg>
|
After Width: | Height: | Size: 924 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5.463 4.433A9.961 9.961 0 0 1 12 2c5.523 0 10 4.477 10 10 0 2.136-.67 4.116-1.81 5.74L17 12h3A8 8 0 0 0 6.46 6.228l-.997-1.795zm13.074 15.134A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12c0-2.136.67-4.116 1.81-5.74L7 12H4a8 8 0 0 0 13.54 5.772l.997 1.795z"/></svg>
|
After Width: | Height: | Size: 396 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5.671 4.257c3.928-3.219 9.733-2.995 13.4.672 3.905 3.905 3.905 10.237 0 14.142-3.905 3.905-10.237 3.905-14.142 0A9.993 9.993 0 0 1 2.25 9.767l.077-.313 1.934.51a8 8 0 1 0 3.053-4.45l-.221.166 1.017 1.017-4.596 1.06 1.06-4.596 1.096 1.096zM13 6v2h2.5v2H10a.5.5 0 0 0-.09.992L10 11h4a2.5 2.5 0 1 1 0 5h-1v2h-2v-2H8.5v-2H14a.5.5 0 0 0 .09-.992L14 13h-4a2.5 2.5 0 1 1 0-5h1V6h2z"/></svg>
|
After Width: | Height: | Size: 514 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 16V4H2V2h3a1 1 0 0 1 1 1v12h12.438l2-8H8V5h13.72a1 1 0 0 1 .97 1.243l-2.5 10a1 1 0 0 1-.97.757H5a1 1 0 0 1-1-1zm2 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm12 0a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></svg>
|
After Width: | Height: | Size: 320 B |
Loading…
Reference in New Issue
Block a user