@blocklet/payment-react 1.19.0 → 1.19.2
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/blockchain/tx.d.ts +1 -1
- package/es/components/blockchain/tx.js +9 -11
- package/es/components/country-select.d.ts +1 -1
- package/es/components/date-range-picker.d.ts +13 -0
- package/es/components/date-range-picker.js +279 -0
- package/es/components/input.d.ts +5 -2
- package/es/components/input.js +6 -2
- package/es/components/label.d.ts +7 -0
- package/es/components/label.js +50 -0
- package/es/components/loading-button.d.ts +1 -1
- package/es/history/credit/grants-list.d.ts +14 -0
- package/es/history/credit/grants-list.js +215 -0
- package/es/history/credit/transactions-list.d.ts +13 -0
- package/es/history/credit/transactions-list.js +254 -0
- package/es/history/invoice/list.js +21 -1
- package/es/index.d.ts +5 -1
- package/es/index.js +10 -1
- package/es/libs/util.d.ts +2 -0
- package/es/libs/util.js +12 -0
- package/es/locales/en.js +20 -2
- package/es/locales/zh.js +20 -2
- package/es/payment/form/address.js +2 -1
- package/es/payment/form/index.js +46 -7
- package/es/payment/index.js +18 -3
- package/es/payment/product-item.d.ts +8 -1
- package/es/payment/product-item.js +137 -5
- package/es/payment/summary.d.ts +3 -1
- package/es/payment/summary.js +9 -0
- package/lib/components/blockchain/tx.d.ts +1 -1
- package/lib/components/blockchain/tx.js +9 -8
- package/lib/components/country-select.d.ts +1 -1
- package/lib/components/date-range-picker.d.ts +13 -0
- package/lib/components/date-range-picker.js +329 -0
- package/lib/components/input.d.ts +5 -2
- package/lib/components/input.js +8 -4
- package/lib/components/label.d.ts +7 -0
- package/lib/components/label.js +62 -0
- package/lib/components/loading-button.d.ts +1 -1
- package/lib/history/credit/grants-list.d.ts +14 -0
- package/lib/history/credit/grants-list.js +277 -0
- package/lib/history/credit/transactions-list.d.ts +13 -0
- package/lib/history/credit/transactions-list.js +300 -0
- package/lib/history/invoice/list.js +24 -0
- package/lib/index.d.ts +5 -1
- package/lib/index.js +39 -0
- package/lib/libs/util.d.ts +2 -0
- package/lib/libs/util.js +14 -0
- package/lib/locales/en.js +20 -2
- package/lib/locales/zh.js +20 -2
- package/lib/payment/form/address.js +6 -5
- package/lib/payment/form/index.js +49 -9
- package/lib/payment/index.js +20 -2
- package/lib/payment/product-item.d.ts +8 -1
- package/lib/payment/product-item.js +144 -4
- package/lib/payment/summary.d.ts +3 -1
- package/lib/payment/summary.js +9 -0
- package/package.json +3 -3
- package/src/components/blockchain/tx.tsx +9 -15
- package/src/components/country-select.tsx +2 -2
- package/src/components/date-range-picker.tsx +310 -0
- package/src/components/input.tsx +14 -3
- package/src/components/label.tsx +59 -0
- package/src/components/loading-button.tsx +1 -1
- package/src/history/credit/grants-list.tsx +276 -0
- package/src/history/credit/transactions-list.tsx +316 -0
- package/src/history/invoice/list.tsx +18 -1
- package/src/index.ts +9 -0
- package/src/libs/util.ts +14 -0
- package/src/locales/en.tsx +20 -0
- package/src/locales/zh.tsx +19 -0
- package/src/payment/form/address.tsx +4 -3
- package/src/payment/form/index.tsx +112 -53
- package/src/payment/index.tsx +17 -1
- package/src/payment/product-item.tsx +152 -4
- package/src/payment/summary.tsx +13 -2
package/es/locales/zh.js
CHANGED
|
@@ -31,6 +31,10 @@ export default flat({
|
|
|
31
31
|
change: "\u66F4\u6362",
|
|
32
32
|
confirm: "\u786E\u8BA4",
|
|
33
33
|
cancel: "\u53D6\u6D88",
|
|
34
|
+
clear: "\u6E05\u7A7A",
|
|
35
|
+
selectTimeRange: "\u9009\u62E9\u65F6\u95F4\u8303\u56F4",
|
|
36
|
+
startDate: "\u5F00\u59CB\u65E5\u671F",
|
|
37
|
+
endDate: "\u7ED3\u675F\u65E5\u671F",
|
|
34
38
|
close: "\u5173\u95ED",
|
|
35
39
|
back: "\u8FD4\u56DE",
|
|
36
40
|
every: "\u6BCF",
|
|
@@ -100,7 +104,8 @@ export default flat({
|
|
|
100
104
|
scan: "\u4F7F\u7528\u4EE5\u4E0B\u65B9\u5F0F\u5B8C\u6210\u672C\u6B21{action}",
|
|
101
105
|
confirm: "\u786E\u8BA4",
|
|
102
106
|
cancel: "\u53D6\u6D88"
|
|
103
|
-
}
|
|
107
|
+
},
|
|
108
|
+
paymentMethod: "\u652F\u4ED8\u65B9\u5F0F"
|
|
104
109
|
},
|
|
105
110
|
payment: {
|
|
106
111
|
checkout: {
|
|
@@ -212,6 +217,11 @@ export default flat({
|
|
|
212
217
|
add: "\u6DFB\u52A0\u5230\u8BA2\u5355",
|
|
213
218
|
remove: "\u4ECE\u8BA2\u5355\u79FB\u9664"
|
|
214
219
|
},
|
|
220
|
+
credit: {
|
|
221
|
+
oneTimeInfo: "\u4ED8\u6B3E\u5B8C\u6210\u540E\u60A8\u5C06\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
|
|
222
|
+
recurringInfo: "\u60A8\u5C06{period}\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
|
|
223
|
+
expiresIn: "\u989D\u5EA6\u6709\u6548\u671F\u4E3A {duration} {unit}"
|
|
224
|
+
},
|
|
215
225
|
emptyItems: {
|
|
216
226
|
title: "\u6CA1\u6709\u4EFB\u4F55\u8D2D\u4E70\u9879\u76EE",
|
|
217
227
|
description: "\u53EF\u80FD\u8FD9\u4E2A\u4ED8\u6B3E\u94FE\u63A5\u6CA1\u6709\u6B63\u786E\u914D\u7F6E"
|
|
@@ -232,7 +242,15 @@ export default flat({
|
|
|
232
242
|
payer: "\u8D26\u6237\u5730\u5740",
|
|
233
243
|
amount: "\u652F\u4ED8\u91D1\u989D",
|
|
234
244
|
failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002",
|
|
235
|
-
balanceLink: "\u67E5\u770B\u4F59\u989D"
|
|
245
|
+
balanceLink: "\u67E5\u770B\u4F59\u989D",
|
|
246
|
+
credit: {
|
|
247
|
+
title: "\u786E\u8BA4\u989D\u5EA6\u652F\u4ED8",
|
|
248
|
+
availableAmount: "\u53EF\u7528\u989D\u5EA6\uFF1A{amount}",
|
|
249
|
+
confirmMessage: "\u60A8\u5C06\u4F7F\u7528 {amount} \u989D\u5EA6\u6765\u8BA2\u9605\u6B64\u670D\u52A1\u3002",
|
|
250
|
+
meteringSubscriptionMessage: "\u6B64\u8BA2\u9605\u670D\u52A1\u5C06\u6839\u636E\u5B9E\u9645\u4F7F\u7528\u60C5\u51B5\u5B9E\u65F6\u6263\u9664\u989D\u5EA6\u3002\u60A8\u5F53\u524D\u53EF\u7528\u989D\u5EA6\u4E3A {available}\uFF0C\u786E\u8BA4\u662F\u5426\u7EE7\u7EED\uFF1F",
|
|
251
|
+
insufficientTitle: "\u989D\u5EA6\u4E0D\u8DB3",
|
|
252
|
+
insufficientMessage: "\u6B64\u8BA2\u9605\u670D\u52A1\u5C06\u6839\u636E\u5B9E\u9645\u4F7F\u7528\u60C5\u51B5\u5B9E\u65F6\u6263\u9664\u989D\u5EA6\u3002\u60A8\u5F53\u524D\u53EF\u7528\u989D\u5EA6\u4E0D\u8DB3\uFF0C\u8BF7\u5148\u5145\u503C\u989D\u5EA6\u3002"
|
|
253
|
+
}
|
|
236
254
|
}
|
|
237
255
|
},
|
|
238
256
|
customer: {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
-
import { Fade,
|
|
3
|
+
import { Fade, InputAdornment, Stack } from "@mui/material";
|
|
4
4
|
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
|
5
5
|
import FormInput from "../../components/input.js";
|
|
6
|
+
import FormLabel from "../../components/label.js";
|
|
6
7
|
import CountrySelect from "../../components/country-select.js";
|
|
7
8
|
import { getFieldValidation, validatePostalCode } from "../../libs/validator.js";
|
|
8
9
|
export default function AddressForm({ mode, stripe, sx = {}, fieldValidation = {}, errorPosition = "right" }) {
|
package/es/payment/form/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import "react-international-phone/style.css";
|
|
3
3
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
4
4
|
import Toast from "@arcblock/ux/lib/Toast";
|
|
5
|
-
import { Box, Button, CircularProgress, Divider, Fade,
|
|
5
|
+
import { Box, Button, CircularProgress, Divider, Fade, Stack, Tooltip, Typography } from "@mui/material";
|
|
6
6
|
import { useMemoizedFn, useSetState } from "ahooks";
|
|
7
7
|
import pWaitFor from "p-wait-for";
|
|
8
8
|
import { useEffect, useMemo, useRef } from "react";
|
|
@@ -15,6 +15,7 @@ import DID from "@arcblock/ux/lib/DID";
|
|
|
15
15
|
import isEmpty from "lodash/isEmpty";
|
|
16
16
|
import { HelpOutline, OpenInNew } from "@mui/icons-material";
|
|
17
17
|
import FormInput from "../../components/input.js";
|
|
18
|
+
import FormLabel from "../../components/label.js";
|
|
18
19
|
import { usePaymentContext } from "../../contexts/payment.js";
|
|
19
20
|
import { useSubscription } from "../../hooks/subscription.js";
|
|
20
21
|
import api from "../../libs/api.js";
|
|
@@ -131,7 +132,8 @@ export default function PaymentForm({
|
|
|
131
132
|
customer,
|
|
132
133
|
customerLimited: false,
|
|
133
134
|
stripePaying: false,
|
|
134
|
-
fastCheckoutInfo: null
|
|
135
|
+
fastCheckoutInfo: null,
|
|
136
|
+
creditInsufficientInfo: null
|
|
135
137
|
});
|
|
136
138
|
const currencies = flattenPaymentMethods(paymentMethods);
|
|
137
139
|
const onCheckoutComplete = useMemoizedFn(async ({ response }) => {
|
|
@@ -300,6 +302,9 @@ export default function PaymentForm({
|
|
|
300
302
|
const handleFastCheckoutCancel = () => {
|
|
301
303
|
setState({ fastCheckoutInfo: null });
|
|
302
304
|
};
|
|
305
|
+
const handleCreditInsufficientClose = () => {
|
|
306
|
+
setState({ creditInsufficientInfo: null });
|
|
307
|
+
};
|
|
303
308
|
const openConnect = () => {
|
|
304
309
|
try {
|
|
305
310
|
if (!["arcblock", "ethereum", "base"].includes(method.type)) {
|
|
@@ -355,7 +360,27 @@ export default function PaymentForm({
|
|
|
355
360
|
customerLimited: false
|
|
356
361
|
});
|
|
357
362
|
if (["arcblock", "ethereum", "base"].includes(method.type)) {
|
|
358
|
-
if (
|
|
363
|
+
if (paymentCurrency?.type === "credit") {
|
|
364
|
+
if (result.data.creditSufficient === true) {
|
|
365
|
+
setState({
|
|
366
|
+
fastCheckoutInfo: {
|
|
367
|
+
open: true,
|
|
368
|
+
loading: false,
|
|
369
|
+
sourceType: "credit",
|
|
370
|
+
amount: result.data.fastPayInfo?.amount || "0",
|
|
371
|
+
payer: result.data.fastPayInfo?.payer,
|
|
372
|
+
availableCredit: result.data.fastPayInfo?.amount || "0",
|
|
373
|
+
balance: result.data.fastPayInfo?.token?.balance || "0"
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
} else {
|
|
377
|
+
setState({
|
|
378
|
+
creditInsufficientInfo: {
|
|
379
|
+
open: true
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
} else if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode && result.data.fastPayInfo) {
|
|
359
384
|
setState({
|
|
360
385
|
fastCheckoutInfo: {
|
|
361
386
|
open: true,
|
|
@@ -445,8 +470,10 @@ export default function PaymentForm({
|
|
|
445
470
|
{
|
|
446
471
|
onConfirm: handleFastCheckoutConfirm,
|
|
447
472
|
onCancel: handleFastCheckoutCancel,
|
|
448
|
-
title: t("payment.checkout.fastPay.title"),
|
|
449
|
-
message: /* @__PURE__ */
|
|
473
|
+
title: state.fastCheckoutInfo.sourceType === "credit" ? t("payment.checkout.fastPay.credit.title") : t("payment.checkout.fastPay.title"),
|
|
474
|
+
message: state.fastCheckoutInfo.sourceType === "credit" ? /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.fastPay.credit.meteringSubscriptionMessage", {
|
|
475
|
+
available: `${fromUnitToToken(state.fastCheckoutInfo?.balance || "0", paymentCurrency?.decimal || 18).toString()} ${paymentCurrency?.symbol}`
|
|
476
|
+
}) }) : /* @__PURE__ */ jsxs(Stack, { children: [
|
|
450
477
|
/* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.fastPay.autoPaymentReason") }),
|
|
451
478
|
/* @__PURE__ */ jsx(Divider, { sx: { mt: 1.5, mb: 1.5 } }),
|
|
452
479
|
/* @__PURE__ */ jsxs(Stack, { spacing: 1, children: [
|
|
@@ -521,6 +548,16 @@ export default function PaymentForm({
|
|
|
521
548
|
color: "primary"
|
|
522
549
|
}
|
|
523
550
|
);
|
|
551
|
+
const CreditInsufficientDialog = state.creditInsufficientInfo && /* @__PURE__ */ jsx(
|
|
552
|
+
ConfirmDialog,
|
|
553
|
+
{
|
|
554
|
+
onConfirm: handleCreditInsufficientClose,
|
|
555
|
+
onCancel: handleCreditInsufficientClose,
|
|
556
|
+
title: t("payment.checkout.fastPay.credit.insufficientTitle"),
|
|
557
|
+
message: /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.fastPay.credit.insufficientMessage") }),
|
|
558
|
+
confirm: t("common.confirm")
|
|
559
|
+
}
|
|
560
|
+
);
|
|
524
561
|
if (onlyShowBtn) {
|
|
525
562
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
526
563
|
/* @__PURE__ */ jsx(Box, { className: "cko-payment-submit-btn", children: /* @__PURE__ */ jsxs(
|
|
@@ -573,7 +610,8 @@ export default function PaymentForm({
|
|
|
573
610
|
}
|
|
574
611
|
}
|
|
575
612
|
),
|
|
576
|
-
FastCheckoutConfirmDialog
|
|
613
|
+
FastCheckoutConfirmDialog,
|
|
614
|
+
CreditInsufficientDialog
|
|
577
615
|
] });
|
|
578
616
|
}
|
|
579
617
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -768,6 +806,7 @@ export default function PaymentForm({
|
|
|
768
806
|
}
|
|
769
807
|
}
|
|
770
808
|
),
|
|
771
|
-
FastCheckoutConfirmDialog
|
|
809
|
+
FastCheckoutConfirmDialog,
|
|
810
|
+
CreditInsufficientDialog
|
|
772
811
|
] });
|
|
773
812
|
}
|
package/es/payment/index.js
CHANGED
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
getQueryParams,
|
|
19
19
|
getStatementDescriptor,
|
|
20
20
|
isMobileSafari,
|
|
21
|
-
isValidCountry
|
|
21
|
+
isValidCountry,
|
|
22
|
+
showStaking
|
|
22
23
|
} from "../libs/util.js";
|
|
23
24
|
import PaymentError from "./error.js";
|
|
24
25
|
import CheckoutFooter from "./footer.js";
|
|
@@ -166,6 +167,18 @@ function PaymentInner({
|
|
|
166
167
|
Toast.error(formatError(err));
|
|
167
168
|
}
|
|
168
169
|
};
|
|
170
|
+
const onQuantityChange = async (itemId, quantity) => {
|
|
171
|
+
try {
|
|
172
|
+
const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/adjust-quantity`, {
|
|
173
|
+
itemId,
|
|
174
|
+
quantity
|
|
175
|
+
});
|
|
176
|
+
setState({ checkoutSession: data });
|
|
177
|
+
} catch (err) {
|
|
178
|
+
console.error(err);
|
|
179
|
+
Toast.error(formatError(err));
|
|
180
|
+
}
|
|
181
|
+
};
|
|
169
182
|
const onCancelCrossSell = async () => {
|
|
170
183
|
try {
|
|
171
184
|
const { data } = await api.delete(`/api/checkout-sessions/${state.checkoutSession.id}/cross-sell`);
|
|
@@ -211,17 +224,19 @@ function PaymentInner({
|
|
|
211
224
|
// @ts-ignore
|
|
212
225
|
state.checkoutSession.subscription_data?.min_stake_amount || 0
|
|
213
226
|
),
|
|
214
|
-
showStaking: method
|
|
227
|
+
showStaking: showStaking(method, currency, !!state.checkoutSession.subscription_data?.no_stake),
|
|
215
228
|
currency,
|
|
216
229
|
onUpsell,
|
|
217
230
|
onDownsell,
|
|
231
|
+
onQuantityChange,
|
|
218
232
|
onApplyCrossSell,
|
|
219
233
|
onCancelCrossSell,
|
|
220
234
|
onChangeAmount,
|
|
221
235
|
checkoutSessionId: state.checkoutSession.id,
|
|
222
236
|
crossSellBehavior: state.checkoutSession.cross_sell_behavior,
|
|
223
237
|
donationSettings: paymentLink?.donation_settings,
|
|
224
|
-
action
|
|
238
|
+
action,
|
|
239
|
+
completed
|
|
225
240
|
}
|
|
226
241
|
),
|
|
227
242
|
mode === "standalone" && !isMobile && /* @__PURE__ */ jsx(CheckoutFooter, { className: "cko-footer", sx: { color: "text.lighter" } })
|
|
@@ -10,6 +10,13 @@ type Props = {
|
|
|
10
10
|
onDownsell: Function;
|
|
11
11
|
mode?: 'normal' | 'cross-sell';
|
|
12
12
|
children?: React.ReactNode;
|
|
13
|
+
adjustableQuantity?: {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
minimum?: number;
|
|
16
|
+
maximum?: number;
|
|
17
|
+
};
|
|
18
|
+
onQuantityChange?: (itemId: string, quantity: number) => void;
|
|
19
|
+
completed?: boolean;
|
|
13
20
|
};
|
|
14
|
-
export default function ProductItem({ item, items, trialInDays, trialEnd, currency, mode, children, onUpsell, onDownsell, }: Props): JSX.Element;
|
|
21
|
+
export default function ProductItem({ item, items, trialInDays, trialEnd, currency, mode, children, onUpsell, onDownsell, completed, adjustableQuantity, onQuantityChange, }: Props): JSX.Element;
|
|
15
22
|
export {};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
-
import { Box, Stack, Typography } from "@mui/material";
|
|
4
|
-
import {
|
|
3
|
+
import { Box, Stack, Typography, IconButton, TextField, Alert } from "@mui/material";
|
|
4
|
+
import { Add, Remove } from "@mui/icons-material";
|
|
5
|
+
import { useMemo, useState } from "react";
|
|
5
6
|
import Status from "../components/status.js";
|
|
6
7
|
import Switch from "../components/switch-button.js";
|
|
7
8
|
import {
|
|
9
|
+
findCurrency,
|
|
8
10
|
formatLineItemPricing,
|
|
9
11
|
formatPrice,
|
|
10
12
|
formatQuantityInventory,
|
|
@@ -13,6 +15,7 @@ import {
|
|
|
13
15
|
} from "../libs/util.js";
|
|
14
16
|
import ProductCard from "./product-card.js";
|
|
15
17
|
import dayjs from "../libs/dayjs.js";
|
|
18
|
+
import { usePaymentContext } from "../contexts/payment.js";
|
|
16
19
|
export default function ProductItem({
|
|
17
20
|
item,
|
|
18
21
|
items,
|
|
@@ -22,13 +25,77 @@ export default function ProductItem({
|
|
|
22
25
|
mode = "normal",
|
|
23
26
|
children = null,
|
|
24
27
|
onUpsell,
|
|
25
|
-
onDownsell
|
|
28
|
+
onDownsell,
|
|
29
|
+
completed = false,
|
|
30
|
+
adjustableQuantity = { enabled: false },
|
|
31
|
+
onQuantityChange = () => {
|
|
32
|
+
}
|
|
26
33
|
}) {
|
|
27
34
|
const { t, locale } = useLocaleContext();
|
|
35
|
+
const { settings } = usePaymentContext();
|
|
28
36
|
const pricing = formatLineItemPricing(item, currency, { trialEnd, trialInDays }, locale);
|
|
29
37
|
const saving = formatUpsellSaving(items, currency);
|
|
30
38
|
const metered = item.price?.recurring?.usage_type === "metered" ? t("common.metered") : "";
|
|
31
39
|
const canUpsell = mode === "normal" && items.length === 1;
|
|
40
|
+
const isCreditProduct = item.price.product?.type === "credit" && item.price.metadata?.credit_config?.credit_amount;
|
|
41
|
+
const creditAmount = isCreditProduct ? Number(item.price.metadata.credit_config.credit_amount) : 0;
|
|
42
|
+
const creditCurrency = isCreditProduct ? findCurrency(settings.paymentMethods, item.price.metadata?.credit_config?.currency_id ?? "") : null;
|
|
43
|
+
const validDuration = item.price.metadata?.credit_config?.valid_duration_value;
|
|
44
|
+
const validDurationUnit = item.price.metadata?.credit_config?.valid_duration_unit || "days";
|
|
45
|
+
const [localQuantity, setLocalQuantity] = useState(item.quantity);
|
|
46
|
+
const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
|
|
47
|
+
const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
|
|
48
|
+
const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
|
|
49
|
+
const maxQuantity = Math.min(adjustableQuantity.maximum || 999, quantityAvailable || 999);
|
|
50
|
+
const handleQuantityChange = (newQuantity) => {
|
|
51
|
+
if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
|
|
52
|
+
setLocalQuantity(newQuantity);
|
|
53
|
+
if (formatQuantityInventory(item.price, newQuantity, locale)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
onQuantityChange(item.price_id, newQuantity);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const handleQuantityIncrease = () => {
|
|
60
|
+
if (localQuantity < maxQuantity) {
|
|
61
|
+
handleQuantityChange(localQuantity + 1);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const handleQuantityDecrease = () => {
|
|
65
|
+
if (localQuantity > minQuantity) {
|
|
66
|
+
handleQuantityChange(localQuantity - 1);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const handleQuantityInputChange = (event) => {
|
|
70
|
+
const value = parseInt(event.target.value, 10);
|
|
71
|
+
if (!Number.isNaN(value)) {
|
|
72
|
+
handleQuantityChange(value);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const formatCreditInfo = () => {
|
|
76
|
+
if (!isCreditProduct) return null;
|
|
77
|
+
const isRecurring = item.price.type === "recurring";
|
|
78
|
+
const totalCredit = creditAmount * localQuantity;
|
|
79
|
+
let message = "";
|
|
80
|
+
if (isRecurring) {
|
|
81
|
+
message = t("payment.checkout.credit.recurringInfo", {
|
|
82
|
+
amount: totalCredit,
|
|
83
|
+
period: formatRecurring(item.price.recurring, true, "per", locale)
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
message = t("payment.checkout.credit.oneTimeInfo", {
|
|
87
|
+
amount: totalCredit,
|
|
88
|
+
symbol: creditCurrency?.symbol || "Credits"
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (validDuration && validDuration > 0) {
|
|
92
|
+
message += `\uFF0C${t("payment.checkout.credit.expiresIn", {
|
|
93
|
+
duration: validDuration,
|
|
94
|
+
unit: t(`common.${validDurationUnit}`)
|
|
95
|
+
})}`;
|
|
96
|
+
}
|
|
97
|
+
return message;
|
|
98
|
+
};
|
|
32
99
|
const primaryText = useMemo(() => {
|
|
33
100
|
const price = item.upsell_price || item.price || {};
|
|
34
101
|
const isRecurring = price?.type === "recurring" && price?.recurring;
|
|
@@ -38,6 +105,7 @@ export default function ProductItem({
|
|
|
38
105
|
}
|
|
39
106
|
return pricing.primary;
|
|
40
107
|
}, [trialInDays, trialEnd, pricing, item, locale]);
|
|
108
|
+
const quantityInventoryError = formatQuantityInventory(item.price, localQuantity, locale);
|
|
41
109
|
return /* @__PURE__ */ jsxs(
|
|
42
110
|
Stack,
|
|
43
111
|
{
|
|
@@ -105,10 +173,10 @@ export default function ProductItem({
|
|
|
105
173
|
]
|
|
106
174
|
}
|
|
107
175
|
),
|
|
108
|
-
|
|
176
|
+
quantityInventoryError ? /* @__PURE__ */ jsx(
|
|
109
177
|
Status,
|
|
110
178
|
{
|
|
111
|
-
label:
|
|
179
|
+
label: quantityInventoryError,
|
|
112
180
|
variant: "outlined",
|
|
113
181
|
sx: {
|
|
114
182
|
mt: 1,
|
|
@@ -118,6 +186,70 @@ export default function ProductItem({
|
|
|
118
186
|
}
|
|
119
187
|
}
|
|
120
188
|
) : null,
|
|
189
|
+
canAdjustQuantity && !completed && /* @__PURE__ */ jsx(Box, { sx: { mt: 1, p: 1 }, children: /* @__PURE__ */ jsxs(
|
|
190
|
+
Stack,
|
|
191
|
+
{
|
|
192
|
+
direction: "row",
|
|
193
|
+
spacing: 1,
|
|
194
|
+
sx: {
|
|
195
|
+
alignItems: "center"
|
|
196
|
+
},
|
|
197
|
+
children: [
|
|
198
|
+
/* @__PURE__ */ jsxs(
|
|
199
|
+
Typography,
|
|
200
|
+
{
|
|
201
|
+
variant: "body2",
|
|
202
|
+
sx: {
|
|
203
|
+
color: "text.secondary",
|
|
204
|
+
minWidth: "fit-content"
|
|
205
|
+
},
|
|
206
|
+
children: [
|
|
207
|
+
t("common.quantity"),
|
|
208
|
+
":"
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
/* @__PURE__ */ jsx(
|
|
213
|
+
IconButton,
|
|
214
|
+
{
|
|
215
|
+
size: "small",
|
|
216
|
+
onClick: handleQuantityDecrease,
|
|
217
|
+
disabled: localQuantity <= minQuantity,
|
|
218
|
+
sx: { minWidth: 32, width: 32, height: 32 },
|
|
219
|
+
children: /* @__PURE__ */ jsx(Remove, { fontSize: "small" })
|
|
220
|
+
}
|
|
221
|
+
),
|
|
222
|
+
/* @__PURE__ */ jsx(
|
|
223
|
+
TextField,
|
|
224
|
+
{
|
|
225
|
+
size: "small",
|
|
226
|
+
value: localQuantity,
|
|
227
|
+
onChange: handleQuantityInputChange,
|
|
228
|
+
sx: { width: 60 },
|
|
229
|
+
type: "number",
|
|
230
|
+
slotProps: {
|
|
231
|
+
htmlInput: {
|
|
232
|
+
min: minQuantity,
|
|
233
|
+
max: maxQuantity,
|
|
234
|
+
style: { textAlign: "center", padding: "4px" }
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
),
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
IconButton,
|
|
241
|
+
{
|
|
242
|
+
size: "small",
|
|
243
|
+
onClick: handleQuantityIncrease,
|
|
244
|
+
disabled: localQuantity >= maxQuantity,
|
|
245
|
+
sx: { minWidth: 32, width: 32, height: 32 },
|
|
246
|
+
children: /* @__PURE__ */ jsx(Add, { fontSize: "small" })
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
) }),
|
|
252
|
+
isCreditProduct && /* @__PURE__ */ jsx(Alert, { severity: "info", sx: { mt: 1, fontSize: "0.875rem" }, icon: false, children: formatCreditInfo() }),
|
|
121
253
|
children
|
|
122
254
|
]
|
|
123
255
|
}
|
package/es/payment/summary.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ type Props = {
|
|
|
8
8
|
showStaking?: boolean;
|
|
9
9
|
onUpsell?: Function;
|
|
10
10
|
onDownsell?: Function;
|
|
11
|
+
onQuantityChange?: Function;
|
|
11
12
|
onChangeAmount?: Function;
|
|
12
13
|
onApplyCrossSell?: Function;
|
|
13
14
|
onCancelCrossSell?: Function;
|
|
@@ -15,6 +16,7 @@ type Props = {
|
|
|
15
16
|
crossSellBehavior?: string;
|
|
16
17
|
donationSettings?: DonationSettings;
|
|
17
18
|
action?: string;
|
|
19
|
+
completed?: boolean;
|
|
18
20
|
};
|
|
19
|
-
export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, ...rest }: Props): import("react").JSX.Element;
|
|
21
|
+
export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onQuantityChange, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, completed, ...rest }: Props): import("react").JSX.Element;
|
|
20
22
|
export {};
|
package/es/payment/summary.js
CHANGED
|
@@ -73,6 +73,7 @@ export default function PaymentSummary({
|
|
|
73
73
|
billingThreshold,
|
|
74
74
|
onUpsell = noop,
|
|
75
75
|
onDownsell = noop,
|
|
76
|
+
onQuantityChange = noop,
|
|
76
77
|
onApplyCrossSell = noop,
|
|
77
78
|
onCancelCrossSell = noop,
|
|
78
79
|
onChangeAmount = noop,
|
|
@@ -82,6 +83,7 @@ export default function PaymentSummary({
|
|
|
82
83
|
donationSettings = void 0,
|
|
83
84
|
action = "",
|
|
84
85
|
trialEnd = 0,
|
|
86
|
+
completed = false,
|
|
85
87
|
...rest
|
|
86
88
|
}) {
|
|
87
89
|
const { t, locale } = useLocaleContext();
|
|
@@ -111,6 +113,10 @@ export default function PaymentSummary({
|
|
|
111
113
|
await onUpsell(from, to);
|
|
112
114
|
runAsync();
|
|
113
115
|
};
|
|
116
|
+
const handleQuantityChange = async (itemId, quantity) => {
|
|
117
|
+
await onQuantityChange(itemId, quantity);
|
|
118
|
+
runAsync();
|
|
119
|
+
};
|
|
114
120
|
const handleDownsell = async (from) => {
|
|
115
121
|
await onDownsell(from);
|
|
116
122
|
runAsync();
|
|
@@ -166,6 +172,9 @@ export default function PaymentSummary({
|
|
|
166
172
|
currency,
|
|
167
173
|
onUpsell: handleUpsell,
|
|
168
174
|
onDownsell: handleDownsell,
|
|
175
|
+
adjustableQuantity: x.adjustable_quantity,
|
|
176
|
+
completed,
|
|
177
|
+
onQuantityChange: handleQuantityChange,
|
|
169
178
|
children: x.cross_sell && /* @__PURE__ */ jsxs(
|
|
170
179
|
Stack,
|
|
171
180
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PaymentDetails, TPaymentMethod } from '@blocklet/payment-types';
|
|
2
|
-
export default function TxLink(
|
|
2
|
+
export default function TxLink({ details, method, mode, align, }: {
|
|
3
3
|
details: PaymentDetails;
|
|
4
4
|
method: TPaymentMethod;
|
|
5
5
|
mode?: 'customer' | 'dashboard';
|
|
@@ -10,15 +10,16 @@ var _iconsMaterial = require("@mui/icons-material");
|
|
|
10
10
|
var _material = require("@mui/material");
|
|
11
11
|
var _system = require("@mui/system");
|
|
12
12
|
var _util = require("../../libs/util");
|
|
13
|
-
function TxLink(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
function TxLink({
|
|
14
|
+
details,
|
|
15
|
+
method,
|
|
16
|
+
mode = "dashboard",
|
|
17
|
+
align = "left"
|
|
18
|
+
}) {
|
|
18
19
|
const {
|
|
19
20
|
t
|
|
20
21
|
} = (0, _context.useLocaleContext)();
|
|
21
|
-
if (!
|
|
22
|
+
if (!details || mode === "customer" && method.type === "stripe") {
|
|
22
23
|
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
23
24
|
component: "small",
|
|
24
25
|
sx: {
|
|
@@ -30,7 +31,7 @@ function TxLink(rawProps) {
|
|
|
30
31
|
const {
|
|
31
32
|
text,
|
|
32
33
|
link
|
|
33
|
-
} = (0, _util.getTxLink)(
|
|
34
|
+
} = (0, _util.getTxLink)(method, details);
|
|
34
35
|
if (link && text) {
|
|
35
36
|
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
|
|
36
37
|
href: link,
|
|
@@ -39,7 +40,7 @@ function TxLink(rawProps) {
|
|
|
39
40
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(Root, {
|
|
40
41
|
direction: "row",
|
|
41
42
|
alignItems: "center",
|
|
42
|
-
justifyContent:
|
|
43
|
+
justifyContent: align === "left" ? "flex-start" : "flex-end",
|
|
43
44
|
sx: {
|
|
44
45
|
color: "text.link"
|
|
45
46
|
},
|
|
@@ -8,5 +8,5 @@ export type CountrySelectProps = {
|
|
|
8
8
|
showDialCode?: boolean;
|
|
9
9
|
};
|
|
10
10
|
export default function CountrySelect({ ref, value, onChange, name, sx, showDialCode, }: CountrySelectProps & {
|
|
11
|
-
ref?: React.RefObject<HTMLDivElement>;
|
|
11
|
+
ref?: React.RefObject<HTMLDivElement | null>;
|
|
12
12
|
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface DateRangeValue {
|
|
2
|
+
start: number | undefined;
|
|
3
|
+
end: number | undefined;
|
|
4
|
+
}
|
|
5
|
+
export interface DateRangePickerProps {
|
|
6
|
+
value: DateRangeValue;
|
|
7
|
+
onChange: (value: DateRangeValue) => void;
|
|
8
|
+
label?: string;
|
|
9
|
+
size?: 'small' | 'medium';
|
|
10
|
+
fullWidth?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export default function DateRangePicker({ value, onChange, label, size, fullWidth, disabled, }: DateRangePickerProps): import("react").JSX.Element;
|