fix wrong fee calculation
This commit is contained in:
parent
5f31dad2d3
commit
03b12d2b27
@ -14,6 +14,7 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Amounts } from "@gnu-taler/taler-util";
|
||||
import { format } from "date-fns";
|
||||
import { h, VNode } from "preact";
|
||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||
@ -27,7 +28,11 @@ import { useTranslationContext } from "../../context/translation.js";
|
||||
import { Button } from "../../mui/Button.js";
|
||||
import { TextField } from "../../mui/TextField.js";
|
||||
import editIcon from "../../svg/edit_24px.svg";
|
||||
import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js";
|
||||
import {
|
||||
ExchangeDetails,
|
||||
getAmountWithFee,
|
||||
InvoiceDetails,
|
||||
} from "../../wallet/Transaction.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
export function ReadyView({
|
||||
@ -144,10 +149,7 @@ export function ReadyView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<InvoiceDetails
|
||||
amount={{
|
||||
effective: toBeReceived,
|
||||
raw: requestAmount,
|
||||
}}
|
||||
amount={getAmountWithFee(toBeReceived, requestAmount, "credit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -27,7 +27,11 @@ import { PaymentButtons } from "../../components/PaymentButtons.js";
|
||||
import { SuccessBox, WarningBox } from "../../components/styled/index.js";
|
||||
import { Time } from "../../components/Time.js";
|
||||
import { useTranslationContext } from "../../context/translation.js";
|
||||
import { MerchantDetails, PurchaseDetails } from "../../wallet/Transaction.js";
|
||||
import {
|
||||
getAmountWithFee,
|
||||
MerchantDetails,
|
||||
PurchaseDetails,
|
||||
} from "../../wallet/Transaction.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
type SupportedStates =
|
||||
@ -41,13 +45,10 @@ export function BaseView(state: SupportedStates): VNode {
|
||||
|
||||
const contractTerms: ContractTerms = state.payStatus.contractTerms;
|
||||
|
||||
const price = {
|
||||
raw: state.amount,
|
||||
effective:
|
||||
"amountEffective" in state.payStatus
|
||||
? Amounts.parseOrThrow(state.payStatus.amountEffective)
|
||||
: state.amount,
|
||||
};
|
||||
const effective =
|
||||
"amountEffective" in state.payStatus
|
||||
? Amounts.parseOrThrow(state.payStatus.amountEffective)
|
||||
: state.amount;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@ -68,7 +69,7 @@ export function BaseView(state: SupportedStates): VNode {
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<PurchaseDetails
|
||||
price={price}
|
||||
price={getAmountWithFee(effective, state.amount, "debit")}
|
||||
info={{
|
||||
...contractTerms,
|
||||
orderId: contractTerms.order_id,
|
||||
|
@ -14,6 +14,7 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Amounts } from "@gnu-taler/taler-util";
|
||||
import { format } from "date-fns";
|
||||
import { h, VNode } from "preact";
|
||||
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
||||
@ -23,7 +24,7 @@ import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||
import { useTranslationContext } from "../../context/translation.js";
|
||||
import { Button } from "../../mui/Button.js";
|
||||
import { TextField } from "../../mui/TextField.js";
|
||||
import { TransferDetails } from "../../wallet/Transaction.js";
|
||||
import { getAmountWithFee, TransferDetails } from "../../wallet/Transaction.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
export function ReadyView({
|
||||
@ -114,10 +115,7 @@ export function ReadyView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<TransferDetails
|
||||
amount={{
|
||||
effective: toBeReceived,
|
||||
raw: debitAmount,
|
||||
}}
|
||||
amount={getAmountWithFee(debitAmount, toBeReceived, "debit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -14,7 +14,7 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { ExchangeTosStatus } from "@gnu-taler/taler-util";
|
||||
import { Amounts, ExchangeTosStatus } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { Amount } from "../../components/Amount.js";
|
||||
@ -26,7 +26,11 @@ import { TermsOfService } from "../../components/TermsOfService/index.js";
|
||||
import { useTranslationContext } from "../../context/translation.js";
|
||||
import { Button } from "../../mui/Button.js";
|
||||
import editIcon from "../../svg/edit_24px.svg";
|
||||
import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js";
|
||||
import {
|
||||
ExchangeDetails,
|
||||
getAmountWithFee,
|
||||
WithdrawDetails,
|
||||
} from "../../wallet/Transaction.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
export function SuccessView(state: State.Success): VNode {
|
||||
@ -64,10 +68,11 @@ export function SuccessView(state: State.Success): VNode {
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<WithdrawDetails
|
||||
amount={{
|
||||
effective: state.toBeReceived,
|
||||
raw: state.chosenAmount,
|
||||
}}
|
||||
amount={getAmountWithFee(
|
||||
state.toBeReceived,
|
||||
state.chosenAmount,
|
||||
"credit",
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -584,26 +584,26 @@ function setAlertedIcon(): void {
|
||||
|
||||
interface OffscreenCanvasRenderingContext2D
|
||||
extends CanvasState,
|
||||
CanvasTransform,
|
||||
CanvasCompositing,
|
||||
CanvasImageSmoothing,
|
||||
CanvasFillStrokeStyles,
|
||||
CanvasShadowStyles,
|
||||
CanvasFilters,
|
||||
CanvasRect,
|
||||
CanvasDrawPath,
|
||||
CanvasUserInterface,
|
||||
CanvasText,
|
||||
CanvasDrawImage,
|
||||
CanvasImageData,
|
||||
CanvasPathDrawingStyles,
|
||||
CanvasTextDrawingStyles,
|
||||
CanvasPath {
|
||||
CanvasTransform,
|
||||
CanvasCompositing,
|
||||
CanvasImageSmoothing,
|
||||
CanvasFillStrokeStyles,
|
||||
CanvasShadowStyles,
|
||||
CanvasFilters,
|
||||
CanvasRect,
|
||||
CanvasDrawPath,
|
||||
CanvasUserInterface,
|
||||
CanvasText,
|
||||
CanvasDrawImage,
|
||||
CanvasImageData,
|
||||
CanvasPathDrawingStyles,
|
||||
CanvasTextDrawingStyles,
|
||||
CanvasPath {
|
||||
readonly canvas: OffscreenCanvas;
|
||||
}
|
||||
declare const OffscreenCanvasRenderingContext2D: {
|
||||
prototype: OffscreenCanvasRenderingContext2D;
|
||||
new(): OffscreenCanvasRenderingContext2D;
|
||||
new (): OffscreenCanvasRenderingContext2D;
|
||||
};
|
||||
|
||||
interface OffscreenCanvas extends EventTarget {
|
||||
@ -616,7 +616,7 @@ interface OffscreenCanvas extends EventTarget {
|
||||
}
|
||||
declare const OffscreenCanvas: {
|
||||
prototype: OffscreenCanvas;
|
||||
new(width: number, height: number): OffscreenCanvas;
|
||||
new (width: number, height: number): OffscreenCanvas;
|
||||
};
|
||||
|
||||
function createCanvas(size: number): OffscreenCanvas {
|
||||
|
@ -28,17 +28,13 @@ import {
|
||||
stringifyPaytoUri,
|
||||
TalerProtocolTimestamp,
|
||||
Transaction,
|
||||
TransactionDeposit,
|
||||
TransactionRefresh,
|
||||
TransactionRefund,
|
||||
TransactionTip,
|
||||
TransactionType,
|
||||
TranslatedString,
|
||||
WithdrawalType,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { styled } from "@linaria/react";
|
||||
import { differenceInSeconds, isAfter, isFuture, isPast } from "date-fns";
|
||||
import { differenceInSeconds, isPast } from "date-fns";
|
||||
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import emptyImg from "../../static/img/empty.png";
|
||||
@ -68,6 +64,7 @@ import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||
import { Button } from "../mui/Button.js";
|
||||
import { SafeHandler } from "../mui/handlers.js";
|
||||
import { Pages } from "../NavigationBar.js";
|
||||
import { assertUnreachable } from "../utils/index.js";
|
||||
|
||||
interface Props {
|
||||
tid: string;
|
||||
@ -392,9 +389,10 @@ export function TransactionView({
|
||||
const { i18n } = useTranslationContext();
|
||||
const { safely } = useAlertContext();
|
||||
|
||||
const raw = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
const effective = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
|
||||
if (transaction.type === TransactionType.Withdrawal) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
const chosen = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -406,7 +404,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Withdrawal`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="positive"
|
||||
>
|
||||
{transaction.exchangeBaseUrl}
|
||||
@ -417,7 +415,7 @@ export function TransactionView({
|
||||
.type === WithdrawalType.ManualTransfer ? (
|
||||
<Fragment>
|
||||
<BankDetailsByPaytoType
|
||||
amount={chosen}
|
||||
amount={raw}
|
||||
exchangeBaseUrl={transaction.exchangeBaseUrl}
|
||||
payto={parsePaytoUri(
|
||||
transaction.withdrawalDetails.exchangePaytoUris[0],
|
||||
@ -500,10 +498,7 @@ export function TransactionView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<WithdrawDetails
|
||||
amount={{
|
||||
effective: Amounts.parseOrThrow(transaction.amountEffective),
|
||||
raw: Amounts.parseOrThrow(transaction.amountRaw),
|
||||
}}
|
||||
amount={getAmountWithFee(effective, raw, "credit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@ -517,15 +512,9 @@ export function TransactionView({
|
||||
? undefined
|
||||
: Amounts.parseOrThrow(transaction.refundPending);
|
||||
|
||||
const price = {
|
||||
raw: Amounts.parseOrThrow(transaction.amountRaw),
|
||||
effective: Amounts.parseOrThrow(transaction.amountEffective),
|
||||
};
|
||||
const refund = {
|
||||
raw: Amounts.parseOrThrow(transaction.totalRefundRaw),
|
||||
effective: Amounts.parseOrThrow(transaction.totalRefundEffective),
|
||||
};
|
||||
const total = Amounts.sub(price.effective, refund.effective).amount;
|
||||
const effectiveRefund = Amounts.parseOrThrow(
|
||||
transaction.totalRefundEffective,
|
||||
);
|
||||
|
||||
return (
|
||||
<TransactionTemplate
|
||||
@ -537,7 +526,7 @@ export function TransactionView({
|
||||
>
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
total={total}
|
||||
total={effective}
|
||||
type={i18n.str`Payment`}
|
||||
kind="negative"
|
||||
>
|
||||
@ -632,8 +621,8 @@ export function TransactionView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<PurchaseDetails
|
||||
price={price}
|
||||
refund={refund}
|
||||
price={getAmountWithFee(effective, raw, "debit")}
|
||||
effectiveRefund={effectiveRefund}
|
||||
info={transaction.info}
|
||||
proposalId={transaction.proposalId}
|
||||
/>
|
||||
@ -645,7 +634,6 @@ export function TransactionView({
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Deposit) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
const payto = parsePaytoUri(transaction.targetPaytoUri);
|
||||
|
||||
const wireTime = AbsoluteTime.fromTimestamp(
|
||||
@ -663,7 +651,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Deposit`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="negative"
|
||||
>
|
||||
{!payto ? transaction.targetPaytoUri : <NicePayto payto={payto} />}
|
||||
@ -671,7 +659,11 @@ export function TransactionView({
|
||||
{payto && <PartPayto payto={payto} kind="neutral" />}
|
||||
<Part
|
||||
title={i18n.str`Details`}
|
||||
text={<DepositDetails transaction={transaction} />}
|
||||
text={
|
||||
<DepositDetails
|
||||
amount={getAmountWithFee(effective, raw, "debit")}
|
||||
/>
|
||||
}
|
||||
kind="neutral"
|
||||
/>
|
||||
{!shouldBeWired ? (
|
||||
@ -712,11 +704,6 @@ export function TransactionView({
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Refresh) {
|
||||
const total = Amounts.sub(
|
||||
Amounts.parseOrThrow(transaction.amountRaw),
|
||||
Amounts.parseOrThrow(transaction.amountEffective),
|
||||
).amount;
|
||||
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -728,22 +715,24 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Refresh`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="negative"
|
||||
>
|
||||
{transaction.exchangeBaseUrl}
|
||||
</Header>
|
||||
<Part
|
||||
title={i18n.str`Details`}
|
||||
text={<RefreshDetails transaction={transaction} />}
|
||||
text={
|
||||
<RefreshDetails
|
||||
amount={getAmountWithFee(effective, raw, "debit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</TransactionTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Tip) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -755,7 +744,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Tip`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="positive"
|
||||
>
|
||||
{transaction.merchantBaseUrl}
|
||||
@ -767,14 +756,15 @@ export function TransactionView({
|
||||
/> */}
|
||||
<Part
|
||||
title={i18n.str`Details`}
|
||||
text={<TipDetails transaction={transaction} />}
|
||||
text={
|
||||
<TipDetails amount={getAmountWithFee(effective, raw, "credit")} />
|
||||
}
|
||||
/>
|
||||
</TransactionTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Refund) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -786,7 +776,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Refund`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="positive"
|
||||
>
|
||||
{transaction.info.summary}
|
||||
@ -817,48 +807,17 @@ export function TransactionView({
|
||||
/>
|
||||
<Part
|
||||
title={i18n.str`Details`}
|
||||
text={<RefundDetails transaction={transaction} />}
|
||||
text={
|
||||
<RefundDetails
|
||||
amount={getAmountWithFee(effective, raw, "credit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</TransactionTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowQrWithCopy({ text }: { text: string }): VNode {
|
||||
const [showing, setShowing] = useState(false);
|
||||
async function copy(): Promise<void> {
|
||||
navigator.clipboard.writeText(text);
|
||||
}
|
||||
async function toggle(): Promise<void> {
|
||||
setShowing((s) => !s);
|
||||
}
|
||||
if (showing) {
|
||||
return (
|
||||
<div>
|
||||
<QR text={text} />
|
||||
<Button onClick={copy as SafeHandler<void>}>
|
||||
<i18n.Translate>copy</i18n.Translate>
|
||||
</Button>
|
||||
<Button onClick={toggle as SafeHandler<void>}>
|
||||
<i18n.Translate>hide qr</i18n.Translate>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div>{text.substring(0, 64)}...</div>
|
||||
<Button onClick={copy as SafeHandler<void>}>
|
||||
<i18n.Translate>copy</i18n.Translate>
|
||||
</Button>
|
||||
<Button onClick={toggle as SafeHandler<void>}>
|
||||
<i18n.Translate>show qr</i18n.Translate>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.PeerPullCredit) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -870,7 +829,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Credit`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="positive"
|
||||
>
|
||||
<i18n.Translate>Invoice</i18n.Translate>
|
||||
@ -900,10 +859,7 @@ export function TransactionView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<InvoiceDetails
|
||||
amount={{
|
||||
effective: Amounts.parseOrThrow(transaction.amountEffective),
|
||||
raw: Amounts.parseOrThrow(transaction.amountRaw),
|
||||
}}
|
||||
amount={getAmountWithFee(effective, raw, "credit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@ -912,7 +868,6 @@ export function TransactionView({
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.PeerPullDebit) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -924,7 +879,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Debit`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="negative"
|
||||
>
|
||||
<i18n.Translate>Invoice</i18n.Translate>
|
||||
@ -946,16 +901,14 @@ export function TransactionView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<InvoiceDetails
|
||||
amount={{
|
||||
effective: Amounts.parseOrThrow(transaction.amountEffective),
|
||||
raw: Amounts.parseOrThrow(transaction.amountRaw),
|
||||
}}
|
||||
amount={getAmountWithFee(effective, raw, "debit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</TransactionTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.PeerPushDebit) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
return (
|
||||
@ -998,10 +951,7 @@ export function TransactionView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<TransferDetails
|
||||
amount={{
|
||||
effective: Amounts.parseOrThrow(transaction.amountEffective),
|
||||
raw: Amounts.parseOrThrow(transaction.amountRaw),
|
||||
}}
|
||||
amount={getAmountWithFee(effective, raw, "debit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@ -1010,7 +960,6 @@ export function TransactionView({
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.PeerPushCredit) {
|
||||
const total = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
return (
|
||||
<TransactionTemplate
|
||||
transaction={transaction}
|
||||
@ -1022,7 +971,7 @@ export function TransactionView({
|
||||
<Header
|
||||
timestamp={transaction.timestamp}
|
||||
type={i18n.str`Credit`}
|
||||
total={total}
|
||||
total={effective}
|
||||
kind="positive"
|
||||
>
|
||||
<i18n.Translate>Transfer</i18n.Translate>
|
||||
@ -1044,17 +993,14 @@ export function TransactionView({
|
||||
title={i18n.str`Details`}
|
||||
text={
|
||||
<TransferDetails
|
||||
amount={{
|
||||
effective: Amounts.parseOrThrow(transaction.amountEffective),
|
||||
raw: Amounts.parseOrThrow(transaction.amountRaw),
|
||||
}}
|
||||
amount={getAmountWithFee(effective, raw, "credit")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</TransactionTemplate>
|
||||
);
|
||||
}
|
||||
return <div />;
|
||||
assertUnreachable(transaction);
|
||||
}
|
||||
|
||||
export function MerchantDetails({
|
||||
@ -1231,19 +1177,37 @@ export function ExchangeDetails({ exchange }: { exchange: string }): VNode {
|
||||
}
|
||||
|
||||
export interface AmountWithFee {
|
||||
effective: AmountJson;
|
||||
raw: AmountJson;
|
||||
value: AmountJson;
|
||||
fee: AmountJson;
|
||||
total: AmountJson;
|
||||
maxFrac: number;
|
||||
}
|
||||
|
||||
export function getAmountWithFee(
|
||||
effective: AmountJson,
|
||||
raw: AmountJson,
|
||||
direction: "credit" | "debit",
|
||||
): AmountWithFee {
|
||||
const fee =
|
||||
direction === "credit"
|
||||
? Amounts.sub(raw, effective).amount
|
||||
: Amounts.sub(effective, raw).amount;
|
||||
|
||||
const maxFrac = [effective, raw, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return {
|
||||
total: effective,
|
||||
value: raw,
|
||||
fee,
|
||||
maxFrac,
|
||||
};
|
||||
}
|
||||
|
||||
export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const fee = Amounts.sub(amount.raw, amount.effective).amount;
|
||||
|
||||
const maxFrac = [amount.raw, amount.effective, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
@ -1251,17 +1215,17 @@ export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
<i18n.Translate>Invoice</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={amount.raw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(amount.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} negative maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -1275,7 +1239,7 @@ export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={amount.effective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
@ -1285,12 +1249,6 @@ export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const fee = Amounts.sub(amount.effective, amount.raw).amount;
|
||||
|
||||
const maxFrac = [amount.raw, amount.effective, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
@ -1298,17 +1256,17 @@ export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
<i18n.Translate>Transfer</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={amount.raw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(amount.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} negative maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -1322,7 +1280,7 @@ export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={amount.effective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
@ -1332,12 +1290,12 @@ export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const fee = Amounts.sub(amount.raw, amount.effective).amount;
|
||||
|
||||
const maxFrac = [amount.raw, amount.effective, fee]
|
||||
const maxFrac = [amount.fee, amount.fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
const total = Amounts.add(amount.value, amount.fee).amount;
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
@ -1345,17 +1303,17 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
<i18n.Translate>Withdraw</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={amount.raw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(amount.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} negative maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -1369,7 +1327,7 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={amount.effective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
@ -1378,24 +1336,18 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
|
||||
export function PurchaseDetails({
|
||||
price,
|
||||
refund,
|
||||
effectiveRefund,
|
||||
info,
|
||||
proposalId,
|
||||
}: {
|
||||
price: AmountWithFee;
|
||||
refund?: AmountWithFee;
|
||||
effectiveRefund?: AmountJson;
|
||||
info: OrderShortInfo;
|
||||
proposalId: string;
|
||||
}): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const partialFee = Amounts.sub(price.effective, price.raw).amount;
|
||||
|
||||
const refundFee = !refund
|
||||
? Amounts.zeroOfCurrency(price.effective.currency)
|
||||
: Amounts.sub(refund.raw, refund.effective).amount;
|
||||
|
||||
const fee = Amounts.sum([partialFee, refundFee]).amount;
|
||||
const total = Amounts.add(price.value, price.fee).amount;
|
||||
|
||||
const hasProducts = info.products && info.products.length > 0;
|
||||
|
||||
@ -1406,10 +1358,6 @@ export function PurchaseDetails({
|
||||
return;
|
||||
};
|
||||
|
||||
const total = !refund
|
||||
? price.effective
|
||||
: Amounts.sub(price.effective, refund.effective).amount;
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
@ -1417,43 +1365,73 @@ export function PurchaseDetails({
|
||||
<i18n.Translate>Price</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={price.raw} />
|
||||
<Amount value={price.value} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{refund && Amounts.isNonZero(refund.raw) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Refunded</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={refund.raw} negative />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(price.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} />
|
||||
<Amount value={price.fee} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<hr />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={total} />
|
||||
</td>
|
||||
</tr>
|
||||
{effectiveRefund && Amounts.isNonZero(effectiveRefund) ? (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<hr />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Subtotal</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={price.total} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Refunded</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={effectiveRefund} negative />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<hr />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={Amounts.sub(total, effectiveRefund).amount} />
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Fragment>
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<hr />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={price.total} />
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
)}
|
||||
{hasProducts && (
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
@ -1508,39 +1486,27 @@ export function PurchaseDetails({
|
||||
);
|
||||
}
|
||||
|
||||
function RefundDetails({
|
||||
transaction,
|
||||
}: {
|
||||
transaction: TransactionRefund;
|
||||
}): VNode {
|
||||
function RefundDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const r = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
const e = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
const fee = Amounts.sub(r, e).amount;
|
||||
|
||||
const maxFrac = [r, e, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Amount</i18n.Translate>
|
||||
<i18n.Translate>Refund</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountRaw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(amount.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} negative maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -1554,45 +1520,34 @@ function RefundDetails({
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountEffective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
);
|
||||
}
|
||||
|
||||
function DepositDetails({
|
||||
transaction,
|
||||
}: {
|
||||
transaction: TransactionDeposit;
|
||||
}): VNode {
|
||||
function DepositDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
const r = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
const e = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
const fee = Amounts.sub(e, r).amount;
|
||||
|
||||
const maxFrac = [r, e, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Amount</i18n.Translate>
|
||||
<i18n.Translate>Deposit</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountRaw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(amount.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -1606,43 +1561,32 @@ function DepositDetails({
|
||||
<i18n.Translate>Total transfer</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountEffective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
);
|
||||
}
|
||||
function RefreshDetails({
|
||||
transaction,
|
||||
}: {
|
||||
transaction: TransactionRefresh;
|
||||
}): VNode {
|
||||
|
||||
function RefreshDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const r = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
const e = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
const fee = Amounts.sub(r, e).amount;
|
||||
|
||||
const maxFrac = [r, e, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Amount</i18n.Translate>
|
||||
<i18n.Translate>Refresh</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountRaw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} negative maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -1655,42 +1599,34 @@ function RefreshDetails({
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountEffective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
);
|
||||
}
|
||||
|
||||
function TipDetails({ transaction }: { transaction: TransactionTip }): VNode {
|
||||
function TipDetails({ amount }: { amount: AmountWithFee }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const r = Amounts.parseOrThrow(transaction.amountRaw);
|
||||
const e = Amounts.parseOrThrow(transaction.amountEffective);
|
||||
const fee = Amounts.sub(r, e).amount;
|
||||
|
||||
const maxFrac = [r, e, fee]
|
||||
.map((a) => Amounts.maxFractionalDigits(a))
|
||||
.reduce((c, p) => Math.max(c, p), 0);
|
||||
|
||||
return (
|
||||
<PurchaseDetailsTable>
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Amount</i18n.Translate>
|
||||
<i18n.Translate>Tip</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountRaw} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.value} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{Amounts.isNonZero(fee) && (
|
||||
{Amounts.isNonZero(amount.fee) && (
|
||||
<tr>
|
||||
<td>
|
||||
<i18n.Translate>Transaction fees</i18n.Translate>
|
||||
<i18n.Translate>Fees</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={fee} negative maxFracSize={maxFrac} />
|
||||
<Amount value={amount.fee} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -1704,7 +1640,7 @@ function TipDetails({ transaction }: { transaction: TransactionTip }): VNode {
|
||||
<i18n.Translate>Total</i18n.Translate>
|
||||
</td>
|
||||
<td>
|
||||
<Amount value={transaction.amountEffective} maxFracSize={maxFrac} />
|
||||
<Amount value={amount.total} maxFracSize={amount.maxFrac} />
|
||||
</td>
|
||||
</tr>
|
||||
</PurchaseDetailsTable>
|
||||
@ -1778,3 +1714,38 @@ function NicePayto({ payto }: { payto: PaytoUri }): VNode {
|
||||
}
|
||||
return <Fragment>{stringifyPaytoUri(payto)}</Fragment>;
|
||||
}
|
||||
|
||||
function ShowQrWithCopy({ text }: { text: string }): VNode {
|
||||
const [showing, setShowing] = useState(false);
|
||||
const { i18n } = useTranslationContext();
|
||||
async function copy(): Promise<void> {
|
||||
navigator.clipboard.writeText(text);
|
||||
}
|
||||
async function toggle(): Promise<void> {
|
||||
setShowing((s) => !s);
|
||||
}
|
||||
if (showing) {
|
||||
return (
|
||||
<div>
|
||||
<QR text={text} />
|
||||
<Button onClick={copy as SafeHandler<void>}>
|
||||
<i18n.Translate>copy</i18n.Translate>
|
||||
</Button>
|
||||
<Button onClick={toggle as SafeHandler<void>}>
|
||||
<i18n.Translate>hide qr</i18n.Translate>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div>{text.substring(0, 64)}...</div>
|
||||
<Button onClick={copy as SafeHandler<void>}>
|
||||
<i18n.Translate>copy</i18n.Translate>
|
||||
</Button>
|
||||
<Button onClick={toggle as SafeHandler<void>}>
|
||||
<i18n.Translate>show qr</i18n.Translate>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user