aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/cta
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta')
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/index.ts16
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/state.ts71
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/stories.tsx175
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/test.ts24
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/views.tsx178
5 files changed, 292 insertions, 172 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/index.ts b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
index 0e67a4991..5c0f6f0d6 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountJson, ConfirmPayResult, PreparePayResult } from "@gnu-taler/taler-util";
+import { AmountJson, ConfirmPayResult, PreparePayResult, PreparePayResultAlreadyConfirmed, PreparePayResultInsufficientBalance, PreparePayResultPaymentPossible } from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
@@ -37,6 +37,7 @@ export type State =
| State.Ready
| State.NoEnoughBalance
| State.NoBalanceForCurrency
+ | State.Completed
| State.Confirmed;
export namespace State {
@@ -52,8 +53,6 @@ export namespace State {
interface BaseInfo {
amount: AmountJson;
- totalFees: AmountJson;
- payStatus: PreparePayResult;
uri: string;
error: undefined;
goToWalletManualWithdraw: (currency?: string) => Promise<void>;
@@ -61,20 +60,30 @@ export namespace State {
}
export interface NoBalanceForCurrency extends BaseInfo {
status: "no-balance-for-currency"
+ payStatus: PreparePayResult;
balance: undefined;
}
export interface NoEnoughBalance extends BaseInfo {
status: "no-enough-balance"
+ payStatus: PreparePayResult;
balance: AmountJson;
}
export interface Ready extends BaseInfo {
status: "ready";
+ payStatus: PreparePayResultPaymentPossible;
payHandler: ButtonHandler;
balance: AmountJson;
}
export interface Confirmed extends BaseInfo {
status: "confirmed";
+ payStatus: PreparePayResultAlreadyConfirmed;
+ balance: AmountJson;
+ }
+
+ export interface Completed extends BaseInfo {
+ status: "completed";
+ payStatus: PreparePayResult;
payResult: ConfirmPayResult;
payHandler: ButtonHandler;
balance: AmountJson;
@@ -87,6 +96,7 @@ const viewMapping: StateViewMap<State> = {
"no-balance-for-currency": BaseView,
"no-enough-balance": BaseView,
confirmed: BaseView,
+ completed: BaseView,
ready: BaseView,
};
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/state.ts b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
index 3c819ec8f..f75cef06f 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
@@ -78,20 +78,9 @@ export function useComponentState(
(b) => Amounts.parseOrThrow(b.available).currency === amount.currency,
);
-
- let totalFees = Amounts.getZero(amount.currency);
- if (payStatus.status === PreparePayResultType.PaymentPossible) {
- const amountEffective: AmountJson = Amounts.parseOrThrow(
- payStatus.amountEffective,
- );
- totalFees = Amounts.sub(amountEffective, amount).amount;
- }
-
const baseResult = {
uri: hook.response.uri,
amount,
- totalFees,
- payStatus,
error: undefined,
goBack, goToWalletManualWithdraw
}
@@ -100,12 +89,45 @@ export function useComponentState(
return {
status: "no-balance-for-currency",
balance: undefined,
+ payStatus,
...baseResult,
}
}
const foundAmount = Amounts.parseOrThrow(foundBalance.available);
+ if (payResult) {
+ return {
+ status: "completed",
+ balance: foundAmount,
+ payStatus,
+ payHandler: {
+ error: payErrMsg,
+ },
+ payResult,
+ ...baseResult,
+ };
+ }
+
+ if (payStatus.status === PreparePayResultType.InsufficientBalance) {
+ return {
+ status: 'no-enough-balance',
+ balance: foundAmount,
+ payStatus,
+ ...baseResult,
+ }
+ }
+
+ if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
+ return {
+ status: "confirmed",
+ balance: foundAmount,
+ payStatus,
+ ...baseResult,
+ };
+ }
+
+
async function doPayment(): Promise<void> {
try {
if (payStatus.status !== "payment-possible") {
@@ -138,34 +160,19 @@ export function useComponentState(
}
}
- if (payStatus.status === PreparePayResultType.InsufficientBalance) {
- return {
- status: 'no-enough-balance',
- balance: foundAmount,
- ...baseResult,
- }
- }
-
const payHandler: ButtonHandler = {
onClick: payErrMsg ? undefined : doPayment,
error: payErrMsg,
};
- if (!payResult) {
- return {
- status: "ready",
- payHandler,
- ...baseResult,
- balance: foundAmount
- };
- }
-
+ // (payStatus.status === PreparePayResultType.PaymentPossible)
return {
- status: "confirmed",
- balance: foundAmount,
- payResult,
- payHandler: {},
+ status: "ready",
+ payHandler,
+ payStatus,
...baseResult,
+ balance: foundAmount
};
+
}
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx b/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx
index 603a9cb33..877c1996a 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx
@@ -21,11 +21,14 @@
import {
Amounts,
+ ConfirmPayResultType,
ContractTerms,
PreparePayResultType,
} from "@gnu-taler/taler-util";
+import merchantIcon from "../../../static-dev/merchant-icon.jpeg";
import { createExample } from "../../test-utils.js";
import { BaseView } from "./views.js";
+import beer from "../../../static-dev/beer.png";
export default {
title: "cta/payment",
@@ -34,25 +37,22 @@ export default {
};
export const NoBalance = createExample(BaseView, {
- status: "ready",
+ status: "no-balance-for-currency",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: undefined,
- payHandler: {
- onClick: async () => {
- null;
- },
- },
- totalFees: Amounts.parseOrThrow("USD:0"),
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
noncePriv: "",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
contractTerms: {
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
@@ -62,7 +62,7 @@ export const NoBalance = createExample(BaseView, {
});
export const NoEnoughBalance = createExample(BaseView, {
- status: "ready",
+ status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
@@ -70,21 +70,18 @@ export const NoEnoughBalance = createExample(BaseView, {
fraction: 40000000,
value: 9,
},
- payHandler: {
- onClick: async () => {
- null;
- },
- },
- totalFees: Amounts.parseOrThrow("USD:0"),
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
noncePriv: "",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
contractTerms: {
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
@@ -94,7 +91,7 @@ export const NoEnoughBalance = createExample(BaseView, {
});
export const EnoughBalanceButRestricted = createExample(BaseView, {
- status: "ready",
+ status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
@@ -102,21 +99,18 @@ export const EnoughBalanceButRestricted = createExample(BaseView, {
fraction: 40000000,
value: 19,
},
- payHandler: {
- onClick: async () => {
- null;
- },
- },
- totalFees: Amounts.parseOrThrow("USD:0"),
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
noncePriv: "",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
contractTerms: {
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
@@ -139,7 +133,6 @@ export const PaymentPossible = createExample(BaseView, {
null;
},
},
- totalFees: Amounts.parseOrThrow("USD:0"),
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payStatus: {
@@ -150,13 +143,19 @@ export const PaymentPossible = createExample(BaseView, {
contractTerms: {
nonce: "123213123",
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
+ },
+ pay_deadline: {
+ t_s: new Date().getTime() / 1000 + 60 * 60 * 3,
},
amount: "USD:10",
summary: "some beers",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
},
});
@@ -174,7 +173,6 @@ export const PaymentPossibleWithFee = createExample(BaseView, {
null;
},
},
- totalFees: Amounts.parseOrThrow("USD:0.20"),
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payStatus: {
@@ -185,18 +183,19 @@ export const PaymentPossibleWithFee = createExample(BaseView, {
contractTerms: {
nonce: "123213123",
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
amount: "USD:10",
summary: "some beers",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
},
});
-import beer from "../../../static-dev/beer.png";
-
export const TicketWithAProductList = createExample(BaseView, {
status: "ready",
error: undefined,
@@ -211,7 +210,6 @@ export const TicketWithAProductList = createExample(BaseView, {
null;
},
},
- totalFees: Amounts.parseOrThrow("USD:0.20"),
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payStatus: {
@@ -222,7 +220,10 @@ export const TicketWithAProductList = createExample(BaseView, {
contractTerms: {
nonce: "123213123",
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
amount: "USD:10",
summary: "some beers",
@@ -247,11 +248,11 @@ export const TicketWithAProductList = createExample(BaseView, {
],
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
},
});
-export const AlreadyConfirmedByOther = createExample(BaseView, {
+export const TicketWithShipping = createExample(BaseView, {
status: "ready",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
@@ -265,7 +266,52 @@ export const AlreadyConfirmedByOther = createExample(BaseView, {
null;
},
},
- totalFees: Amounts.parseOrThrow("USD:0.20"),
+
+ uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
+ payStatus: {
+ status: PreparePayResultType.PaymentPossible,
+ amountEffective: "USD:10.20",
+ amountRaw: "USD:10",
+ noncePriv: "",
+ contractTerms: {
+ nonce: "123213123",
+ merchant: {
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
+ },
+ amount: "USD:10",
+ summary: "banana pi set",
+ products: [
+ {
+ description: "banana pi",
+ price: "USD:2",
+ quantity: 1,
+ },
+ ],
+ delivery_date: {
+ t_s: new Date().getTime() / 1000 + 30 * 24 * 60 * 60,
+ },
+ delivery_location: {
+ town: "Liverpool",
+ street: "Down st 1234",
+ },
+ } as Partial<ContractTerms> as any,
+ contractTermsHash: "123456",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
+ },
+});
+
+export const AlreadyConfirmedByOther = createExample(BaseView, {
+ status: "confirmed",
+ error: undefined,
+ amount: Amounts.parseOrThrow("USD:10"),
+ balance: {
+ currency: "USD",
+ fraction: 40000000,
+ value: 11,
+ },
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payStatus: {
@@ -274,19 +320,22 @@ export const AlreadyConfirmedByOther = createExample(BaseView, {
amountRaw: "USD:10",
contractTerms: {
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
paid: false,
},
});
export const AlreadyPaidWithoutFulfillment = createExample(BaseView, {
- status: "ready",
+ status: "completed",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
@@ -294,33 +343,34 @@ export const AlreadyPaidWithoutFulfillment = createExample(BaseView, {
fraction: 40000000,
value: 11,
},
- payHandler: {
- onClick: async () => {
- null;
- },
- },
- totalFees: Amounts.parseOrThrow("USD:0.20"),
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
+ payResult: {
+ type: ConfirmPayResultType.Done,
+ contractTerms: {} as any,
+ },
payStatus: {
status: PreparePayResultType.AlreadyConfirmed,
amountEffective: "USD:10",
amountRaw: "USD:10",
contractTerms: {
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
paid: true,
},
});
export const AlreadyPaidWithFulfillment = createExample(BaseView, {
- status: "ready",
+ status: "completed",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
@@ -328,29 +378,34 @@ export const AlreadyPaidWithFulfillment = createExample(BaseView, {
fraction: 40000000,
value: 11,
},
- payHandler: {
- onClick: async () => {
- null;
- },
- },
- totalFees: Amounts.parseOrThrow("USD:0.20"),
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
+ payResult: {
+ type: ConfirmPayResultType.Done,
+ contractTerms: {
+ fulfillment_message: "thanks for buying!",
+ fulfillment_url: "https://demo.taler.net",
+ } as Partial<ContractTerms> as any,
+ },
payStatus: {
status: PreparePayResultType.AlreadyConfirmed,
amountEffective: "USD:10",
amountRaw: "USD:10",
contractTerms: {
merchant: {
- name: "someone",
+ name: "the merchant",
+ logo: merchantIcon,
+ website: "https://www.themerchant.taler",
+ email: "contact@merchant.taler",
},
+ fulfillment_url: "https://demo.taler.net",
fulfillment_message:
"congratulations! you are looking at the fulfillment message! ",
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
- proposalId: "proposal1234",
+ proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
paid: true,
},
});
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/test.ts b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
index aea70b7ca..afd881a72 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
@@ -204,7 +204,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:0"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:0"));
expect(r.payHandler.onClick).not.undefined;
}
@@ -246,7 +246,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
expect(r.payHandler.onClick).not.undefined;
}
@@ -293,7 +293,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
if (r.payHandler.onClick === undefined) expect.fail();
r.payHandler.onClick();
}
@@ -302,13 +302,13 @@ describe("Payment CTA states", () => {
{
const r = getLastResultOrThrow();
- if (r.status !== "confirmed") expect.fail();
+ if (r.status !== "completed") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
- if (r.payResult.type !== ConfirmPayResultType.Done) expect.fail();
- expect(r.payResult.contractTerms).not.undefined;
- expect(r.payHandler.onClick).undefined;
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // if (r.payResult.type !== ConfirmPayResultType.Done) expect.fail();
+ // expect(r.payResult.contractTerms).not.undefined;
+ // expect(r.payHandler.onClick).undefined;
}
await assertNoPendingUpdate();
@@ -354,7 +354,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
if (r.payHandler.onClick === undefined) expect.fail();
r.payHandler.onClick();
}
@@ -366,7 +366,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
expect(r.payHandler.onClick).undefined;
if (r.payHandler.error === undefined) expect.fail();
//FIXME: error message here is bad
@@ -425,7 +425,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:10"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
expect(r.payHandler.onClick).not.undefined;
notifyCoinWithdrawn(Amounts.parseOrThrow("USD:5"));
@@ -438,7 +438,7 @@ describe("Payment CTA states", () => {
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
+ // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
expect(r.payHandler.onClick).not.undefined;
}
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/views.tsx b/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
index a8c9a640a..4c2ddc0f2 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
@@ -15,6 +15,7 @@
*/
import {
+ AbsoluteTime,
Amounts,
ConfirmPayResultType,
ContractTerms,
@@ -38,8 +39,10 @@ import {
WalletAction,
WarningBox,
} from "../../components/styled/index.js";
+import { Time } from "../../components/Time.js";
import { useTranslationContext } from "../../context/translation.js";
import { Button } from "../../mui/Button.js";
+import { MerchantDetails, PurchaseDetails } from "../../wallet/Transaction.js";
import { State } from "./index.js";
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
@@ -56,6 +59,7 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode {
type SupportedStates =
| State.Ready
| State.Confirmed
+ | State.Completed
| State.NoBalanceForCurrency
| State.NoEnoughBalance;
@@ -63,6 +67,15 @@ export function BaseView(state: SupportedStates): VNode {
const { i18n } = useTranslationContext();
const contractTerms: ContractTerms = state.payStatus.contractTerms;
+ const price = {
+ raw: state.amount,
+ effective:
+ "amountEffective" in state.payStatus
+ ? Amounts.parseOrThrow(state.payStatus.amountEffective)
+ : state.amount,
+ };
+ const totalFees = Amounts.sub(price.effective, price.raw).amount;
+
return (
<WalletAction>
<LogoHeader />
@@ -73,9 +86,9 @@ export function BaseView(state: SupportedStates): VNode {
<ShowImportantMessage state={state} />
- <section>
- {state.payStatus.status !== PreparePayResultType.InsufficientBalance &&
- Amounts.isNonZero(state.totalFees) && (
+ <section style={{ textAlign: "left" }}>
+ {/* {state.payStatus.status !== PreparePayResultType.InsufficientBalance &&
+ Amounts.isNonZero(totalFees) && (
<Part
big
title={<i18n.Translate>Total to pay</i18n.Translate>}
@@ -89,24 +102,43 @@ export function BaseView(state: SupportedStates): VNode {
text={<Amount value={state.payStatus.amountRaw} />}
kind="neutral"
/>
- {Amounts.isNonZero(state.totalFees) && (
+ {Amounts.isNonZero(totalFees) && (
<Fragment>
<Part
big
title={<i18n.Translate>Fee</i18n.Translate>}
- text={<Amount value={state.totalFees} />}
+ text={<Amount value={totalFees} />}
kind="negative"
/>
</Fragment>
- )}
+ )} */}
+ <Part
+ title={<i18n.Translate>Purchase</i18n.Translate>}
+ text={contractTerms.summary}
+ kind="neutral"
+ />
<Part
title={<i18n.Translate>Merchant</i18n.Translate>}
- text={contractTerms.merchant.name}
+ text={<MerchantDetails merchant={contractTerms.merchant} />}
kind="neutral"
/>
+ {/* <pre>{JSON.stringify(price)}</pre>
+ <hr />
+ <pre>{JSON.stringify(state.payStatus, undefined, 2)}</pre> */}
<Part
- title={<i18n.Translate>Purchase</i18n.Translate>}
- text={contractTerms.summary}
+ title={<i18n.Translate>Details</i18n.Translate>}
+ text={
+ <PurchaseDetails
+ price={price}
+ info={{
+ ...contractTerms,
+ orderId: contractTerms.order_id,
+ contractTermsHash: "",
+ products: contractTerms.products!,
+ }}
+ proposalId={state.payStatus.proposalId}
+ />
+ }
kind="neutral"
/>
{contractTerms.order_id && (
@@ -116,8 +148,19 @@ export function BaseView(state: SupportedStates): VNode {
kind="neutral"
/>
)}
- {contractTerms.products && contractTerms.products.length > 0 && (
- <ProductList products={contractTerms.products} />
+ {contractTerms.pay_deadline && (
+ <Part
+ title={<i18n.Translate>Valid until</i18n.Translate>}
+ text={
+ <Time
+ timestamp={AbsoluteTime.fromTimestamp(
+ contractTerms.pay_deadline,
+ )}
+ format="dd MMMM yyyy, HH:mm"
+ />
+ }
+ kind="neutral"
+ />
)}
</section>
<ButtonsSection
@@ -232,7 +275,7 @@ function ShowImportantMessage({ state }: { state: SupportedStates }): VNode {
);
}
- if (state.status == "confirmed") {
+ if (state.status == "completed") {
const { payResult, payHandler } = state;
if (payHandler.error) {
return <ErrorTalerOperation error={payHandler.error.errorDetail} />;
@@ -264,7 +307,7 @@ function ShowImportantMessage({ state }: { state: SupportedStates }): VNode {
return <Fragment />;
}
-function PayWithMobile({ state }: { state: State.Ready }): VNode {
+function PayWithMobile({ state }: { state: SupportedStates }): VNode {
const { i18n } = useTranslationContext();
const [showQR, setShowQR] = useState<boolean>(false);
@@ -286,7 +329,7 @@ function PayWithMobile({ state }: { state: State.Ready }): VNode {
<div>
<QR text={privateUri} />
<i18n.Translate>
- Scan the QR code or
+ Scan the QR code or &nbsp;
<a href={privateUri}>
<i18n.Translate>click here</i18n.Translate>
</a>
@@ -306,61 +349,66 @@ function ButtonsSection({
}): VNode {
const { i18n } = useTranslationContext();
if (state.status === "ready") {
- const { payStatus } = state;
- if (payStatus.status === PreparePayResultType.PaymentPossible) {
- return (
- <Fragment>
- <section>
- <Button
- variant="contained"
- color="success"
- onClick={state.payHandler.onClick}
- >
- <i18n.Translate>
- Pay {<Amount value={payStatus.amountEffective} />}
- </i18n.Translate>
- </Button>
- </section>
- <PayWithMobile state={state} />
- </Fragment>
- );
- }
- if (payStatus.status === PreparePayResultType.InsufficientBalance) {
- let BalanceMessage = "";
- if (!state.balance) {
- BalanceMessage = i18n.str`You have no balance for this currency. Withdraw digital cash first.`;
+ return (
+ <Fragment>
+ <section>
+ <Button
+ variant="contained"
+ color="success"
+ onClick={state.payHandler.onClick}
+ >
+ <i18n.Translate>
+ Pay &nbsp;
+ {<Amount value={state.payStatus.amountEffective} />}
+ </i18n.Translate>
+ </Button>
+ </section>
+ <PayWithMobile state={state} />
+ </Fragment>
+ );
+ }
+ if (
+ state.status === "no-enough-balance" ||
+ state.status === "no-balance-for-currency"
+ ) {
+ // if (state.payStatus.status === PreparePayResultType.InsufficientBalance) {
+ let BalanceMessage = "";
+ if (!state.balance) {
+ BalanceMessage = i18n.str`You have no balance for this currency. Withdraw digital cash first.`;
+ } else {
+ const balanceShouldBeEnough =
+ Amounts.cmp(state.balance, state.amount) !== -1;
+ if (balanceShouldBeEnough) {
+ BalanceMessage = i18n.str`Could not find enough coins to pay this order. Even if you have enough ${state.balance.currency} some restriction may apply.`;
} else {
- const balanceShouldBeEnough =
- Amounts.cmp(state.balance, state.amount) !== -1;
- if (balanceShouldBeEnough) {
- BalanceMessage = i18n.str`Could not find enough coins to pay this order. Even if you have enough ${state.balance.currency} some restriction may apply.`;
- } else {
- BalanceMessage = i18n.str`Your current balance is not enough for this order.`;
- }
+ BalanceMessage = i18n.str`Your current balance is not enough for this order.`;
}
- return (
- <Fragment>
- <section>
- <WarningBox>{BalanceMessage}</WarningBox>
- </section>
- <section>
- <Button
- variant="contained"
- color="success"
- onClick={() => goToWalletManualWithdraw(state.amount.currency)}
- >
- <i18n.Translate>Withdraw digital cash</i18n.Translate>
- </Button>
- </section>
- <PayWithMobile state={state} />
- </Fragment>
- );
}
- if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
+ return (
+ <Fragment>
+ <section>
+ <WarningBox>{BalanceMessage}</WarningBox>
+ </section>
+ <section>
+ <Button
+ variant="contained"
+ color="success"
+ onClick={() => goToWalletManualWithdraw(state.amount.currency)}
+ >
+ <i18n.Translate>Withdraw digital cash</i18n.Translate>
+ </Button>
+ </section>
+ <PayWithMobile state={state} />
+ </Fragment>
+ );
+ // }
+ }
+ if (state.status === "confirmed") {
+ if (state.payStatus.status === PreparePayResultType.AlreadyConfirmed) {
return (
<Fragment>
<section>
- {payStatus.paid &&
+ {state.payStatus.paid &&
state.payStatus.contractTerms.fulfillment_message && (
<Part
title={<i18n.Translate>Merchant message</i18n.Translate>}
@@ -369,13 +417,13 @@ function ButtonsSection({
/>
)}
</section>
- {!payStatus.paid && <PayWithMobile state={state} />}
+ {!state.payStatus.paid && <PayWithMobile state={state} />}
</Fragment>
);
}
}
- if (state.status === "confirmed") {
+ if (state.status === "completed") {
if (state.payResult.type === ConfirmPayResultType.Pending) {
return (
<section>