@blocklet/payment-react 1.13.296 → 1.13.298

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.
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import type { TProductExpanded } from '@blocklet/payment-types';
3
+ import { PricingRenderProps } from '../types';
4
+ export type PricingItemProps = {
5
+ productId: string;
6
+ quantity: number;
7
+ priceId: string | undefined;
8
+ children?: (pricing: PricingRenderProps, product?: TProductExpanded | undefined) => React.ReactNode;
9
+ };
10
+ declare function PricingItem({ productId, quantity, children, priceId }: PricingItemProps): import("react").JSX.Element;
11
+ declare namespace PricingItem {
12
+ var defaultProps: {
13
+ children: null;
14
+ };
15
+ }
16
+ export default PricingItem;
@@ -0,0 +1,43 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useRequest } from "ahooks";
3
+ import { CircularProgress, Typography } from "@mui/material";
4
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
5
+ import { useMemo } from "react";
6
+ import Toast from "@arcblock/ux/lib/Toast";
7
+ import { Box } from "@mui/system";
8
+ import api from "../libs/api.js";
9
+ import { formatError, formatTotalPrice } from "../libs/util.js";
10
+ const fetchProduct = (productId) => {
11
+ return api.get(`/api/products/${productId}`).then((res) => res.data);
12
+ };
13
+ function PricingItem({ productId, quantity, children, priceId }) {
14
+ const { locale } = useLocaleContext();
15
+ const { data: productInfo, loading = false } = useRequest(() => fetchProduct(productId), {
16
+ refreshDeps: [productId],
17
+ onSuccess: (res) => {
18
+ if (!res) {
19
+ Toast.error(formatError(new Error("Product not found")));
20
+ }
21
+ },
22
+ onError: (err) => {
23
+ Toast.error(formatError(err));
24
+ }
25
+ });
26
+ const pricing = useMemo(
27
+ () => formatTotalPrice({
28
+ product: productInfo,
29
+ quantity,
30
+ priceId,
31
+ locale
32
+ }),
33
+ [productInfo, quantity, priceId, locale]
34
+ );
35
+ if (loading) {
36
+ return /* @__PURE__ */ jsx(CircularProgress, {});
37
+ }
38
+ return /* @__PURE__ */ jsx(Box, { children: children ? children(pricing, productInfo) : /* @__PURE__ */ jsx(Typography, { children: pricing?.totalPrice }) });
39
+ }
40
+ PricingItem.defaultProps = {
41
+ children: null
42
+ };
43
+ export default PricingItem;
package/es/index.d.ts CHANGED
@@ -22,9 +22,10 @@ import StripeForm from './payment/form/stripe';
22
22
  import Payment from './payment/index';
23
23
  import ProductSkeleton from './payment/product-skeleton';
24
24
  import PaymentSummary from './payment/summary';
25
+ import PricingItem from './components/pricing-item';
25
26
  export * from './libs/util';
26
27
  export * from './libs/connect';
27
28
  export * from './contexts/payment';
28
29
  export * from './hooks/subscription';
29
30
  export { translations, createTranslator } from './locales';
30
- export { api, dayjs, FormInput, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, };
31
+ export { api, dayjs, FormInput, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, };
package/es/index.js CHANGED
@@ -22,6 +22,7 @@ import StripeForm from "./payment/form/stripe.js";
22
22
  import Payment from "./payment/index.js";
23
23
  import ProductSkeleton from "./payment/product-skeleton.js";
24
24
  import PaymentSummary from "./payment/summary.js";
25
+ import PricingItem from "./components/pricing-item.js";
25
26
  export * from "./libs/util.js";
26
27
  export * from "./libs/connect.js";
27
28
  export * from "./contexts/payment.js";
@@ -51,5 +52,6 @@ export {
51
52
  CustomerPaymentList,
52
53
  TxLink,
53
54
  TxGas,
54
- SafeGuard
55
+ SafeGuard,
56
+ PricingItem
55
57
  };
package/es/libs/util.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
- import type { PaymentDetails, PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentCurrencyExpanded, TPaymentMethod, TPaymentMethodExpanded, TPrice, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
2
+ import type { PaymentDetails, PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentCurrencyExpanded, TPaymentMethod, TPaymentMethodExpanded, TPrice, TProductExpanded, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
3
+ import { PricingRenderProps } from '../types';
3
4
  export declare const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
4
5
  export declare const isPaymentKitMounted: () => any;
5
6
  export declare const getPrefix: () => string;
@@ -69,3 +70,9 @@ export declare const getTxLink: (method: TPaymentMethod, details: PaymentDetails
69
70
  };
70
71
  export declare function getQueryParams(url: string): Record<string, string>;
71
72
  export declare function lazyLoad(lazyRun: () => void): void;
73
+ export declare function formatTotalPrice({ product, quantity, priceId, locale, }: {
74
+ product: TProductExpanded;
75
+ quantity: number;
76
+ priceId?: string;
77
+ locale: string;
78
+ }): PricingRenderProps;
package/es/libs/util.js CHANGED
@@ -636,3 +636,39 @@ export function lazyLoad(lazyRun) {
636
636
  lazyRun();
637
637
  }, 0);
638
638
  }
639
+ export function formatTotalPrice({
640
+ product,
641
+ quantity = 1,
642
+ priceId,
643
+ locale = "en"
644
+ }) {
645
+ const { prices = [], default_price_id: defaultPriceId } = product ?? { prices: [], default_price_id: "" };
646
+ const price = prices?.find((x) => x.id === (priceId || defaultPriceId));
647
+ if (!price || !product) {
648
+ return {
649
+ totalPrice: "0",
650
+ unitPrice: "",
651
+ quantity: t("common.qty", locale, { count: quantity }),
652
+ totalAmount: "0"
653
+ };
654
+ }
655
+ const unitValue = new BN(price.custom_unit_amount || price.unit_amount);
656
+ const currency = price?.currency ?? {};
657
+ const total = `${fromUnitToToken(unitValue.mul(new BN(quantity)), currency.decimal)} ${currency.symbol}`;
658
+ const unit = `${fromUnitToToken(unitValue, currency.decimal)} ${currency.symbol}`;
659
+ const appendUnit = (v, alt) => {
660
+ if (product.unit_label) {
661
+ return `${v}/${price.product.unit_label}`;
662
+ }
663
+ if (price.recurring?.usage_type === "metered" || quantity === 1) {
664
+ return alt;
665
+ }
666
+ return quantity ? t("common.each", locale, { unit }) : "";
667
+ };
668
+ return {
669
+ totalPrice: total,
670
+ unitPrice: appendUnit(total, ""),
671
+ quantity: t("common.qty", locale, { count: quantity }),
672
+ totalAmount: unitValue.mul(new BN(quantity)).toString()
673
+ };
674
+ }
package/es/locales/en.js CHANGED
@@ -113,7 +113,7 @@ export default flat({
113
113
  between: "Please enter an amount between {min} and {max}.",
114
114
  custom: "Custom Amount",
115
115
  select: "Select Amount",
116
- summary: "{total} supporters {totalAmount}{symbol}",
116
+ summary: "{total} supporters {totalAmount} {symbol}",
117
117
  empty: "No supporters yet"
118
118
  },
119
119
  cardPay: "{action} with card",
package/es/locales/zh.js CHANGED
@@ -113,7 +113,7 @@ export default flat({
113
113
  between: "\u91D1\u989D\u5FC5\u987B\u5927\u4E8E {min} \u4E14\u5C0F\u4E8E {max}",
114
114
  custom: "\u8F93\u5165\u91D1\u989D",
115
115
  select: "\u9009\u62E9\u91D1\u989D",
116
- summary: "\u5171\u6709 {total} \u4EBA\u652F\u6301 {totalAmount}{symbol}",
116
+ summary: "\u5171\u6709 {total} \u4EBA\u652F\u6301 {totalAmount} {symbol}",
117
117
  empty: "\u2764\uFE0F \u652F\u6301\u4E00\u4E0B"
118
118
  },
119
119
  cardPay: "\u4F7F\u7528\u5361\u7247{action}",
@@ -36,3 +36,9 @@ export type CheckoutCallbacks = {
36
36
  onChange?: (data: CheckoutFormData) => void;
37
37
  goBack?: () => void;
38
38
  };
39
+ export type PricingRenderProps = {
40
+ totalPrice: string;
41
+ unitPrice?: string;
42
+ quantity: string;
43
+ totalAmount: string;
44
+ };
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import type { TProductExpanded } from '@blocklet/payment-types';
3
+ import { PricingRenderProps } from '../types';
4
+ export type PricingItemProps = {
5
+ productId: string;
6
+ quantity: number;
7
+ priceId: string | undefined;
8
+ children?: (pricing: PricingRenderProps, product?: TProductExpanded | undefined) => React.ReactNode;
9
+ };
10
+ declare function PricingItem({ productId, quantity, children, priceId }: PricingItemProps): import("react").JSX.Element;
11
+ declare namespace PricingItem {
12
+ var defaultProps: {
13
+ children: null;
14
+ };
15
+ }
16
+ export default PricingItem;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+
7
+ var _jsxRuntime = require("react/jsx-runtime");
8
+ var _ahooks = require("ahooks");
9
+ var _material = require("@mui/material");
10
+ var _context = require("@arcblock/ux/lib/Locale/context");
11
+ var _react = require("react");
12
+ var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
13
+ var _system = require("@mui/system");
14
+ var _api = _interopRequireDefault(require("../libs/api"));
15
+ var _util = require("../libs/util");
16
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
+ const fetchProduct = productId => {
18
+ return _api.default.get(`/api/products/${productId}`).then(res => res.data);
19
+ };
20
+ function PricingItem({
21
+ productId,
22
+ quantity,
23
+ children,
24
+ priceId
25
+ }) {
26
+ const {
27
+ locale
28
+ } = (0, _context.useLocaleContext)();
29
+ const {
30
+ data: productInfo,
31
+ loading = false
32
+ } = (0, _ahooks.useRequest)(() => fetchProduct(productId), {
33
+ refreshDeps: [productId],
34
+ onSuccess: res => {
35
+ if (!res) {
36
+ _Toast.default.error((0, _util.formatError)(new Error("Product not found")));
37
+ }
38
+ },
39
+ onError: err => {
40
+ _Toast.default.error((0, _util.formatError)(err));
41
+ }
42
+ });
43
+ const pricing = (0, _react.useMemo)(() => (0, _util.formatTotalPrice)({
44
+ product: productInfo,
45
+ quantity,
46
+ priceId,
47
+ locale
48
+ }), [productInfo, quantity, priceId, locale]);
49
+ if (loading) {
50
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.CircularProgress, {});
51
+ }
52
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_system.Box, {
53
+ children: children ? children(pricing, productInfo) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
54
+ children: pricing?.totalPrice
55
+ })
56
+ });
57
+ }
58
+ PricingItem.defaultProps = {
59
+ children: null
60
+ };
61
+ module.exports = PricingItem;
package/lib/index.d.ts CHANGED
@@ -22,9 +22,10 @@ import StripeForm from './payment/form/stripe';
22
22
  import Payment from './payment/index';
23
23
  import ProductSkeleton from './payment/product-skeleton';
24
24
  import PaymentSummary from './payment/summary';
25
+ import PricingItem from './components/pricing-item';
25
26
  export * from './libs/util';
26
27
  export * from './libs/connect';
27
28
  export * from './contexts/payment';
28
29
  export * from './hooks/subscription';
29
30
  export { translations, createTranslator } from './locales';
30
- export { api, dayjs, FormInput, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, };
31
+ export { api, dayjs, FormInput, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, };
package/lib/index.js CHANGED
@@ -28,6 +28,7 @@ var _exportNames = {
28
28
  Payment: true,
29
29
  ProductSkeleton: true,
30
30
  PaymentSummary: true,
31
+ PricingItem: true,
31
32
  translations: true,
32
33
  createTranslator: true
33
34
  };
@@ -115,6 +116,12 @@ Object.defineProperty(exports, "PhoneInput", {
115
116
  return _phone.default;
116
117
  }
117
118
  });
119
+ Object.defineProperty(exports, "PricingItem", {
120
+ enumerable: true,
121
+ get: function () {
122
+ return _pricingItem.default;
123
+ }
124
+ });
118
125
  Object.defineProperty(exports, "PricingTable", {
119
126
  enumerable: true,
120
127
  get: function () {
@@ -211,6 +218,7 @@ var _stripe = _interopRequireDefault(require("./payment/form/stripe"));
211
218
  var _index = _interopRequireDefault(require("./payment/index"));
212
219
  var _productSkeleton = _interopRequireDefault(require("./payment/product-skeleton"));
213
220
  var _summary = _interopRequireDefault(require("./payment/summary"));
221
+ var _pricingItem = _interopRequireDefault(require("./components/pricing-item"));
214
222
  var _util = require("./libs/util");
215
223
  Object.keys(_util).forEach(function (key) {
216
224
  if (key === "default" || key === "__esModule") return;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
- import type { PaymentDetails, PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentCurrencyExpanded, TPaymentMethod, TPaymentMethodExpanded, TPrice, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
2
+ import type { PaymentDetails, PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentCurrencyExpanded, TPaymentMethod, TPaymentMethodExpanded, TPrice, TProductExpanded, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
3
+ import { PricingRenderProps } from '../types';
3
4
  export declare const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
4
5
  export declare const isPaymentKitMounted: () => any;
5
6
  export declare const getPrefix: () => string;
@@ -69,3 +70,9 @@ export declare const getTxLink: (method: TPaymentMethod, details: PaymentDetails
69
70
  };
70
71
  export declare function getQueryParams(url: string): Record<string, string>;
71
72
  export declare function lazyLoad(lazyRun: () => void): void;
73
+ export declare function formatTotalPrice({ product, quantity, priceId, locale, }: {
74
+ product: TProductExpanded;
75
+ quantity: number;
76
+ priceId?: string;
77
+ locale: string;
78
+ }): PricingRenderProps;
package/lib/libs/util.js CHANGED
@@ -20,6 +20,7 @@ exports.formatSubscriptionProduct = formatSubscriptionProduct;
20
20
  exports.formatTime = formatTime;
21
21
  exports.formatToDate = formatToDate;
22
22
  exports.formatToDatetime = formatToDatetime;
23
+ exports.formatTotalPrice = formatTotalPrice;
23
24
  exports.formatUpsellSaving = formatUpsellSaving;
24
25
  exports.getCheckoutAmount = getCheckoutAmount;
25
26
  exports.getInvoiceStatusColor = getInvoiceStatusColor;
@@ -756,4 +757,52 @@ function lazyLoad(lazyRun) {
756
757
  setTimeout(() => {
757
758
  lazyRun();
758
759
  }, 0);
760
+ }
761
+ function formatTotalPrice({
762
+ product,
763
+ quantity = 1,
764
+ priceId,
765
+ locale = "en"
766
+ }) {
767
+ const {
768
+ prices = [],
769
+ default_price_id: defaultPriceId
770
+ } = product ?? {
771
+ prices: [],
772
+ default_price_id: ""
773
+ };
774
+ const price = prices?.find(x => x.id === (priceId || defaultPriceId));
775
+ if (!price || !product) {
776
+ return {
777
+ totalPrice: "0",
778
+ unitPrice: "",
779
+ quantity: (0, _locales.t)("common.qty", locale, {
780
+ count: quantity
781
+ }),
782
+ totalAmount: "0"
783
+ };
784
+ }
785
+ const unitValue = new _util.BN(price.custom_unit_amount || price.unit_amount);
786
+ const currency = price?.currency ?? {};
787
+ const total = `${(0, _util.fromUnitToToken)(unitValue.mul(new _util.BN(quantity)), currency.decimal)} ${currency.symbol}`;
788
+ const unit = `${(0, _util.fromUnitToToken)(unitValue, currency.decimal)} ${currency.symbol}`;
789
+ const appendUnit = (v, alt) => {
790
+ if (product.unit_label) {
791
+ return `${v}/${price.product.unit_label}`;
792
+ }
793
+ if (price.recurring?.usage_type === "metered" || quantity === 1) {
794
+ return alt;
795
+ }
796
+ return quantity ? (0, _locales.t)("common.each", locale, {
797
+ unit
798
+ }) : "";
799
+ };
800
+ return {
801
+ totalPrice: total,
802
+ unitPrice: appendUnit(total, ""),
803
+ quantity: (0, _locales.t)("common.qty", locale, {
804
+ count: quantity
805
+ }),
806
+ totalAmount: unitValue.mul(new _util.BN(quantity)).toString()
807
+ };
759
808
  }
package/lib/locales/en.js CHANGED
@@ -120,7 +120,7 @@ module.exports = (0, _flat.default)({
120
120
  between: "Please enter an amount between {min} and {max}.",
121
121
  custom: "Custom Amount",
122
122
  select: "Select Amount",
123
- summary: "{total} supporters {totalAmount}{symbol}",
123
+ summary: "{total} supporters {totalAmount} {symbol}",
124
124
  empty: "No supporters yet"
125
125
  },
126
126
  cardPay: "{action} with card",
package/lib/locales/zh.js CHANGED
@@ -120,7 +120,7 @@ module.exports = (0, _flat.default)({
120
120
  between: "\u91D1\u989D\u5FC5\u987B\u5927\u4E8E {min} \u4E14\u5C0F\u4E8E {max}",
121
121
  custom: "\u8F93\u5165\u91D1\u989D",
122
122
  select: "\u9009\u62E9\u91D1\u989D",
123
- summary: "\u5171\u6709 {total} \u4EBA\u652F\u6301 {totalAmount}{symbol}",
123
+ summary: "\u5171\u6709 {total} \u4EBA\u652F\u6301 {totalAmount} {symbol}",
124
124
  empty: "\u2764\uFE0F \u652F\u6301\u4E00\u4E0B"
125
125
  },
126
126
  cardPay: "\u4F7F\u7528\u5361\u7247{action}",
@@ -36,3 +36,9 @@ export type CheckoutCallbacks = {
36
36
  onChange?: (data: CheckoutFormData) => void;
37
37
  goBack?: () => void;
38
38
  };
39
+ export type PricingRenderProps = {
40
+ totalPrice: string;
41
+ unitPrice?: string;
42
+ quantity: string;
43
+ totalAmount: string;
44
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.13.296",
3
+ "version": "1.13.298",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -91,7 +91,7 @@
91
91
  "@babel/core": "^7.24.7",
92
92
  "@babel/preset-env": "^7.24.7",
93
93
  "@babel/preset-react": "^7.24.7",
94
- "@blocklet/payment-types": "1.13.296",
94
+ "@blocklet/payment-types": "1.13.298",
95
95
  "@storybook/addon-essentials": "^7.6.19",
96
96
  "@storybook/addon-interactions": "^7.6.19",
97
97
  "@storybook/addon-links": "^7.6.19",
@@ -120,5 +120,5 @@
120
120
  "vite-plugin-babel": "^1.2.0",
121
121
  "vite-plugin-node-polyfills": "^0.21.0"
122
122
  },
123
- "gitHead": "e0f0556ce4ed8833464248e00250c09dbde2c5a9"
123
+ "gitHead": "85dd6105a19723e06405eebb4bcc6ffddc2cd7aa"
124
124
  }
@@ -0,0 +1,57 @@
1
+ import { useRequest } from 'ahooks';
2
+ import { CircularProgress, Typography } from '@mui/material';
3
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
+ import type { TProductExpanded } from '@blocklet/payment-types';
5
+ import { useMemo } from 'react';
6
+ import Toast from '@arcblock/ux/lib/Toast';
7
+ import { Box } from '@mui/system';
8
+ import api from '../libs/api';
9
+ import { formatError, formatTotalPrice } from '../libs/util';
10
+ import { PricingRenderProps } from '../types';
11
+
12
+ const fetchProduct = (productId: string): Promise<TProductExpanded> => {
13
+ return api.get(`/api/products/${productId}`).then((res) => res.data);
14
+ };
15
+
16
+ export type PricingItemProps = {
17
+ productId: string;
18
+ quantity: number;
19
+ priceId: string | undefined;
20
+ children?: (pricing: PricingRenderProps, product?: TProductExpanded | undefined) => React.ReactNode;
21
+ };
22
+
23
+ function PricingItem({ productId, quantity, children, priceId }: PricingItemProps) {
24
+ const { locale } = useLocaleContext();
25
+
26
+ const { data: productInfo, loading = false } = useRequest(() => fetchProduct(productId), {
27
+ refreshDeps: [productId],
28
+ onSuccess: (res) => {
29
+ if (!res) {
30
+ Toast.error(formatError(new Error('Product not found')));
31
+ }
32
+ },
33
+ onError: (err: any) => {
34
+ Toast.error(formatError(err));
35
+ },
36
+ });
37
+
38
+ const pricing: PricingRenderProps = useMemo(
39
+ () =>
40
+ formatTotalPrice({
41
+ product: productInfo!,
42
+ quantity,
43
+ priceId,
44
+ locale,
45
+ }),
46
+ [productInfo, quantity, priceId, locale]
47
+ );
48
+ if (loading) {
49
+ return <CircularProgress />;
50
+ }
51
+ return <Box>{children ? children(pricing, productInfo) : <Typography>{pricing?.totalPrice}</Typography>}</Box>;
52
+ }
53
+
54
+ PricingItem.defaultProps = {
55
+ children: null,
56
+ };
57
+ export default PricingItem;
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import StripeForm from './payment/form/stripe';
22
22
  import Payment from './payment/index';
23
23
  import ProductSkeleton from './payment/product-skeleton';
24
24
  import PaymentSummary from './payment/summary';
25
+ import PricingItem from './components/pricing-item';
25
26
 
26
27
  export * from './libs/util';
27
28
  export * from './libs/connect';
@@ -55,4 +56,5 @@ export {
55
56
  TxLink,
56
57
  TxGas,
57
58
  SafeGuard,
59
+ PricingItem,
58
60
  };
package/src/libs/util.ts CHANGED
@@ -10,6 +10,7 @@ import type {
10
10
  TPaymentMethod,
11
11
  TPaymentMethodExpanded,
12
12
  TPrice,
13
+ TProductExpanded,
13
14
  TSubscriptionExpanded,
14
15
  TSubscriptionItemExpanded,
15
16
  } from '@blocklet/payment-types';
@@ -23,6 +24,7 @@ import { joinURL } from 'ufo';
23
24
 
24
25
  import { t } from '../locales';
25
26
  import dayjs from './dayjs';
27
+ import { PricingRenderProps } from '../types';
26
28
 
27
29
  export const PAYMENT_KIT_DID = 'z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk';
28
30
 
@@ -824,3 +826,49 @@ export function lazyLoad(lazyRun: () => void) {
824
826
  lazyRun();
825
827
  }, 0);
826
828
  }
829
+
830
+ export function formatTotalPrice({
831
+ product,
832
+ quantity = 1,
833
+ priceId,
834
+ locale = 'en',
835
+ }: {
836
+ product: TProductExpanded;
837
+ quantity: number;
838
+ priceId?: string;
839
+ locale: string;
840
+ }): PricingRenderProps {
841
+ const { prices = [], default_price_id: defaultPriceId } = product ?? { prices: [], default_price_id: '' };
842
+ const price = prices?.find((x) => x.id === (priceId || defaultPriceId));
843
+ if (!price || !product) {
844
+ return {
845
+ totalPrice: '0',
846
+ unitPrice: '',
847
+ quantity: t('common.qty', locale, { count: quantity }),
848
+ totalAmount: '0',
849
+ };
850
+ }
851
+ const unitValue = new BN(price.custom_unit_amount || price.unit_amount);
852
+ const currency: TPaymentCurrency = price?.currency ?? {};
853
+
854
+ const total = `${fromUnitToToken(unitValue.mul(new BN(quantity)), currency.decimal)} ${currency.symbol}`;
855
+
856
+ const unit = `${fromUnitToToken(unitValue, currency.decimal)} ${currency.symbol}`;
857
+
858
+ const appendUnit = (v: string, alt: string) => {
859
+ if (product.unit_label) {
860
+ return `${v}/${price.product.unit_label}`;
861
+ }
862
+ if (price.recurring?.usage_type === 'metered' || quantity === 1) {
863
+ return alt;
864
+ }
865
+ return quantity ? t('common.each', locale, { unit }) : '';
866
+ };
867
+
868
+ return {
869
+ totalPrice: total,
870
+ unitPrice: appendUnit(total, ''),
871
+ quantity: t('common.qty', locale, { count: quantity }),
872
+ totalAmount: unitValue.mul(new BN(quantity)).toString(),
873
+ };
874
+ }
@@ -116,7 +116,7 @@ export default flat({
116
116
  between: 'Please enter an amount between {min} and {max}.',
117
117
  custom: 'Custom Amount',
118
118
  select: 'Select Amount',
119
- summary: '{total} supporters {totalAmount}{symbol}',
119
+ summary: '{total} supporters {totalAmount} {symbol}',
120
120
  empty: 'No supporters yet',
121
121
  },
122
122
  cardPay: '{action} with card',
@@ -115,7 +115,7 @@ export default flat({
115
115
  between: '金额必须大于 {min} 且小于 {max}',
116
116
  custom: '输入金额',
117
117
  select: '选择金额',
118
- summary: '共有 {total} 人支持 {totalAmount}{symbol}',
118
+ summary: '共有 {total} 人支持 {totalAmount} {symbol}',
119
119
  empty: '❤️ 支持一下',
120
120
  },
121
121
  cardPay: '使用卡片{action}',
@@ -47,3 +47,10 @@ export type CheckoutCallbacks = {
47
47
  onChange?: (data: CheckoutFormData) => void;
48
48
  goBack?: () => void;
49
49
  };
50
+
51
+ export type PricingRenderProps = {
52
+ totalPrice: string;
53
+ unitPrice?: string;
54
+ quantity: string;
55
+ totalAmount: string;
56
+ };