aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-05-14 18:09:33 -0300
committerSebastian <sebasjm@gmail.com>2022-05-14 18:09:49 -0300
commite4ea2019430fb3c4b788f67427fbd743f604b7e5 (patch)
treee7426a82a2cc523c15d7f8b64e16c53722f7a87b /packages/taler-wallet-webextension/src
parentc02dbc833bc384b72e5b18450a47ae2b212b0a8e (diff)
feat: awaiting refund
Diffstat (limited to 'packages/taler-wallet-webextension/src')
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund.stories.tsx8
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund.test.ts53
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund.tsx70
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.stories.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx208
6 files changed, 235 insertions, 112 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx
index 6b7cf4621..bc2939896 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx
@@ -33,6 +33,7 @@ export const Complete = createExample(TestedComponent, {
state: {
status: "completed",
amount: Amounts.parseOrThrow("USD:1"),
+ granted: Amounts.parseOrThrow("USD:1"),
hook: undefined,
merchantName: "the merchant",
products: undefined,
@@ -44,9 +45,10 @@ export const InProgress = createExample(TestedComponent, {
status: "in-progress",
hook: undefined,
amount: Amounts.parseOrThrow("USD:1"),
+ awaitingAmount: Amounts.parseOrThrow("USD:1"),
+ granted: Amounts.parseOrThrow("USD:0"),
merchantName: "the merchant",
products: undefined,
- progress: 0.5,
},
});
@@ -58,6 +60,8 @@ export const Ready = createExample(TestedComponent, {
ignore: {},
amount: Amounts.parseOrThrow("USD:1"),
+ awaitingAmount: Amounts.parseOrThrow("USD:1"),
+ granted: Amounts.parseOrThrow("USD:0"),
merchantName: "the merchant",
products: [],
orderId: "abcdef",
@@ -73,6 +77,8 @@ export const WithAProductList = createExample(TestedComponent, {
accept: {},
ignore: {},
amount: Amounts.parseOrThrow("USD:1"),
+ awaitingAmount: Amounts.parseOrThrow("USD:1"),
+ granted: Amounts.parseOrThrow("USD:0"),
merchantName: "the merchant",
products: [
{
diff --git a/packages/taler-wallet-webextension/src/cta/Refund.test.ts b/packages/taler-wallet-webextension/src/cta/Refund.test.ts
index e77f8e682..864b4f12c 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund.test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund.test.ts
@@ -19,7 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Amounts, NotificationType, PrepareRefundResult } from "@gnu-taler/taler-util";
+import { AmountJson, Amounts, NotificationType, PrepareRefundResult } from "@gnu-taler/taler-util";
import { expect } from "chai";
import { mountHook } from "../test-utils.js";
import { SubsHandler } from "./Pay.test.js";
@@ -62,10 +62,12 @@ describe("Refund CTA states", () => {
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = mountHook(() =>
useComponentState("taler://refund/asdasdas", {
prepareRefund: async () => ({
- total: 0,
- applied: 0,
- failed: 0,
- amountEffectivePaid: 'EUR:2',
+ effectivePaid: 'EUR:2',
+ awaiting: 'EUR:2',
+ gone: 'EUR:0',
+ granted: 'EUR:0',
+ pending: false,
+ proposalId: '1',
info: {
contractTermsHash: '123',
merchant: {
@@ -107,10 +109,12 @@ describe("Refund CTA states", () => {
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = mountHook(() =>
useComponentState("taler://refund/asdasdas", {
prepareRefund: async () => ({
- total: 0,
- applied: 0,
- failed: 0,
- amountEffectivePaid: 'EUR:2',
+ effectivePaid: 'EUR:2',
+ awaiting: 'EUR:2',
+ gone: 'EUR:0',
+ granted: 'EUR:0',
+ pending: false,
+ proposalId: '1',
info: {
contractTermsHash: '123',
merchant: {
@@ -161,21 +165,30 @@ describe("Refund CTA states", () => {
});
it("should be in progress when doing refresh", async () => {
- let numApplied = 1;
+ let granted = Amounts.getZero('EUR')
+ const unit: AmountJson = { currency: 'EUR', value: 1, fraction: 0 }
+ const refunded: AmountJson = { currency: 'EUR', value: 2, fraction: 0 }
+ let awaiting: AmountJson = refunded
+ let pending = true;
+
const subscriptions = new SubsHandler();
function notifyMelt(): void {
- numApplied++;
+ granted = Amounts.add(granted, unit).amount;
+ pending = granted.value < refunded.value;
+ awaiting = Amounts.sub(refunded, granted).amount;
subscriptions.notifyEvent(NotificationType.RefreshMelted)
}
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = mountHook(() =>
useComponentState("taler://refund/asdasdas", {
prepareRefund: async () => ({
- total: 3,
- applied: numApplied,
- failed: 0,
- amountEffectivePaid: 'EUR:2',
+ awaiting: Amounts.stringify(awaiting),
+ effectivePaid: 'EUR:2',
+ gone: 'EUR:0',
+ granted: Amounts.stringify(granted),
+ pending,
+ proposalId: '1',
info: {
contractTermsHash: '123',
merchant: {
@@ -201,12 +214,12 @@ describe("Refund CTA states", () => {
{
const state = getLastResultOrThrow()
- if (state.status !== 'in-progress') expect.fail();
+ if (state.status !== 'in-progress') expect.fail('1');
if (state.hook) expect.fail();
expect(state.merchantName).eq('the merchant name');
expect(state.products).undefined;
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"))
- expect(state.progress).closeTo(1 / 3, 0.01)
+ // expect(state.progress).closeTo(1 / 3, 0.01)
notifyMelt()
}
@@ -216,12 +229,12 @@ describe("Refund CTA states", () => {
{
const state = getLastResultOrThrow()
- if (state.status !== 'in-progress') expect.fail();
+ if (state.status !== 'in-progress') expect.fail('2');
if (state.hook) expect.fail();
expect(state.merchantName).eq('the merchant name');
expect(state.products).undefined;
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"))
- expect(state.progress).closeTo(2 / 3, 0.01)
+ // expect(state.progress).closeTo(2 / 3, 0.01)
notifyMelt()
}
@@ -231,7 +244,7 @@ describe("Refund CTA states", () => {
{
const state = getLastResultOrThrow()
- if (state.status !== 'completed') expect.fail();
+ if (state.status !== 'completed') expect.fail('3');
if (state.hook) expect.fail();
expect(state.merchantName).eq('the merchant name');
expect(state.products).undefined;
diff --git a/packages/taler-wallet-webextension/src/cta/Refund.tsx b/packages/taler-wallet-webextension/src/cta/Refund.tsx
index f69fc4311..5387a1782 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund.tsx
@@ -34,7 +34,6 @@ import { LoadingError } from "../components/LoadingError.js";
import { LogoHeader } from "../components/LogoHeader.js";
import { Part } from "../components/Part.js";
import {
- Button,
ButtonSuccess,
SubTitle,
WalletAction,
@@ -99,6 +98,12 @@ export function View({ state }: ViewProps): VNode {
<Part
big
title={<i18n.Translate>Total to refund</i18n.Translate>}
+ text={<Amount value={state.awaitingAmount} />}
+ kind="negative"
+ />
+ <Part
+ big
+ title={<i18n.Translate>Refunded</i18n.Translate>}
text={<Amount value={state.amount} />}
kind="negative"
/>
@@ -108,9 +113,9 @@ export function View({ state }: ViewProps): VNode {
<ProductList products={state.products} />
</section>
) : undefined}
- <section>
+ {/* <section>
<ProgressBar value={state.progress} />
- </section>
+ </section> */}
</WalletAction>
);
}
@@ -128,6 +133,14 @@ export function View({ state }: ViewProps): VNode {
<i18n.Translate>this refund is already accepted.</i18n.Translate>
</p>
</section>
+ <section>
+ <Part
+ big
+ title={<i18n.Translate>Total to refunded</i18n.Translate>}
+ text={<Amount value={state.granted} />}
+ kind="negative"
+ />
+ </section>
</WalletAction>
);
}
@@ -150,9 +163,23 @@ export function View({ state }: ViewProps): VNode {
<section>
<Part
big
- title={<i18n.Translate>Total to refund</i18n.Translate>}
+ title={<i18n.Translate>Order amount</i18n.Translate>}
text={<Amount value={state.amount} />}
- kind="negative"
+ kind="neutral"
+ />
+ {Amounts.isNonZero(state.granted) && (
+ <Part
+ big
+ title={<i18n.Translate>Already refunded</i18n.Translate>}
+ text={<Amount value={state.granted} />}
+ kind="neutral"
+ />
+ )}
+ <Part
+ big
+ title={<i18n.Translate>Refund offered</i18n.Translate>}
+ text={<Amount value={state.awaitingAmount} />}
+ kind="positive"
/>
</section>
{state.products && state.products.length ? (
@@ -164,9 +191,6 @@ export function View({ state }: ViewProps): VNode {
<ButtonSuccess onClick={state.accept.onClick}>
<i18n.Translate>Confirm refund</i18n.Translate>
</ButtonSuccess>
- <Button onClick={state.ignore.onClick}>
- <i18n.Translate>Ignore</i18n.Translate>
- </Button>
</section>
</WalletAction>
);
@@ -184,6 +208,8 @@ interface Ready {
merchantName: string;
products: Product[] | undefined;
amount: AmountJson;
+ awaitingAmount: AmountJson;
+ granted: AmountJson;
accept: ButtonHandler;
ignore: ButtonHandler;
orderId: string;
@@ -199,7 +225,8 @@ interface InProgress {
merchantName: string;
products: Product[] | undefined;
amount: AmountJson;
- progress: number;
+ awaitingAmount: AmountJson;
+ granted: AmountJson;
}
interface Completed {
status: "completed";
@@ -207,6 +234,7 @@ interface Completed {
merchantName: string;
products: Product[] | undefined;
amount: AmountJson;
+ granted: AmountJson;
}
export function useComponentState(
@@ -253,25 +281,27 @@ export function useComponentState(
};
}
- const pending = refund.total > refund.applied + refund.failed;
- const completed = refund.total > 0 && refund.applied === refund.total;
+ const awaitingAmount = Amounts.parseOrThrow(refund.awaiting);
- if (pending) {
+ if (Amounts.isZero(awaitingAmount)) {
return {
- status: "in-progress",
+ status: "completed",
hook: undefined,
- amount: Amounts.parseOrThrow(info.response.refund.amountEffectivePaid),
+ amount: Amounts.parseOrThrow(info.response.refund.effectivePaid),
+ granted: Amounts.parseOrThrow(info.response.refund.granted),
merchantName: info.response.refund.info.merchant.name,
products: info.response.refund.info.products,
- progress: (refund.applied + refund.failed) / refund.total,
};
}
- if (completed) {
+ if (refund.pending) {
return {
- status: "completed",
+ status: "in-progress",
hook: undefined,
- amount: Amounts.parseOrThrow(info.response.refund.amountEffectivePaid),
+ awaitingAmount,
+ amount: Amounts.parseOrThrow(info.response.refund.effectivePaid),
+ granted: Amounts.parseOrThrow(info.response.refund.granted),
+
merchantName: info.response.refund.info.merchant.name,
products: info.response.refund.info.products,
};
@@ -280,7 +310,9 @@ export function useComponentState(
return {
status: "ready",
hook: undefined,
- amount: Amounts.parseOrThrow(info.response.refund.amountEffectivePaid),
+ amount: Amounts.parseOrThrow(info.response.refund.effectivePaid),
+ granted: Amounts.parseOrThrow(info.response.refund.granted),
+ awaitingAmount,
merchantName: info.response.refund.info.merchant.name,
products: info.response.refund.info.products,
orderId: info.response.refund.info.orderId,
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index 92f1dea1b..3080a866e 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -78,6 +78,9 @@ const exampleData = {
summary: "the summary",
fulfillmentMessage: "",
},
+ refundPending: undefined,
+ totalRefundEffective: "USD:0",
+ totalRefundRaw: "USD:0",
proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
@@ -112,6 +115,7 @@ const exampleData = {
summary: "the summary",
fulfillmentMessage: "",
},
+ refundPending: undefined,
} as TransactionRefund,
};
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
index b4dfb6ce0..f162543ae 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
@@ -83,6 +83,9 @@ const exampleData = {
summary: "Essay: Why the Devil's Advocate Doesn't Help Reach the Truth",
fulfillmentMessage: "",
},
+ refundPending: undefined,
+ totalRefundEffective: "USD:0",
+ totalRefundRaw: "USD:0",
proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
@@ -117,6 +120,7 @@ const exampleData = {
summary: "the summary",
fulfillmentMessage: "",
},
+ refundPending: undefined,
} as TransactionRefund,
};
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index bcf6114a1..3377f98c7 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -40,7 +40,6 @@ import {
ButtonPrimary,
CenteredDialog,
InfoBox,
- LargeText,
ListOfProducts,
Overlay,
RowBorderGray,
@@ -51,6 +50,7 @@ import {
import { Time } from "../components/Time.js";
import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
+import { Pages } from "../NavigationBar.js";
import * as wxApi from "../wxApi.js";
interface Props {
@@ -344,6 +344,17 @@ export function TransactionView({
Amounts.parseOrThrow(transaction.amountRaw),
).amount;
+ const refundFee = Amounts.sub(
+ Amounts.parseOrThrow(transaction.totalRefundRaw),
+ Amounts.parseOrThrow(transaction.totalRefundEffective),
+ ).amount;
+ const refunded = Amounts.isNonZero(
+ Amounts.parseOrThrow(transaction.totalRefundRaw),
+ );
+ const pendingRefund =
+ transaction.refundPending === undefined
+ ? undefined
+ : Amounts.parseOrThrow(transaction.refundPending);
return (
<TransactionTemplate>
<SubTitle>
@@ -360,18 +371,54 @@ export function TransactionView({
text={<Amount value={transaction.amountEffective} />}
kind="negative"
/>
- <Part
- big
- title={<i18n.Translate>Purchase amount</i18n.Translate>}
- text={<Amount value={transaction.amountRaw} />}
- kind="neutral"
- />
- <Part
- big
- title={<i18n.Translate>Fee</i18n.Translate>}
- text={<Amount value={fee} />}
- kind="negative"
- />
+ {Amounts.isNonZero(fee) && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Purchase amount</i18n.Translate>}
+ text={<Amount value={transaction.amountRaw} />}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>Purchase Fee</i18n.Translate>}
+ text={<Amount value={fee} />}
+ kind="negative"
+ />
+ </Fragment>
+ )}
+ {refunded && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Total refunded</i18n.Translate>}
+ text={<Amount value={transaction.totalRefundEffective} />}
+ kind="positive"
+ />
+ {Amounts.isNonZero(refundFee) && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Refund amount</i18n.Translate>}
+ text={<Amount value={transaction.totalRefundRaw} />}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>Refund fee</i18n.Translate>}
+ text={<Amount value={refundFee} />}
+ kind="negative"
+ />
+ </Fragment>
+ )}
+ </Fragment>
+ )}
+ {pendingRefund !== undefined && Amounts.isNonZero(pendingRefund) && (
+ <Part
+ big
+ title={<i18n.Translate>Refund pending</i18n.Translate>}
+ text={<Amount value={pendingRefund} />}
+ kind="positive"
+ />
+ )}
<Part
title={<i18n.Translate>Merchant</i18n.Translate>}
text={transaction.info.merchant.name}
@@ -447,18 +494,22 @@ export function TransactionView({
text={<Amount value={transaction.amountEffective} />}
kind="neutral"
/>
- <Part
- big
- title={<i18n.Translate>Deposit amount</i18n.Translate>}
- text={<Amount value={transaction.amountRaw} />}
- kind="positive"
- />
- <Part
- big
- title={<i18n.Translate>Fee</i18n.Translate>}
- text={<Amount value={fee} />}
- kind="negative"
- />
+ {Amounts.isNonZero(fee) && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Deposit amount</i18n.Translate>}
+ text={<Amount value={transaction.amountRaw} />}
+ kind="positive"
+ />
+ <Part
+ big
+ title={<i18n.Translate>Fee</i18n.Translate>}
+ text={<Amount value={fee} />}
+ kind="negative"
+ />
+ </Fragment>
+ )}
{payto && <PartPayto big payto={payto} kind="neutral" />}
</TransactionTemplate>
);
@@ -485,18 +536,22 @@ export function TransactionView({
text={<Amount value={transaction.amountEffective} />}
kind="negative"
/>
- <Part
- big
- title={<i18n.Translate>Refresh amount</i18n.Translate>}
- text={<Amount value={transaction.amountRaw} />}
- kind="neutral"
- />
- <Part
- big
- title={<i18n.Translate>Fee</i18n.Translate>}
- text={<Amount value={fee} />}
- kind="negative"
- />
+ {Amounts.isNonZero(fee) && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Refresh amount</i18n.Translate>}
+ text={<Amount value={transaction.amountRaw} />}
+ kind="neutral"
+ />
+ <Part
+ big
+ title={<i18n.Translate>Fee</i18n.Translate>}
+ text={<Amount value={fee} />}
+ kind="negative"
+ />
+ </Fragment>
+ )}
</TransactionTemplate>
);
}
@@ -522,18 +577,22 @@ export function TransactionView({
text={<Amount value={transaction.amountRaw} />}
kind="positive"
/>
- <Part
- big
- title={<i18n.Translate>Received amount</i18n.Translate>}
- text={<Amount value={transaction.amountEffective} />}
- kind="neutral"
- />
- <Part
- big
- title={<i18n.Translate>Fee</i18n.Translate>}
- text={<Amount value={fee} />}
- kind="negative"
- />
+ {Amounts.isNonZero(fee) && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Received amount</i18n.Translate>}
+ text={<Amount value={transaction.amountEffective} />}
+ kind="neutral"
+ />
+ <Part
+ big
+ title={<i18n.Translate>Fee</i18n.Translate>}
+ text={<Amount value={fee} />}
+ kind="negative"
+ />
+ </Fragment>
+ )}
</TransactionTemplate>
);
}
@@ -559,37 +618,42 @@ export function TransactionView({
text={<Amount value={transaction.amountEffective} />}
kind="positive"
/>
- <Part
- big
- title={<i18n.Translate>Refund amount</i18n.Translate>}
- text={<Amount value={transaction.amountRaw} />}
- kind="neutral"
- />
- <Part
- big
- title={<i18n.Translate>Fee</i18n.Translate>}
- text={<Amount value={fee} />}
- kind="negative"
- />
+ {Amounts.isNonZero(fee) && (
+ <Fragment>
+ <Part
+ big
+ title={<i18n.Translate>Refund amount</i18n.Translate>}
+ text={<Amount value={transaction.amountRaw} />}
+ kind="neutral"
+ />
+ <Part
+ big
+ title={<i18n.Translate>Fee</i18n.Translate>}
+ text={<Amount value={fee} />}
+ kind="negative"
+ />
+ </Fragment>
+ )}
<Part
title={<i18n.Translate>Merchant</i18n.Translate>}
text={transaction.info.merchant.name}
kind="neutral"
/>
+
<Part
title={<i18n.Translate>Purchase</i18n.Translate>}
text={
- transaction.info.fulfillmentUrl ? (
- <a
- href={transaction.info.fulfillmentUrl}
- target="_bank"
- rel="noreferrer"
- >
- {transaction.info.summary}
- </a>
- ) : (
- transaction.info.summary
- )
+ <a
+ href={Pages.balance_transaction.replace(
+ ":tid",
+ transaction.refundedTransactionId,
+ )}
+ // href={transaction.info.fulfillmentUrl}
+ // target="_bank"
+ // rel="noreferrer"
+ >
+ {transaction.info.summary}
+ </a>
}
kind="neutral"
/>