@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.
Files changed (41) hide show
  1. package/es/components/promotion-code.d.ts +19 -0
  2. package/es/components/promotion-code.js +153 -0
  3. package/es/contexts/payment.d.ts +8 -0
  4. package/es/contexts/payment.js +10 -1
  5. package/es/index.d.ts +2 -1
  6. package/es/index.js +3 -1
  7. package/es/libs/util.d.ts +5 -1
  8. package/es/libs/util.js +23 -0
  9. package/es/locales/en.js +40 -15
  10. package/es/locales/zh.js +29 -0
  11. package/es/payment/form/index.js +7 -1
  12. package/es/payment/index.js +19 -0
  13. package/es/payment/product-item.js +32 -3
  14. package/es/payment/summary.d.ts +5 -2
  15. package/es/payment/summary.js +193 -16
  16. package/lib/components/promotion-code.d.ts +19 -0
  17. package/lib/components/promotion-code.js +155 -0
  18. package/lib/contexts/payment.d.ts +8 -0
  19. package/lib/contexts/payment.js +13 -1
  20. package/lib/index.d.ts +2 -1
  21. package/lib/index.js +8 -0
  22. package/lib/libs/util.d.ts +5 -1
  23. package/lib/libs/util.js +29 -0
  24. package/lib/locales/en.js +40 -15
  25. package/lib/locales/zh.js +29 -0
  26. package/lib/payment/form/index.js +8 -1
  27. package/lib/payment/index.js +23 -0
  28. package/lib/payment/product-item.js +46 -0
  29. package/lib/payment/summary.d.ts +5 -2
  30. package/lib/payment/summary.js +153 -11
  31. package/package.json +9 -9
  32. package/src/components/promotion-code.tsx +184 -0
  33. package/src/contexts/payment.tsx +15 -0
  34. package/src/index.ts +2 -0
  35. package/src/libs/util.ts +35 -0
  36. package/src/locales/en.tsx +40 -15
  37. package/src/locales/zh.tsx +29 -0
  38. package/src/payment/form/index.tsx +10 -1
  39. package/src/payment/index.tsx +22 -0
  40. package/src/payment/product-item.tsx +37 -2
  41. package/src/payment/summary.tsx +201 -16
package/lib/locales/en.js CHANGED
@@ -109,8 +109,8 @@ module.exports = (0, _flat.default)({
109
109
  know: "I know",
110
110
  relatedSubscription: "Subscription",
111
111
  connect: {
112
- defaultScan: "Use following methods to complete this action",
113
- scan: "Use following methods to complete this {action}",
112
+ defaultScan: "Use the following methods to complete this action",
113
+ scan: "Use the following methods to complete this {action}",
114
114
  confirm: "Confirm",
115
115
  cancel: "Cancel"
116
116
  },
@@ -160,14 +160,14 @@ module.exports = (0, _flat.default)({
160
160
  },
161
161
  inactive: "Donation feature is not enabled",
162
162
  enable: "Enable Donation",
163
- enableSuccess: "Enable Success",
164
- configPrompt: "Donation feature is enabled, you can configure donation options in Payment Kit",
163
+ enableSuccess: "Successfully enabled",
164
+ configPrompt: "The donation feature is enabled. You can configure donation options in Payment Kit",
165
165
  configNow: "Configure Now",
166
166
  later: "Configure Later",
167
167
  configTip: "Configure donation settings in Payment Kit"
168
168
  },
169
169
  cardPay: "{action} with bank card",
170
- empty: "No thing to pay",
170
+ empty: "Nothing to pay",
171
171
  per: "per",
172
172
  pay: "Pay {payee}",
173
173
  try1: "Try {name}",
@@ -181,8 +181,8 @@ module.exports = (0, _flat.default)({
181
181
  least: "continue with at least",
182
182
  completed: {
183
183
  payment: "Thanks for your purchase",
184
- subscription: "Thanks for your subscribing",
185
- setup: "Thanks for your subscribing",
184
+ subscription: "Thanks for subscribing",
185
+ setup: "Thanks for subscribing",
186
186
  donate: "Thanks for your tip",
187
187
  tip: "A payment to {payee} has been completed. You can view the details of this payment in your account."
188
188
  },
@@ -191,7 +191,7 @@ module.exports = (0, _flat.default)({
191
191
  progress: "Progress {progress}%",
192
192
  delivered: "Installation completed",
193
193
  failed: "Processing failed",
194
- failedMsg: "An exception occurred during installation. We will automatically process a refund for you. We apologize for the inconvenience caused. Thank you for your understanding!"
194
+ failedMsg: "An exception occurred during installation. We will automatically process a refund for you. We apologize for the inconvenience. Thank you for your understanding!"
195
195
  },
196
196
  confirm: {
197
197
  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.",
@@ -240,14 +240,39 @@ module.exports = (0, _flat.default)({
240
240
  },
241
241
  emptyItems: {
242
242
  title: "Nothing to show here",
243
- description: "Seems this checkoutSession is not configured properly"
243
+ description: "It seems this checkout session is not configured properly"
244
244
  },
245
245
  orderSummary: "Order Summary",
246
246
  paymentDetails: "Payment Details",
247
247
  productListTotal: "Includes {total} items",
248
+ promotion: {
249
+ add_code: "Add promotion code",
250
+ enter_code: "Enter promotion code",
251
+ placeholder: "Enter code",
252
+ apply: "Apply",
253
+ applied: "Applied promotion codes",
254
+ dialog: {
255
+ title: "Add promotion code"
256
+ },
257
+ error: {
258
+ unknown: "Unknown error",
259
+ network: "Network error occurred",
260
+ removal: "Failed to remove code"
261
+ }
262
+ },
263
+ coupon: {
264
+ noDiscount: "No discount",
265
+ percentage: "{percent}% off",
266
+ fixedAmount: "{amount} {symbol} off",
267
+ terms: {
268
+ forever: "{couponOff} forever",
269
+ once: "{couponOff} once",
270
+ repeating: "{couponOff} for {months} month{months > 1 ? 's' : ''}"
271
+ }
272
+ },
248
273
  connectModal: {
249
274
  title: "{action}",
250
- scan: "Use following methods to complete this payment",
275
+ scan: "Use the following methods to complete this payment",
251
276
  confirm: "Confirm",
252
277
  cancel: "Cancel"
253
278
  },
@@ -330,7 +355,7 @@ module.exports = (0, _flat.default)({
330
355
  summary: "Summary",
331
356
  products: "Products",
332
357
  update: "Update Information",
333
- empty: "Seems you do not have any subscriptions or payments here",
358
+ empty: "It seems you do not have any subscriptions or payments here",
334
359
  cancel: {
335
360
  button: "Unsubscribe",
336
361
  title: "Cancel your subscription",
@@ -341,7 +366,7 @@ module.exports = (0, _flat.default)({
341
366
  tip: "We would love your feedback, it will help us improve our service",
342
367
  too_expensive: "The service is too expensive",
343
368
  missing_features: "Features are missing for this service",
344
- switched_service: "I have switched to alternative service",
369
+ switched_service: "I have switched to an alternative service",
345
370
  unused: "I no longer use this service",
346
371
  customer_service: "The customer service is poor",
347
372
  too_complex: "The service is too complex to use",
@@ -352,7 +377,7 @@ module.exports = (0, _flat.default)({
352
377
  pastDue: {
353
378
  button: "Pay",
354
379
  invoices: "Past Due Invoices",
355
- warning: "Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.",
380
+ warning: "Past due invoices need to be paid immediately, otherwise you cannot make new purchases anymore.",
356
381
  alert: {
357
382
  title: "You have unpaid invoices",
358
383
  customMessage: "Please pay immediately, otherwise new purchases or subscriptions will be prohibited.",
@@ -405,7 +430,7 @@ module.exports = (0, _flat.default)({
405
430
  amountApplied: "Applied Credit",
406
431
  pay: "Pay this invoice",
407
432
  paySuccess: "You have successfully paid the invoice",
408
- payError: "Failed to paid the invoice",
433
+ payError: "Failed to pay the invoice",
409
434
  renew: "Renew the subscription",
410
435
  renewSuccess: "You have successfully renewed the subscription",
411
436
  renewError: "Failed to renew the subscription",
@@ -433,7 +458,7 @@ module.exports = (0, _flat.default)({
433
458
  viewAll: "View all",
434
459
  empty: "There are no subscriptions here",
435
460
  changePayment: "Change payment method",
436
- trialLeft: "Trail Left",
461
+ trialLeft: "Trial Left",
437
462
  owner: "Subscription Owner"
438
463
  },
439
464
  overdue: {
package/lib/locales/zh.js CHANGED
@@ -233,6 +233,35 @@ module.exports = (0, _flat.default)({
233
233
  add: "\u6DFB\u52A0\u5230\u8BA2\u5355",
234
234
  remove: "\u4ECE\u8BA2\u5355\u79FB\u9664"
235
235
  },
236
+ promotion: {
237
+ add_code: "\u6DFB\u52A0\u4FC3\u9500\u7801",
238
+ enter_code: "\u8F93\u5165\u4FC3\u9500\u7801",
239
+ apply: "\u5E94\u7528",
240
+ applied: "\u5DF2\u5E94\u7528\u7684\u4FC3\u9500\u7801",
241
+ placeholder: "\u8F93\u5165\u4FC3\u9500\u7801",
242
+ duration_once: "1\u6B21\u4F18\u60E0 {amount} {symbol}",
243
+ duration_repeating: "{months}\u4E2A\u6708\u4F18\u60E0 {amount} {symbol}",
244
+ duration_forever: "\u6C38\u4E45\u4F18\u60E0 {amount} {symbol}",
245
+ dialog: {
246
+ title: "\u6DFB\u52A0\u4FC3\u9500\u7801"
247
+ },
248
+ error: {
249
+ invalid: "\u65E0\u6548\u7684\u4FC3\u9500\u7801",
250
+ expired: "\u4FC3\u9500\u7801\u5DF2\u8FC7\u671F",
251
+ used: "\u4FC3\u9500\u7801\u5DF2\u88AB\u4F7F\u7528",
252
+ not_applicable: "\u4FC3\u9500\u7801\u4E0D\u9002\u7528\u4E8E\u6B64\u8BA2\u5355"
253
+ }
254
+ },
255
+ coupon: {
256
+ noDiscount: "\u65E0\u4F18\u60E0",
257
+ percentage: "{percent}%",
258
+ fixedAmount: "{amount} {symbol}",
259
+ terms: {
260
+ forever: "\u6C38\u4E45\u4EAB {couponOff} \u6298\u6263",
261
+ once: "\u5355\u6B21\u4EAB {couponOff} \u6298\u6263",
262
+ repeating: "{months} \u4E2A\u6708\u5185\u4EAB {couponOff} \u6298\u6263"
263
+ }
264
+ },
236
265
  credit: {
237
266
  oneTimeInfo: "\u4ED8\u6B3E\u5B8C\u6210\u540E\u60A8\u5C06\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
238
267
  recurringInfo: "\u60A8\u5C06{period}\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
@@ -122,7 +122,8 @@ function PaymentForm({
122
122
  const {
123
123
  session,
124
124
  connect,
125
- payable
125
+ payable,
126
+ setPaymentState
126
127
  } = (0, _payment.usePaymentContext)();
127
128
  const subscription = (0, _subscription.useSubscription)("events");
128
129
  const formErrorPosition = "bottom";
@@ -174,6 +175,12 @@ function PaymentForm({
174
175
  subscription.on("checkout.session.completed", onCheckoutComplete);
175
176
  }
176
177
  }, [subscription]);
178
+ (0, _react.useEffect)(() => {
179
+ setPaymentState({
180
+ paying: state.submitting || state.paying,
181
+ stripePaying: state.stripePaying
182
+ });
183
+ }, [state.submitting, state.paying, state.stripePaying]);
177
184
  const mergeUserInfo = (customerInfo, userInfo) => {
178
185
  return {
179
186
  ...(userInfo || {}),
@@ -149,6 +149,13 @@ function PaymentInner({
149
149
  if (onChange) {
150
150
  onChange(methods.getValues());
151
151
  }
152
+ if (state.checkoutSession?.discounts?.length) {
153
+ _api.default.post(`/api/checkout-sessions/${state.checkoutSession.id}/recalculate-promotion`, {
154
+ currency_id: currencyId
155
+ }).then(() => {
156
+ onPromotionUpdate();
157
+ });
158
+ }
152
159
  }, [currencyId]);
153
160
  const onUpsell = async (from, to) => {
154
161
  try {
@@ -244,6 +251,19 @@ function PaymentInner({
244
251
  _Toast.default.error((0, _util2.formatError)(err));
245
252
  }
246
253
  };
254
+ const onPromotionUpdate = async () => {
255
+ try {
256
+ const {
257
+ data
258
+ } = await _api.default.get(`/api/checkout-sessions/retrieve/${state.checkoutSession.id}`);
259
+ setState({
260
+ checkoutSession: data.checkoutSession
261
+ });
262
+ } catch (err) {
263
+ console.error(err);
264
+ _Toast.default.error((0, _util2.formatError)(err));
265
+ }
266
+ };
247
267
  const handlePaid = result => {
248
268
  setState({
249
269
  checkoutSession: result.checkoutSession
@@ -292,6 +312,9 @@ function PaymentInner({
292
312
  donationSettings: paymentLink?.donation_settings,
293
313
  action,
294
314
  completed,
315
+ checkoutSession: state.checkoutSession,
316
+ onPromotionUpdate,
317
+ paymentMethods,
295
318
  showFeatures
296
319
  }), mode === "standalone" && !isMobile && /* @__PURE__ */(0, _jsxRuntime.jsx)(_footer.default, {
297
320
  className: "cko-footer",
@@ -183,6 +183,52 @@ function ProductItem({
183
183
  children: pricing.secondary
184
184
  })]
185
185
  })]
186
+ }), item.discount_amounts && item.discount_amounts.length > 0 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Stack, {
187
+ direction: "row",
188
+ spacing: 1,
189
+ sx: {
190
+ mt: 1,
191
+ alignItems: "center"
192
+ },
193
+ children: item.discount_amounts.map(discountAmount => /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Chip, {
194
+ icon: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.LocalOffer, {
195
+ sx: {
196
+ fontSize: "0.8rem !important"
197
+ }
198
+ }),
199
+ label: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
200
+ sx: {
201
+ display: "flex",
202
+ alignItems: "center",
203
+ gap: 0.5
204
+ },
205
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
206
+ component: "span",
207
+ sx: {
208
+ fontSize: "0.75rem",
209
+ fontWeight: "medium"
210
+ },
211
+ children: discountAmount.promotion_code?.code || "DISCOUNT"
212
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
213
+ component: "span",
214
+ sx: {
215
+ fontSize: "0.75rem"
216
+ },
217
+ children: ["(-", (0, _util.formatAmount)(discountAmount.amount || "0", currency.decimal), " ", currency.symbol, ")"]
218
+ })]
219
+ }),
220
+ size: "small",
221
+ variant: "filled",
222
+ sx: {
223
+ height: 20,
224
+ "& .MuiChip-icon": {
225
+ color: "warning.main"
226
+ },
227
+ "& .MuiChip-label": {
228
+ px: 1
229
+ }
230
+ }
231
+ }, discountAmount.promotion_code))
186
232
  }), showFeatures && features.length > 0 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
187
233
  sx: {
188
234
  display: "flex",
@@ -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 {};
@@ -24,6 +24,7 @@ var _livemode = _interopRequireDefault(require("../components/livemode"));
24
24
  var _payment = require("../contexts/payment");
25
25
  var _mobile = require("../hooks/mobile");
26
26
  var _loadingButton = _interopRequireDefault(require("../components/loading-button"));
27
+ var _promotionCode = _interopRequireDefault(require("../components/promotion-code"));
27
28
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
28
29
  const ExpandMore = (0, _styles.styled)(props => {
29
30
  const {
@@ -101,6 +102,9 @@ function PaymentSummary({
101
102
  action = "",
102
103
  trialEnd = 0,
103
104
  completed = false,
105
+ checkoutSession = void 0,
106
+ paymentMethods = [],
107
+ onPromotionUpdate = _noop.default,
104
108
  showFeatures = false,
105
109
  ...rest
106
110
  }) {
@@ -111,7 +115,10 @@ function PaymentSummary({
111
115
  const {
112
116
  isMobile
113
117
  } = (0, _mobile.useMobile)();
114
- const settings = (0, _payment.usePaymentContext)();
118
+ const {
119
+ paymentState,
120
+ ...settings
121
+ } = (0, _payment.usePaymentContext)();
115
122
  const [state, setState] = (0, _ahooks.useSetState)({
116
123
  loading: false,
117
124
  shake: false,
@@ -121,12 +128,40 @@ function PaymentSummary({
121
128
  data,
122
129
  runAsync
123
130
  } = (0, _ahooks.useRequest)(() => checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null));
124
- const headlines = (0, _util2.formatCheckoutHeadlines)(items, currency, {
131
+ const sessionDiscounts = checkoutSession?.discounts || [];
132
+ const allowPromotionCodes = !!checkoutSession?.allow_promotion_codes;
133
+ const hasDiscounts = sessionDiscounts?.length > 0;
134
+ const discountCurrency = paymentMethods && checkoutSession ? (0, _util2.findCurrency)(paymentMethods, hasDiscounts ? checkoutSession?.currency_id || currency.id : currency.id) || settings.settings?.baseCurrency : currency;
135
+ const headlines = (0, _util2.formatCheckoutHeadlines)(items, discountCurrency, {
125
136
  trialEnd,
126
137
  trialInDays
127
138
  }, locale);
128
- const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : "0";
129
- const totalAmount = (0, _util.fromUnitToToken)(new _util.BN((0, _util.fromTokenToUnit)(headlines.actualAmount, currency?.decimal)).add(new _util.BN(staking)).toString(), currency?.decimal);
139
+ const staking = showStaking ? getStakingSetup(items, discountCurrency, billingThreshold) : "0";
140
+ const getAppliedPromotionCodes = () => {
141
+ if (!sessionDiscounts?.length) return [];
142
+ return sessionDiscounts.map(discount => ({
143
+ id: discount.promotion_code || discount.coupon,
144
+ code: discount.verification_data?.code || "APPLIED",
145
+ discount_amount: discount.discount_amount
146
+ }));
147
+ };
148
+ const handlePromotionUpdate = () => {
149
+ onPromotionUpdate?.();
150
+ };
151
+ const handleRemovePromotion = async sessionId => {
152
+ if (paymentState.paying || paymentState.stripePaying) {
153
+ return;
154
+ }
155
+ try {
156
+ await _api.default.delete(`/api/checkout-sessions/${sessionId}/remove-promotion`);
157
+ onPromotionUpdate?.();
158
+ } catch (err) {
159
+ console.error("Failed to remove promotion code:", err);
160
+ }
161
+ };
162
+ const discountAmount = new _util.BN(checkoutSession?.total_details?.amount_discount || "0");
163
+ const subtotalAmount = (0, _util.fromUnitToToken)(new _util.BN((0, _util.fromTokenToUnit)(headlines.actualAmount, discountCurrency?.decimal)).add(new _util.BN(staking)).toString(), discountCurrency?.decimal);
164
+ const totalAmount = (0, _util.fromUnitToToken)(new _util.BN((0, _util.fromTokenToUnit)(subtotalAmount, discountCurrency?.decimal)).sub(discountAmount).toString(), discountCurrency?.decimal);
130
165
  (0, _useBus.default)("error.REQUIRE_CROSS_SELL", () => {
131
166
  setState({
132
167
  shake: true
@@ -194,13 +229,13 @@ function PaymentSummary({
194
229
  item: x,
195
230
  settings: donationSettings,
196
231
  onChange: onChangeAmount,
197
- currency
198
- }, `${x.price_id}-${currency.id}`) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_productItem.default, {
232
+ currency: discountCurrency
233
+ }, `${x.price_id}-${discountCurrency.id}`) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_productItem.default, {
199
234
  item: x,
200
235
  items,
201
236
  trialInDays,
202
237
  trialEnd,
203
- currency,
238
+ currency: discountCurrency,
204
239
  onUpsell: handleUpsell,
205
240
  onDownsell: handleDownsell,
206
241
  adjustableQuantity: x.adjustable_quantity,
@@ -225,7 +260,7 @@ function PaymentSummary({
225
260
  children: t("payment.checkout.cross_sell.remove")
226
261
  })]
227
262
  })
228
- }, `${x.price_id}-${currency.id}`))
263
+ }, `${x.price_id}-${discountCurrency.id}`))
229
264
  }), data && items.some(x => x.price_id === data.id) === false && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Grow, {
230
265
  in: true,
231
266
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Stack, {
@@ -241,7 +276,7 @@ function PaymentSummary({
241
276
  },
242
277
  items,
243
278
  trialInDays,
244
- currency,
279
+ currency: discountCurrency,
245
280
  trialEnd,
246
281
  onUpsell: _noop.default,
247
282
  onDownsell: _noop.default,
@@ -400,9 +435,116 @@ function PaymentSummary({
400
435
  })
401
436
  })]
402
437
  }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
403
- children: [(0, _util2.formatAmount)(staking, currency.decimal), " ", currency.symbol]
438
+ children: [(0, _util2.formatAmount)(staking, discountCurrency.decimal), " ", discountCurrency.symbol]
404
439
  })]
405
440
  })]
441
+ }), (allowPromotionCodes || hasDiscounts) && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
442
+ direction: "row",
443
+ spacing: 1,
444
+ sx: {
445
+ justifyContent: "space-between",
446
+ alignItems: "center",
447
+ ...(staking > 0 && {
448
+ borderTop: "1px solid",
449
+ borderColor: "divider",
450
+ pt: 1,
451
+ mt: 1
452
+ })
453
+ },
454
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
455
+ className: "base-label",
456
+ children: t("common.subtotal")
457
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
458
+ children: [(0, _util2.formatNumber)(subtotalAmount), " ", discountCurrency.symbol]
459
+ })]
460
+ }), allowPromotionCodes && !hasDiscounts && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
461
+ sx: {
462
+ mt: 1
463
+ },
464
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_promotionCode.default, {
465
+ checkoutSessionId: checkoutSession.id,
466
+ initialAppliedCodes: getAppliedPromotionCodes(),
467
+ disabled: completed,
468
+ onUpdate: handlePromotionUpdate,
469
+ currencyId: currency.id
470
+ })
471
+ }), hasDiscounts && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
472
+ sx: {
473
+ py: 1.5
474
+ },
475
+ children: sessionDiscounts.map(discount => {
476
+ const promotionCodeInfo = discount.promotion_code_details;
477
+ const couponInfo = discount.coupon_details;
478
+ const discountDescription = couponInfo ? (0, _util2.formatCouponTerms)(couponInfo, discountCurrency, locale) : "";
479
+ const notSupported = discountDescription === t("payment.checkout.coupon.noDiscount");
480
+ return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
481
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
482
+ direction: "row",
483
+ spacing: 1,
484
+ sx: {
485
+ justifyContent: "space-between",
486
+ alignItems: "center"
487
+ },
488
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
489
+ direction: "row",
490
+ spacing: 1,
491
+ sx: {
492
+ alignItems: "center",
493
+ backgroundColor: "grey.100",
494
+ width: "fit-content",
495
+ px: 1,
496
+ py: 0.5,
497
+ borderRadius: 1
498
+ },
499
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
500
+ sx: {
501
+ fontWeight: "medium",
502
+ fontSize: "small",
503
+ display: "flex",
504
+ alignItems: "center",
505
+ gap: 0.5
506
+ },
507
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.LocalOffer, {
508
+ sx: {
509
+ color: "warning.main",
510
+ fontSize: "small"
511
+ }
512
+ }), promotionCodeInfo?.code || discount.verification_data?.code || t("payment.checkout.discount")]
513
+ }), !completed && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
514
+ size: "small",
515
+ disabled: paymentState.paying || paymentState.stripePaying,
516
+ onClick: () => handleRemovePromotion(checkoutSessionId),
517
+ sx: {
518
+ minWidth: "auto",
519
+ width: 16,
520
+ height: 16,
521
+ color: "text.secondary",
522
+ "&.Mui-disabled": {
523
+ color: "text.disabled"
524
+ }
525
+ },
526
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.Close, {
527
+ sx: {
528
+ fontSize: 14
529
+ }
530
+ })
531
+ })]
532
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
533
+ sx: {
534
+ color: "text.secondary"
535
+ },
536
+ children: ["-", (0, _util2.formatAmount)(discount.discount_amount || "0", discountCurrency.decimal), " ", discountCurrency.symbol]
537
+ })]
538
+ }), discountDescription && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
539
+ sx: {
540
+ fontSize: "small",
541
+ color: notSupported ? "error.main" : "text.secondary",
542
+ mt: 0.5
543
+ },
544
+ children: discountDescription
545
+ })]
546
+ }, discount.promotion_code || discount.coupon || `discount-${discount.discount_amount}`);
547
+ })
406
548
  }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
407
549
  sx: {
408
550
  display: "flex",
@@ -415,7 +557,7 @@ function PaymentSummary({
415
557
  className: "base-label",
416
558
  children: [t("common.total"), " "]
417
559
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_amount.default, {
418
- amount: `${totalAmount} ${currency.symbol}`,
560
+ amount: `${totalAmount} ${discountCurrency.symbol}`,
419
561
  sx: {
420
562
  fontSize: "16px"
421
563
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.20.10",
3
+ "version": "1.20.12",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -54,16 +54,16 @@
54
54
  }
55
55
  },
56
56
  "dependencies": {
57
- "@arcblock/did-connect-react": "^3.1.40",
58
- "@arcblock/ux": "^3.1.40",
59
- "@arcblock/ws": "^1.24.9",
60
- "@blocklet/theme": "^3.1.40",
61
- "@blocklet/ui-react": "^3.1.40",
57
+ "@arcblock/did-connect-react": "^3.1.41",
58
+ "@arcblock/ux": "^3.1.41",
59
+ "@arcblock/ws": "^1.25.1",
60
+ "@blocklet/theme": "^3.1.41",
61
+ "@blocklet/ui-react": "^3.1.41",
62
62
  "@mui/icons-material": "^7.1.2",
63
63
  "@mui/lab": "7.0.0-beta.14",
64
64
  "@mui/material": "^7.1.2",
65
65
  "@mui/system": "^7.1.1",
66
- "@ocap/util": "^1.24.9",
66
+ "@ocap/util": "^1.25.1",
67
67
  "@stripe/react-stripe-js": "^2.9.0",
68
68
  "@stripe/stripe-js": "^2.4.0",
69
69
  "@vitejs/plugin-legacy": "^7.0.0",
@@ -94,7 +94,7 @@
94
94
  "@babel/core": "^7.27.4",
95
95
  "@babel/preset-env": "^7.27.2",
96
96
  "@babel/preset-react": "^7.27.1",
97
- "@blocklet/payment-types": "1.20.10",
97
+ "@blocklet/payment-types": "1.20.12",
98
98
  "@storybook/addon-essentials": "^7.6.20",
99
99
  "@storybook/addon-interactions": "^7.6.20",
100
100
  "@storybook/addon-links": "^7.6.20",
@@ -125,5 +125,5 @@
125
125
  "vite-plugin-babel": "^1.3.1",
126
126
  "vite-plugin-node-polyfills": "^0.23.0"
127
127
  },
128
- "gitHead": "1659d63120ced92167ec8681e51db96801b910ec"
128
+ "gitHead": "e6c432f89c2bf305efc903c0809f4a0557c07774"
129
129
  }