@blocklet/payment-react 1.20.10 → 1.20.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/components/promotion-code.d.ts +19 -0
- package/es/components/promotion-code.js +153 -0
- package/es/contexts/payment.d.ts +8 -0
- package/es/contexts/payment.js +10 -1
- package/es/index.d.ts +2 -1
- package/es/index.js +3 -1
- package/es/libs/util.d.ts +5 -1
- package/es/libs/util.js +23 -0
- package/es/locales/en.js +40 -15
- package/es/locales/zh.js +29 -0
- package/es/payment/form/index.js +7 -1
- package/es/payment/index.js +19 -0
- package/es/payment/product-item.js +32 -3
- package/es/payment/summary.d.ts +5 -2
- package/es/payment/summary.js +193 -16
- package/lib/components/promotion-code.d.ts +19 -0
- package/lib/components/promotion-code.js +155 -0
- package/lib/contexts/payment.d.ts +8 -0
- package/lib/contexts/payment.js +13 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +8 -0
- package/lib/libs/util.d.ts +5 -1
- package/lib/libs/util.js +29 -0
- package/lib/locales/en.js +40 -15
- package/lib/locales/zh.js +29 -0
- package/lib/payment/form/index.js +8 -1
- package/lib/payment/index.js +23 -0
- package/lib/payment/product-item.js +46 -0
- package/lib/payment/summary.d.ts +5 -2
- package/lib/payment/summary.js +153 -11
- package/package.json +9 -9
- package/src/components/promotion-code.tsx +184 -0
- package/src/contexts/payment.tsx +15 -0
- package/src/index.ts +2 -0
- package/src/libs/util.ts +35 -0
- package/src/locales/en.tsx +40 -15
- package/src/locales/zh.tsx +29 -0
- package/src/payment/form/index.tsx +10 -1
- package/src/payment/index.tsx +22 -0
- package/src/payment/product-item.tsx +37 -2
- package/src/payment/summary.tsx +201 -16
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface AppliedPromoCode {
|
|
2
|
+
id: string;
|
|
3
|
+
code: string;
|
|
4
|
+
discount_amount?: string;
|
|
5
|
+
}
|
|
6
|
+
interface PromotionCodeProps {
|
|
7
|
+
checkoutSessionId: string;
|
|
8
|
+
initialAppliedCodes?: AppliedPromoCode[];
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
currencyId: string;
|
|
13
|
+
onUpdate?: (data: {
|
|
14
|
+
appliedCodes: AppliedPromoCode[];
|
|
15
|
+
discountAmount: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
}
|
|
18
|
+
export default function PromotionCode({ checkoutSessionId, initialAppliedCodes, disabled, className, placeholder, onUpdate, currencyId, }: PromotionCodeProps): import("react").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
+
import { TextField, Button, Alert, Box, InputAdornment } from "@mui/material";
|
|
4
|
+
import { Add } from "@mui/icons-material";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import LoadingButton from "./loading-button.js";
|
|
7
|
+
import api from "../libs/api.js";
|
|
8
|
+
import { usePaymentContext } from "../contexts/payment.js";
|
|
9
|
+
export default function PromotionCode({
|
|
10
|
+
checkoutSessionId,
|
|
11
|
+
initialAppliedCodes = [],
|
|
12
|
+
disabled = false,
|
|
13
|
+
className = "",
|
|
14
|
+
placeholder = "",
|
|
15
|
+
onUpdate = void 0,
|
|
16
|
+
currencyId
|
|
17
|
+
}) {
|
|
18
|
+
const { t } = useLocaleContext();
|
|
19
|
+
const [showInput, setShowInput] = useState(false);
|
|
20
|
+
const [code, setCode] = useState("");
|
|
21
|
+
const [error, setError] = useState("");
|
|
22
|
+
const [applying, setApplying] = useState(false);
|
|
23
|
+
const [appliedCodes, setAppliedCodes] = useState(initialAppliedCodes);
|
|
24
|
+
const { session, paymentState } = usePaymentContext();
|
|
25
|
+
const handleLoginCheck = () => {
|
|
26
|
+
if (!session.user) {
|
|
27
|
+
session?.login(() => {
|
|
28
|
+
handleApply();
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
handleApply();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const handleApply = async () => {
|
|
35
|
+
if (!code.trim()) return;
|
|
36
|
+
if (paymentState.paying || paymentState.stripePaying) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
setApplying(true);
|
|
40
|
+
setError("");
|
|
41
|
+
try {
|
|
42
|
+
const response = await api.post(`/api/checkout-sessions/${checkoutSessionId}/apply-promotion`, {
|
|
43
|
+
promotion_code: code.trim(),
|
|
44
|
+
currency_id: currencyId
|
|
45
|
+
});
|
|
46
|
+
const discounts = response.data.discounts || [];
|
|
47
|
+
const appliedDiscount = discounts[0];
|
|
48
|
+
if (appliedDiscount) {
|
|
49
|
+
const newCode = {
|
|
50
|
+
id: appliedDiscount.promotion_code || appliedDiscount.coupon,
|
|
51
|
+
code: code.trim(),
|
|
52
|
+
discount_amount: appliedDiscount.discount_amount
|
|
53
|
+
};
|
|
54
|
+
setAppliedCodes([newCode]);
|
|
55
|
+
setCode("");
|
|
56
|
+
setShowInput(false);
|
|
57
|
+
onUpdate?.({
|
|
58
|
+
appliedCodes: [newCode],
|
|
59
|
+
discountAmount: appliedDiscount.discount_amount
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
const errorMessage = err.response?.data?.error || err.message;
|
|
64
|
+
setError(errorMessage);
|
|
65
|
+
} finally {
|
|
66
|
+
setApplying(false);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const handleKeyPress = (event) => {
|
|
70
|
+
if (event.key === "Enter" && !applying && code.trim()) {
|
|
71
|
+
handleLoginCheck();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const isPaymentInProgress = paymentState.paying || paymentState.stripePaying;
|
|
75
|
+
return /* @__PURE__ */ jsx(Box, { className, children: appliedCodes.length === 0 && !disabled && !isPaymentInProgress && (showInput ? /* @__PURE__ */ jsxs(
|
|
76
|
+
Box,
|
|
77
|
+
{
|
|
78
|
+
onBlur: () => {
|
|
79
|
+
if (!code.trim()) {
|
|
80
|
+
setShowInput(false);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
TextField,
|
|
86
|
+
{
|
|
87
|
+
fullWidth: true,
|
|
88
|
+
value: code,
|
|
89
|
+
onChange: (e) => setCode(e.target.value),
|
|
90
|
+
onKeyPress: handleKeyPress,
|
|
91
|
+
placeholder: placeholder || t("payment.checkout.promotion.placeholder"),
|
|
92
|
+
variant: "outlined",
|
|
93
|
+
size: "small",
|
|
94
|
+
disabled: applying,
|
|
95
|
+
autoFocus: true,
|
|
96
|
+
slotProps: {
|
|
97
|
+
input: {
|
|
98
|
+
endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
|
|
99
|
+
LoadingButton,
|
|
100
|
+
{
|
|
101
|
+
size: "small",
|
|
102
|
+
onClick: handleLoginCheck,
|
|
103
|
+
loading: applying,
|
|
104
|
+
disabled: !code.trim(),
|
|
105
|
+
variant: "text",
|
|
106
|
+
sx: {
|
|
107
|
+
color: "primary.main",
|
|
108
|
+
fontSize: "small"
|
|
109
|
+
},
|
|
110
|
+
children: t("payment.checkout.promotion.apply")
|
|
111
|
+
}
|
|
112
|
+
) })
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
sx: {
|
|
116
|
+
"& .MuiOutlinedInput-root": {
|
|
117
|
+
pr: 1
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
),
|
|
122
|
+
error && /* @__PURE__ */ jsx(
|
|
123
|
+
Alert,
|
|
124
|
+
{
|
|
125
|
+
severity: "error",
|
|
126
|
+
sx: {
|
|
127
|
+
my: 1
|
|
128
|
+
},
|
|
129
|
+
children: error
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
) : /* @__PURE__ */ jsx(
|
|
135
|
+
Button,
|
|
136
|
+
{
|
|
137
|
+
onClick: () => setShowInput(true),
|
|
138
|
+
startIcon: /* @__PURE__ */ jsx(Add, { fontSize: "small" }),
|
|
139
|
+
variant: "text",
|
|
140
|
+
sx: {
|
|
141
|
+
fontWeight: "normal",
|
|
142
|
+
textTransform: "none",
|
|
143
|
+
justifyContent: "flex-start",
|
|
144
|
+
p: 0,
|
|
145
|
+
"&:hover": {
|
|
146
|
+
backgroundColor: "transparent",
|
|
147
|
+
textDecoration: "underline"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
children: t("payment.checkout.promotion.add_code")
|
|
151
|
+
}
|
|
152
|
+
)) });
|
|
153
|
+
}
|
package/es/contexts/payment.d.ts
CHANGED
|
@@ -19,6 +19,14 @@ export type PaymentContextType = {
|
|
|
19
19
|
api: Axios;
|
|
20
20
|
payable: boolean;
|
|
21
21
|
setPayable: (status: boolean) => void;
|
|
22
|
+
paymentState: {
|
|
23
|
+
paying: boolean;
|
|
24
|
+
stripePaying: boolean;
|
|
25
|
+
};
|
|
26
|
+
setPaymentState: (state: Partial<{
|
|
27
|
+
paying: boolean;
|
|
28
|
+
stripePaying: boolean;
|
|
29
|
+
}>) => void;
|
|
22
30
|
};
|
|
23
31
|
export type PaymentContextProps = {
|
|
24
32
|
session: import('@arcblock/did-connect-react/lib/types').SessionContext['session'];
|
package/es/contexts/payment.js
CHANGED
|
@@ -125,6 +125,13 @@ function PaymentProvider({
|
|
|
125
125
|
}, [session?.user]);
|
|
126
126
|
const prefix = getPrefix();
|
|
127
127
|
const [payable, setPayable] = useState(true);
|
|
128
|
+
const [paymentState, setPaymentState] = useState({
|
|
129
|
+
paying: false,
|
|
130
|
+
stripePaying: false
|
|
131
|
+
});
|
|
132
|
+
const updatePaymentState = (state) => {
|
|
133
|
+
setPaymentState((prev) => ({ ...prev, ...state }));
|
|
134
|
+
};
|
|
128
135
|
if (error) {
|
|
129
136
|
return /* @__PURE__ */ jsx(Alert, { severity: "error", children: error.message });
|
|
130
137
|
}
|
|
@@ -146,7 +153,9 @@ function PaymentProvider({
|
|
|
146
153
|
setLivemode,
|
|
147
154
|
api,
|
|
148
155
|
payable,
|
|
149
|
-
setPayable
|
|
156
|
+
setPayable,
|
|
157
|
+
paymentState,
|
|
158
|
+
setPaymentState: updatePaymentState
|
|
150
159
|
},
|
|
151
160
|
children
|
|
152
161
|
}
|
package/es/index.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ import DateRangePicker from './components/date-range-picker';
|
|
|
39
39
|
import AutoTopupModal from './components/auto-topup/modal';
|
|
40
40
|
import AutoTopup from './components/auto-topup';
|
|
41
41
|
import Collapse from './components/collapse';
|
|
42
|
+
import PromotionCode from './components/promotion-code';
|
|
42
43
|
export { PaymentThemeProvider } from './theme';
|
|
43
44
|
export * from './libs/util';
|
|
44
45
|
export * from './libs/connect';
|
|
@@ -53,4 +54,4 @@ export * from './hooks/scroll';
|
|
|
53
54
|
export * from './hooks/keyboard';
|
|
54
55
|
export * from './libs/validator';
|
|
55
56
|
export { translations, createTranslator } from './locales';
|
|
56
|
-
export { createLazyComponent, api, dayjs, FormInput, FormLabel, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, PaymentBeneficiaries, LoadingButton, DonateDetails, ResumeSubscription, CreditGrantsList, CreditTransactionsList, DateRangePicker, CreditStatusChip, AutoTopupModal, AutoTopup, Collapse, };
|
|
57
|
+
export { createLazyComponent, api, dayjs, FormInput, FormLabel, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, PaymentBeneficiaries, LoadingButton, DonateDetails, ResumeSubscription, CreditGrantsList, CreditTransactionsList, DateRangePicker, CreditStatusChip, AutoTopupModal, AutoTopup, Collapse, PromotionCode, };
|
package/es/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import DateRangePicker from "./components/date-range-picker.js";
|
|
|
39
39
|
import AutoTopupModal from "./components/auto-topup/modal.js";
|
|
40
40
|
import AutoTopup from "./components/auto-topup/index.js";
|
|
41
41
|
import Collapse from "./components/collapse.js";
|
|
42
|
+
import PromotionCode from "./components/promotion-code.js";
|
|
42
43
|
export { PaymentThemeProvider } from "./theme/index.js";
|
|
43
44
|
export * from "./libs/util.js";
|
|
44
45
|
export * from "./libs/connect.js";
|
|
@@ -96,5 +97,6 @@ export {
|
|
|
96
97
|
CreditStatusChip,
|
|
97
98
|
AutoTopupModal,
|
|
98
99
|
AutoTopup,
|
|
99
|
-
Collapse
|
|
100
|
+
Collapse,
|
|
101
|
+
PromotionCode
|
|
100
102
|
};
|
package/es/libs/util.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type { PaymentDetails, PriceCurrency, PriceRecurring, TInvoiceExpanded, TLineItemExpanded, TPaymentCurrency, TPaymentCurrencyExpanded, TPaymentMethod, TPaymentMethodExpanded, TPrice, TProductExpanded, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
1
|
+
import type { PaymentDetails, PriceCurrency, PriceRecurring, TCoupon, TInvoiceExpanded, TLineItemExpanded, TPaymentCurrency, TPaymentCurrencyExpanded, TPaymentMethod, TPaymentMethodExpanded, TPrice, TProductExpanded, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
2
2
|
import type { ActionProps, PricingRenderProps } from '../types';
|
|
3
3
|
export declare const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
4
|
+
/**
|
|
5
|
+
* Format coupon discount terms for display
|
|
6
|
+
*/
|
|
7
|
+
export declare const formatCouponTerms: (coupon: TCoupon, currency: TPaymentCurrency, locale?: string) => string;
|
|
4
8
|
export declare const isPaymentKitMounted: () => any;
|
|
5
9
|
export declare const getPrefix: () => string;
|
|
6
10
|
export declare function isCrossOrigin(): boolean;
|
package/es/libs/util.js
CHANGED
|
@@ -8,6 +8,29 @@ import { joinURL, withQuery } from "ufo";
|
|
|
8
8
|
import { t } from "../locales/index.js";
|
|
9
9
|
import dayjs from "./dayjs.js";
|
|
10
10
|
export const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
11
|
+
export const formatCouponTerms = (coupon, currency, locale = "en") => {
|
|
12
|
+
let couponOff = "";
|
|
13
|
+
if (coupon.percent_off && coupon.percent_off > 0) {
|
|
14
|
+
couponOff = t("payment.checkout.coupon.percentage", locale, { percent: coupon.percent_off });
|
|
15
|
+
}
|
|
16
|
+
if (coupon.amount_off && coupon.amount_off !== "0") {
|
|
17
|
+
const { symbol } = currency;
|
|
18
|
+
couponOff = coupon.currency_id === currency.id ? coupon.amount_off || "" : coupon.currency_options?.[currency.id]?.amount_off || "";
|
|
19
|
+
if (couponOff) {
|
|
20
|
+
couponOff = t("payment.checkout.coupon.fixedAmount", locale, {
|
|
21
|
+
amount: formatAmount(couponOff, currency.decimal),
|
|
22
|
+
symbol
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!couponOff) {
|
|
27
|
+
return t("payment.checkout.coupon.noDiscount");
|
|
28
|
+
}
|
|
29
|
+
return t(`payment.checkout.coupon.terms.${coupon.duration}`, locale, {
|
|
30
|
+
couponOff,
|
|
31
|
+
months: coupon.duration_in_months || 0
|
|
32
|
+
});
|
|
33
|
+
};
|
|
11
34
|
export const isPaymentKitMounted = () => {
|
|
12
35
|
return (window.blocklet?.componentMountPoints || []).some((x) => x.did === PAYMENT_KIT_DID);
|
|
13
36
|
};
|
package/es/locales/en.js
CHANGED
|
@@ -102,8 +102,8 @@ export default flat({
|
|
|
102
102
|
know: "I know",
|
|
103
103
|
relatedSubscription: "Subscription",
|
|
104
104
|
connect: {
|
|
105
|
-
defaultScan: "Use following methods to complete this action",
|
|
106
|
-
scan: "Use following methods to complete this {action}",
|
|
105
|
+
defaultScan: "Use the following methods to complete this action",
|
|
106
|
+
scan: "Use the following methods to complete this {action}",
|
|
107
107
|
confirm: "Confirm",
|
|
108
108
|
cancel: "Cancel"
|
|
109
109
|
},
|
|
@@ -153,14 +153,14 @@ export default flat({
|
|
|
153
153
|
},
|
|
154
154
|
inactive: "Donation feature is not enabled",
|
|
155
155
|
enable: "Enable Donation",
|
|
156
|
-
enableSuccess: "
|
|
157
|
-
configPrompt: "
|
|
156
|
+
enableSuccess: "Successfully enabled",
|
|
157
|
+
configPrompt: "The donation feature is enabled. You can configure donation options in Payment Kit",
|
|
158
158
|
configNow: "Configure Now",
|
|
159
159
|
later: "Configure Later",
|
|
160
160
|
configTip: "Configure donation settings in Payment Kit"
|
|
161
161
|
},
|
|
162
162
|
cardPay: "{action} with bank card",
|
|
163
|
-
empty: "
|
|
163
|
+
empty: "Nothing to pay",
|
|
164
164
|
per: "per",
|
|
165
165
|
pay: "Pay {payee}",
|
|
166
166
|
try1: "Try {name}",
|
|
@@ -174,8 +174,8 @@ export default flat({
|
|
|
174
174
|
least: "continue with at least",
|
|
175
175
|
completed: {
|
|
176
176
|
payment: "Thanks for your purchase",
|
|
177
|
-
subscription: "Thanks for
|
|
178
|
-
setup: "Thanks for
|
|
177
|
+
subscription: "Thanks for subscribing",
|
|
178
|
+
setup: "Thanks for subscribing",
|
|
179
179
|
donate: "Thanks for your tip",
|
|
180
180
|
tip: "A payment to {payee} has been completed. You can view the details of this payment in your account."
|
|
181
181
|
},
|
|
@@ -184,7 +184,7 @@ export default flat({
|
|
|
184
184
|
progress: "Progress {progress}%",
|
|
185
185
|
delivered: "Installation completed",
|
|
186
186
|
failed: "Processing failed",
|
|
187
|
-
failedMsg: "An exception occurred during installation. We will automatically process a refund for you. We apologize for the inconvenience
|
|
187
|
+
failedMsg: "An exception occurred during installation. We will automatically process a refund for you. We apologize for the inconvenience. Thank you for your understanding!"
|
|
188
188
|
},
|
|
189
189
|
confirm: {
|
|
190
190
|
withStake: "By confirming, you allow {payee} to charge your account for future payments and, if necessary, slash your stake. You can cancel your subscription or withdraw your stake at any time.",
|
|
@@ -233,14 +233,39 @@ export default flat({
|
|
|
233
233
|
},
|
|
234
234
|
emptyItems: {
|
|
235
235
|
title: "Nothing to show here",
|
|
236
|
-
description: "
|
|
236
|
+
description: "It seems this checkout session is not configured properly"
|
|
237
237
|
},
|
|
238
238
|
orderSummary: "Order Summary",
|
|
239
239
|
paymentDetails: "Payment Details",
|
|
240
240
|
productListTotal: "Includes {total} items",
|
|
241
|
+
promotion: {
|
|
242
|
+
add_code: "Add promotion code",
|
|
243
|
+
enter_code: "Enter promotion code",
|
|
244
|
+
placeholder: "Enter code",
|
|
245
|
+
apply: "Apply",
|
|
246
|
+
applied: "Applied promotion codes",
|
|
247
|
+
dialog: {
|
|
248
|
+
title: "Add promotion code"
|
|
249
|
+
},
|
|
250
|
+
error: {
|
|
251
|
+
unknown: "Unknown error",
|
|
252
|
+
network: "Network error occurred",
|
|
253
|
+
removal: "Failed to remove code"
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
coupon: {
|
|
257
|
+
noDiscount: "No discount",
|
|
258
|
+
percentage: "{percent}% off",
|
|
259
|
+
fixedAmount: "{amount} {symbol} off",
|
|
260
|
+
terms: {
|
|
261
|
+
forever: "{couponOff} forever",
|
|
262
|
+
once: "{couponOff} once",
|
|
263
|
+
repeating: "{couponOff} for {months} month{months > 1 ? 's' : ''}"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
241
266
|
connectModal: {
|
|
242
267
|
title: "{action}",
|
|
243
|
-
scan: "Use following methods to complete this payment",
|
|
268
|
+
scan: "Use the following methods to complete this payment",
|
|
244
269
|
confirm: "Confirm",
|
|
245
270
|
cancel: "Cancel"
|
|
246
271
|
},
|
|
@@ -323,7 +348,7 @@ export default flat({
|
|
|
323
348
|
summary: "Summary",
|
|
324
349
|
products: "Products",
|
|
325
350
|
update: "Update Information",
|
|
326
|
-
empty: "
|
|
351
|
+
empty: "It seems you do not have any subscriptions or payments here",
|
|
327
352
|
cancel: {
|
|
328
353
|
button: "Unsubscribe",
|
|
329
354
|
title: "Cancel your subscription",
|
|
@@ -334,7 +359,7 @@ export default flat({
|
|
|
334
359
|
tip: "We would love your feedback, it will help us improve our service",
|
|
335
360
|
too_expensive: "The service is too expensive",
|
|
336
361
|
missing_features: "Features are missing for this service",
|
|
337
|
-
switched_service: "I have switched to alternative service",
|
|
362
|
+
switched_service: "I have switched to an alternative service",
|
|
338
363
|
unused: "I no longer use this service",
|
|
339
364
|
customer_service: "The customer service is poor",
|
|
340
365
|
too_complex: "The service is too complex to use",
|
|
@@ -345,7 +370,7 @@ export default flat({
|
|
|
345
370
|
pastDue: {
|
|
346
371
|
button: "Pay",
|
|
347
372
|
invoices: "Past Due Invoices",
|
|
348
|
-
warning: "Past due invoices need to be paid immediately, otherwise you
|
|
373
|
+
warning: "Past due invoices need to be paid immediately, otherwise you cannot make new purchases anymore.",
|
|
349
374
|
alert: {
|
|
350
375
|
title: "You have unpaid invoices",
|
|
351
376
|
customMessage: "Please pay immediately, otherwise new purchases or subscriptions will be prohibited.",
|
|
@@ -398,7 +423,7 @@ export default flat({
|
|
|
398
423
|
amountApplied: "Applied Credit",
|
|
399
424
|
pay: "Pay this invoice",
|
|
400
425
|
paySuccess: "You have successfully paid the invoice",
|
|
401
|
-
payError: "Failed to
|
|
426
|
+
payError: "Failed to pay the invoice",
|
|
402
427
|
renew: "Renew the subscription",
|
|
403
428
|
renewSuccess: "You have successfully renewed the subscription",
|
|
404
429
|
renewError: "Failed to renew the subscription",
|
|
@@ -426,7 +451,7 @@ export default flat({
|
|
|
426
451
|
viewAll: "View all",
|
|
427
452
|
empty: "There are no subscriptions here",
|
|
428
453
|
changePayment: "Change payment method",
|
|
429
|
-
trialLeft: "
|
|
454
|
+
trialLeft: "Trial Left",
|
|
430
455
|
owner: "Subscription Owner"
|
|
431
456
|
},
|
|
432
457
|
overdue: {
|
package/es/locales/zh.js
CHANGED
|
@@ -226,6 +226,35 @@ export default flat({
|
|
|
226
226
|
add: "\u6DFB\u52A0\u5230\u8BA2\u5355",
|
|
227
227
|
remove: "\u4ECE\u8BA2\u5355\u79FB\u9664"
|
|
228
228
|
},
|
|
229
|
+
promotion: {
|
|
230
|
+
add_code: "\u6DFB\u52A0\u4FC3\u9500\u7801",
|
|
231
|
+
enter_code: "\u8F93\u5165\u4FC3\u9500\u7801",
|
|
232
|
+
apply: "\u5E94\u7528",
|
|
233
|
+
applied: "\u5DF2\u5E94\u7528\u7684\u4FC3\u9500\u7801",
|
|
234
|
+
placeholder: "\u8F93\u5165\u4FC3\u9500\u7801",
|
|
235
|
+
duration_once: "1\u6B21\u4F18\u60E0 {amount} {symbol}",
|
|
236
|
+
duration_repeating: "{months}\u4E2A\u6708\u4F18\u60E0 {amount} {symbol}",
|
|
237
|
+
duration_forever: "\u6C38\u4E45\u4F18\u60E0 {amount} {symbol}",
|
|
238
|
+
dialog: {
|
|
239
|
+
title: "\u6DFB\u52A0\u4FC3\u9500\u7801"
|
|
240
|
+
},
|
|
241
|
+
error: {
|
|
242
|
+
invalid: "\u65E0\u6548\u7684\u4FC3\u9500\u7801",
|
|
243
|
+
expired: "\u4FC3\u9500\u7801\u5DF2\u8FC7\u671F",
|
|
244
|
+
used: "\u4FC3\u9500\u7801\u5DF2\u88AB\u4F7F\u7528",
|
|
245
|
+
not_applicable: "\u4FC3\u9500\u7801\u4E0D\u9002\u7528\u4E8E\u6B64\u8BA2\u5355"
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
coupon: {
|
|
249
|
+
noDiscount: "\u65E0\u4F18\u60E0",
|
|
250
|
+
percentage: "{percent}%",
|
|
251
|
+
fixedAmount: "{amount} {symbol}",
|
|
252
|
+
terms: {
|
|
253
|
+
forever: "\u6C38\u4E45\u4EAB {couponOff} \u6298\u6263",
|
|
254
|
+
once: "\u5355\u6B21\u4EAB {couponOff} \u6298\u6263",
|
|
255
|
+
repeating: "{months} \u4E2A\u6708\u5185\u4EAB {couponOff} \u6298\u6263"
|
|
256
|
+
}
|
|
257
|
+
},
|
|
229
258
|
credit: {
|
|
230
259
|
oneTimeInfo: "\u4ED8\u6B3E\u5B8C\u6210\u540E\u60A8\u5C06\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
|
|
231
260
|
recurringInfo: "\u60A8\u5C06{period}\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
|
package/es/payment/form/index.js
CHANGED
|
@@ -103,7 +103,7 @@ export default function PaymentForm({
|
|
|
103
103
|
}) {
|
|
104
104
|
const { t, locale } = useLocaleContext();
|
|
105
105
|
const { isMobile } = useMobile();
|
|
106
|
-
const { session, connect, payable } = usePaymentContext();
|
|
106
|
+
const { session, connect, payable, setPaymentState } = usePaymentContext();
|
|
107
107
|
const subscription = useSubscription("events");
|
|
108
108
|
const formErrorPosition = "bottom";
|
|
109
109
|
const {
|
|
@@ -150,6 +150,12 @@ export default function PaymentForm({
|
|
|
150
150
|
subscription.on("checkout.session.completed", onCheckoutComplete);
|
|
151
151
|
}
|
|
152
152
|
}, [subscription]);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
setPaymentState({
|
|
155
|
+
paying: state.submitting || state.paying,
|
|
156
|
+
stripePaying: state.stripePaying
|
|
157
|
+
});
|
|
158
|
+
}, [state.submitting, state.paying, state.stripePaying]);
|
|
153
159
|
const mergeUserInfo = (customerInfo, userInfo) => {
|
|
154
160
|
return {
|
|
155
161
|
...userInfo || {},
|
package/es/payment/index.js
CHANGED
|
@@ -139,6 +139,13 @@ function PaymentInner({
|
|
|
139
139
|
if (onChange) {
|
|
140
140
|
onChange(methods.getValues());
|
|
141
141
|
}
|
|
142
|
+
if (state.checkoutSession?.discounts?.length) {
|
|
143
|
+
api.post(`/api/checkout-sessions/${state.checkoutSession.id}/recalculate-promotion`, {
|
|
144
|
+
currency_id: currencyId
|
|
145
|
+
}).then(() => {
|
|
146
|
+
onPromotionUpdate();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
142
149
|
}, [currencyId]);
|
|
143
150
|
const onUpsell = async (from, to) => {
|
|
144
151
|
try {
|
|
@@ -200,6 +207,15 @@ function PaymentInner({
|
|
|
200
207
|
Toast.error(formatError(err));
|
|
201
208
|
}
|
|
202
209
|
};
|
|
210
|
+
const onPromotionUpdate = async () => {
|
|
211
|
+
try {
|
|
212
|
+
const { data } = await api.get(`/api/checkout-sessions/retrieve/${state.checkoutSession.id}`);
|
|
213
|
+
setState({ checkoutSession: data.checkoutSession });
|
|
214
|
+
} catch (err) {
|
|
215
|
+
console.error(err);
|
|
216
|
+
Toast.error(formatError(err));
|
|
217
|
+
}
|
|
218
|
+
};
|
|
203
219
|
const handlePaid = (result) => {
|
|
204
220
|
setState({ checkoutSession: result.checkoutSession });
|
|
205
221
|
onPaid(result);
|
|
@@ -238,6 +254,9 @@ function PaymentInner({
|
|
|
238
254
|
donationSettings: paymentLink?.donation_settings,
|
|
239
255
|
action,
|
|
240
256
|
completed,
|
|
257
|
+
checkoutSession: state.checkoutSession,
|
|
258
|
+
onPromotionUpdate,
|
|
259
|
+
paymentMethods,
|
|
241
260
|
showFeatures
|
|
242
261
|
}
|
|
243
262
|
),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
-
import { Box, Stack, Typography, IconButton, TextField, Alert } from "@mui/material";
|
|
4
|
-
import { Add, Remove } from "@mui/icons-material";
|
|
3
|
+
import { Box, Stack, Typography, IconButton, TextField, Alert, Chip } from "@mui/material";
|
|
4
|
+
import { Add, Remove, LocalOffer } from "@mui/icons-material";
|
|
5
5
|
import { useMemo, useState } from "react";
|
|
6
6
|
import Status from "../components/status.js";
|
|
7
7
|
import Switch from "../components/switch-button.js";
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
formatPrice,
|
|
13
13
|
formatQuantityInventory,
|
|
14
14
|
formatRecurring,
|
|
15
|
-
formatUpsellSaving
|
|
15
|
+
formatUpsellSaving,
|
|
16
|
+
formatAmount
|
|
16
17
|
} from "../libs/util.js";
|
|
17
18
|
import ProductCard from "./product-card.js";
|
|
18
19
|
import dayjs from "../libs/dayjs.js";
|
|
@@ -183,6 +184,34 @@ export default function ProductItem({
|
|
|
183
184
|
]
|
|
184
185
|
}
|
|
185
186
|
),
|
|
187
|
+
item.discount_amounts && item.discount_amounts.length > 0 && /* @__PURE__ */ jsx(Stack, { direction: "row", spacing: 1, sx: { mt: 1, alignItems: "center" }, children: item.discount_amounts.map((discountAmount) => /* @__PURE__ */ jsx(
|
|
188
|
+
Chip,
|
|
189
|
+
{
|
|
190
|
+
icon: /* @__PURE__ */ jsx(LocalOffer, { sx: { fontSize: "0.8rem !important" } }),
|
|
191
|
+
label: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
|
|
192
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { fontSize: "0.75rem", fontWeight: "medium" }, children: discountAmount.promotion_code?.code || "DISCOUNT" }),
|
|
193
|
+
/* @__PURE__ */ jsxs(Typography, { component: "span", sx: { fontSize: "0.75rem" }, children: [
|
|
194
|
+
"(-",
|
|
195
|
+
formatAmount(discountAmount.amount || "0", currency.decimal),
|
|
196
|
+
" ",
|
|
197
|
+
currency.symbol,
|
|
198
|
+
")"
|
|
199
|
+
] })
|
|
200
|
+
] }),
|
|
201
|
+
size: "small",
|
|
202
|
+
variant: "filled",
|
|
203
|
+
sx: {
|
|
204
|
+
height: 20,
|
|
205
|
+
"& .MuiChip-icon": {
|
|
206
|
+
color: "warning.main"
|
|
207
|
+
},
|
|
208
|
+
"& .MuiChip-label": {
|
|
209
|
+
px: 1
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
discountAmount.promotion_code
|
|
214
|
+
)) }),
|
|
186
215
|
showFeatures && features.length > 0 && /* @__PURE__ */ jsx(
|
|
187
216
|
Box,
|
|
188
217
|
{
|
package/es/payment/summary.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
|
|
1
|
+
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency, TCheckoutSession, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
2
2
|
type Props = {
|
|
3
3
|
items: TLineItemExpanded[];
|
|
4
4
|
currency: TPaymentCurrency;
|
|
@@ -17,7 +17,10 @@ type Props = {
|
|
|
17
17
|
donationSettings?: DonationSettings;
|
|
18
18
|
action?: string;
|
|
19
19
|
completed?: boolean;
|
|
20
|
+
checkoutSession?: TCheckoutSession;
|
|
21
|
+
onPromotionUpdate?: () => void;
|
|
22
|
+
paymentMethods?: TPaymentMethodExpanded[];
|
|
20
23
|
showFeatures?: boolean;
|
|
21
24
|
};
|
|
22
|
-
export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onQuantityChange, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, completed, showFeatures, ...rest }: Props): import("react").JSX.Element;
|
|
25
|
+
export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onQuantityChange, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, completed, checkoutSession, paymentMethods, onPromotionUpdate, showFeatures, ...rest }: Props): import("react").JSX.Element;
|
|
23
26
|
export {};
|