@blocklet/payment-react 1.20.11 → 1.20.13

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 +25 -0
  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 +25 -0
  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 +25 -0
  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/src/libs/util.ts CHANGED
@@ -5,6 +5,7 @@ import type {
5
5
  PaymentDetails,
6
6
  PriceCurrency,
7
7
  PriceRecurring,
8
+ TCoupon,
8
9
  TInvoiceExpanded,
9
10
  TLineItemExpanded,
10
11
  TPaymentCurrency,
@@ -31,6 +32,40 @@ import type { ActionProps, PricingRenderProps } from '../types';
31
32
 
32
33
  export const PAYMENT_KIT_DID = 'z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk';
33
34
 
35
+ /**
36
+ * Format coupon discount terms for display
37
+ */
38
+ export const formatCouponTerms = (coupon: TCoupon, currency: TPaymentCurrency, locale: string = 'en'): string => {
39
+ let couponOff = '';
40
+
41
+ if (coupon.percent_off && coupon.percent_off > 0) {
42
+ couponOff = t('payment.checkout.coupon.percentage', locale, { percent: coupon.percent_off });
43
+ }
44
+
45
+ if (coupon.amount_off && coupon.amount_off !== '0') {
46
+ const { symbol } = currency;
47
+ couponOff =
48
+ coupon.currency_id === currency.id
49
+ ? coupon.amount_off || ''
50
+ : coupon.currency_options?.[currency.id]?.amount_off || '';
51
+ if (couponOff) {
52
+ couponOff = t('payment.checkout.coupon.fixedAmount', locale, {
53
+ amount: formatAmount(couponOff, currency.decimal),
54
+ symbol,
55
+ });
56
+ }
57
+ }
58
+
59
+ if (!couponOff) {
60
+ return t('payment.checkout.coupon.noDiscount');
61
+ }
62
+
63
+ return t(`payment.checkout.coupon.terms.${coupon.duration}`, locale, {
64
+ couponOff,
65
+ months: coupon.duration_in_months || 0,
66
+ });
67
+ };
68
+
34
69
  export const isPaymentKitMounted = () => {
35
70
  return (window.blocklet?.componentMountPoints || []).some((x: any) => x.did === PAYMENT_KIT_DID);
36
71
  };
@@ -246,6 +246,31 @@ export default flat({
246
246
  orderSummary: 'Order Summary',
247
247
  paymentDetails: 'Payment Details',
248
248
  productListTotal: 'Includes {total} items',
249
+ promotion: {
250
+ add_code: 'Add promotion code',
251
+ enter_code: 'Enter promotion code',
252
+ placeholder: 'Enter code',
253
+ apply: 'Apply',
254
+ applied: 'Applied promotion codes',
255
+ dialog: {
256
+ title: 'Add promotion code',
257
+ },
258
+ error: {
259
+ unknown: 'Unknown error',
260
+ network: 'Network error occurred',
261
+ removal: 'Failed to remove code',
262
+ },
263
+ },
264
+ coupon: {
265
+ noDiscount: 'No discount',
266
+ percentage: '{percent}% off',
267
+ fixedAmount: '{amount} {symbol} off',
268
+ terms: {
269
+ forever: '{couponOff} forever',
270
+ once: '{couponOff} once',
271
+ repeating: "{couponOff} for {months} month{months > 1 ? 's' : ''}",
272
+ },
273
+ },
249
274
  connectModal: {
250
275
  title: '{action}',
251
276
  scan: 'Use the following methods to complete this payment',
@@ -229,6 +229,35 @@ export default flat({
229
229
  add: '添加到订单',
230
230
  remove: '从订单移除',
231
231
  },
232
+ promotion: {
233
+ add_code: '添加促销码',
234
+ enter_code: '输入促销码',
235
+ apply: '应用',
236
+ applied: '已应用的促销码',
237
+ placeholder: '输入促销码',
238
+ duration_once: '1次优惠 {amount} {symbol}',
239
+ duration_repeating: '{months}个月优惠 {amount} {symbol}',
240
+ duration_forever: '永久优惠 {amount} {symbol}',
241
+ dialog: {
242
+ title: '添加促销码',
243
+ },
244
+ error: {
245
+ invalid: '无效的促销码',
246
+ expired: '促销码已过期',
247
+ used: '促销码已被使用',
248
+ not_applicable: '促销码不适用于此订单',
249
+ },
250
+ },
251
+ coupon: {
252
+ noDiscount: '无优惠',
253
+ percentage: '{percent}%',
254
+ fixedAmount: '{amount} {symbol}',
255
+ terms: {
256
+ forever: '永久享 {couponOff} 折扣',
257
+ once: '单次享 {couponOff} 折扣',
258
+ repeating: '{months} 个月内享 {couponOff} 折扣',
259
+ },
260
+ },
232
261
  credit: {
233
262
  oneTimeInfo: '付款完成后您将获得 {amount} {symbol} 额度',
234
263
  recurringInfo: '您将{period}获得 {amount} {symbol} 额度',
@@ -176,7 +176,7 @@ export default function PaymentForm({
176
176
  // const theme = useTheme();
177
177
  const { t, locale } = useLocaleContext();
178
178
  const { isMobile } = useMobile();
179
- const { session, connect, payable } = usePaymentContext();
179
+ const { session, connect, payable, setPaymentState } = usePaymentContext();
180
180
  const subscription = useSubscription('events');
181
181
  const formErrorPosition = 'bottom';
182
182
  const {
@@ -244,6 +244,15 @@ export default function PaymentForm({
244
244
  }
245
245
  }, [subscription]); // eslint-disable-line react-hooks/exhaustive-deps
246
246
 
247
+ // Sync payment states to PaymentContext
248
+ useEffect(() => {
249
+ setPaymentState({
250
+ paying: state.submitting || state.paying,
251
+ stripePaying: state.stripePaying,
252
+ });
253
+ // eslint-disable-next-line react-hooks/exhaustive-deps
254
+ }, [state.submitting, state.paying, state.stripePaying]);
255
+
247
256
  const mergeUserInfo = (
248
257
  customerInfo: UserInfo | (TCustomer & { fullName?: string }),
249
258
  userInfo?: UserInfo
@@ -177,6 +177,15 @@ function PaymentInner({
177
177
  if (onChange) {
178
178
  onChange(methods.getValues());
179
179
  }
180
+ if ((state.checkoutSession as any)?.discounts?.length) {
181
+ api
182
+ .post(`/api/checkout-sessions/${state.checkoutSession.id}/recalculate-promotion`, {
183
+ currency_id: currencyId,
184
+ })
185
+ .then(() => {
186
+ onPromotionUpdate();
187
+ });
188
+ }
180
189
  }, [currencyId]); // eslint-disable-line
181
190
 
182
191
  const onUpsell = async (from: string, to: string) => {
@@ -245,6 +254,16 @@ function PaymentInner({
245
254
  }
246
255
  };
247
256
 
257
+ const onPromotionUpdate = async () => {
258
+ try {
259
+ const { data } = await api.get(`/api/checkout-sessions/retrieve/${state.checkoutSession.id}`);
260
+ setState({ checkoutSession: data.checkoutSession });
261
+ } catch (err) {
262
+ console.error(err);
263
+ Toast.error(formatError(err));
264
+ }
265
+ };
266
+
248
267
  const handlePaid = (result: any) => {
249
268
  setState({ checkoutSession: result.checkoutSession });
250
269
  onPaid(result);
@@ -292,6 +311,9 @@ function PaymentInner({
292
311
  donationSettings={paymentLink?.donation_settings}
293
312
  action={action}
294
313
  completed={completed}
314
+ checkoutSession={state.checkoutSession}
315
+ onPromotionUpdate={onPromotionUpdate}
316
+ paymentMethods={paymentMethods as TPaymentMethodExpanded[]}
295
317
  showFeatures={showFeatures}
296
318
  />
297
319
  {mode === 'standalone' && !isMobile && (
@@ -1,7 +1,7 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import type { PriceRecurring, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
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
 
6
6
  import React, { useMemo, useState } from 'react';
7
7
  import Status from '../components/status';
@@ -14,6 +14,7 @@ import {
14
14
  formatQuantityInventory,
15
15
  formatRecurring,
16
16
  formatUpsellSaving,
17
+ formatAmount,
17
18
  } from '../libs/util';
18
19
  import ProductCard from './product-card';
19
20
  import dayjs from '../libs/dayjs';
@@ -212,6 +213,40 @@ export default function ProductItem({
212
213
  )}
213
214
  </Stack>
214
215
  </Stack>
216
+
217
+ {/* Display discount information for this item */}
218
+ {item.discount_amounts && item.discount_amounts.length > 0 && (
219
+ <Stack direction="row" spacing={1} sx={{ mt: 1, alignItems: 'center' }}>
220
+ {item.discount_amounts.map((discountAmount: any) => (
221
+ <Chip
222
+ key={discountAmount.promotion_code}
223
+ icon={<LocalOffer sx={{ fontSize: '0.8rem !important' }} />}
224
+ label={
225
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
226
+ <Typography component="span" sx={{ fontSize: '0.75rem', fontWeight: 'medium' }}>
227
+ {discountAmount.promotion_code?.code || 'DISCOUNT'}
228
+ </Typography>
229
+ <Typography component="span" sx={{ fontSize: '0.75rem' }}>
230
+ (-{formatAmount(discountAmount.amount || '0', currency.decimal)} {currency.symbol})
231
+ </Typography>
232
+ </Box>
233
+ }
234
+ size="small"
235
+ variant="filled"
236
+ sx={{
237
+ height: 20,
238
+ '& .MuiChip-icon': {
239
+ color: 'warning.main',
240
+ },
241
+ '& .MuiChip-label': {
242
+ px: 1,
243
+ },
244
+ }}
245
+ />
246
+ ))}
247
+ </Stack>
248
+ )}
249
+
215
250
  {showFeatures && features.length > 0 && (
216
251
  <Box
217
252
  sx={{
@@ -1,7 +1,14 @@
1
+ /* eslint-disable @typescript-eslint/indent */
1
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
- import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
3
- import { HelpOutline } from '@mui/icons-material';
4
- import { Box, Divider, Fade, Grow, Stack, Tooltip, Typography, Collapse, IconButton } from '@mui/material';
3
+ import type {
4
+ DonationSettings,
5
+ TLineItemExpanded,
6
+ TPaymentCurrency,
7
+ TCheckoutSession,
8
+ TPaymentMethodExpanded,
9
+ } from '@blocklet/payment-types';
10
+ import { HelpOutline, Close, LocalOffer } from '@mui/icons-material';
11
+ import { Box, Divider, Fade, Grow, Stack, Tooltip, Typography, Collapse, IconButton, Button } from '@mui/material';
5
12
  import type { IconButtonProps } from '@mui/material';
6
13
  import { BN, fromTokenToUnit, fromUnitToToken } from '@ocap/util';
7
14
  import { useRequest, useSetState } from 'ahooks';
@@ -11,7 +18,14 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
11
18
  import { styled } from '@mui/material/styles';
12
19
  import Status from '../components/status';
13
20
  import api from '../libs/api';
14
- import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from '../libs/util';
21
+ import {
22
+ formatAmount,
23
+ formatCheckoutHeadlines,
24
+ getPriceUintAmountByCurrency,
25
+ formatCouponTerms,
26
+ formatNumber,
27
+ findCurrency,
28
+ } from '../libs/util';
15
29
  import PaymentAmount from './amount';
16
30
  import ProductDonation from './product-donation';
17
31
  import ProductItem from './product-item';
@@ -19,6 +33,7 @@ import Livemode from '../components/livemode';
19
33
  import { usePaymentContext } from '../contexts/payment';
20
34
  import { useMobile } from '../hooks/mobile';
21
35
  import LoadingButton from '../components/loading-button';
36
+ import PromotionCode from '../components/promotion-code';
22
37
 
23
38
  // const shake = keyframes`
24
39
  // 0% {
@@ -71,6 +86,9 @@ type Props = {
71
86
  donationSettings?: DonationSettings; // only include backend part
72
87
  action?: string;
73
88
  completed?: boolean;
89
+ checkoutSession?: TCheckoutSession;
90
+ onPromotionUpdate?: () => void;
91
+ paymentMethods?: TPaymentMethodExpanded[];
74
92
  showFeatures?: boolean;
75
93
  };
76
94
 
@@ -139,23 +157,74 @@ export default function PaymentSummary({
139
157
  action = '',
140
158
  trialEnd = 0,
141
159
  completed = false,
160
+ checkoutSession = undefined,
161
+ paymentMethods = [],
162
+ onPromotionUpdate = noop,
142
163
  showFeatures = false,
143
164
  ...rest
144
165
  }: Props) {
145
166
  const { t, locale } = useLocaleContext();
146
167
  const { isMobile } = useMobile();
147
- const settings = usePaymentContext();
168
+ const { paymentState, ...settings } = usePaymentContext();
148
169
  const [state, setState] = useSetState({ loading: false, shake: false, expanded: items?.length < 3 });
149
170
  const { data, runAsync } = useRequest(() =>
150
171
  checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null)
151
172
  );
152
- const headlines = formatCheckoutHeadlines(items, currency, { trialEnd, trialInDays }, locale);
153
- const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : '0';
173
+
174
+ const sessionDiscounts = (checkoutSession as any)?.discounts || [];
175
+ const allowPromotionCodes = !!checkoutSession?.allow_promotion_codes;
176
+ const hasDiscounts = sessionDiscounts?.length > 0;
177
+
178
+ const discountCurrency =
179
+ paymentMethods && checkoutSession
180
+ ? (findCurrency(
181
+ paymentMethods as TPaymentMethodExpanded[],
182
+ hasDiscounts ? checkoutSession?.currency_id || currency.id : (currency.id as string)
183
+ ) as TPaymentCurrency) || settings.settings?.baseCurrency
184
+ : currency;
185
+
186
+ const headlines = formatCheckoutHeadlines(items, discountCurrency, { trialEnd, trialInDays }, locale);
187
+ const staking = showStaking ? getStakingSetup(items, discountCurrency, billingThreshold) : '0';
188
+
189
+ const getAppliedPromotionCodes = () => {
190
+ if (!sessionDiscounts?.length) return [];
191
+
192
+ return sessionDiscounts.map((discount: any) => ({
193
+ id: discount.promotion_code || discount.coupon,
194
+ code: discount.verification_data?.code || 'APPLIED',
195
+ discount_amount: discount.discount_amount,
196
+ }));
197
+ };
198
+
199
+ const handlePromotionUpdate = () => {
200
+ onPromotionUpdate?.();
201
+ };
202
+
203
+ const handleRemovePromotion = async (sessionId: string) => {
204
+ // Prevent removing promotion during payment process
205
+ if (paymentState.paying || paymentState.stripePaying) {
206
+ return;
207
+ }
208
+ try {
209
+ await api.delete(`/api/checkout-sessions/${sessionId}/remove-promotion`);
210
+ onPromotionUpdate?.();
211
+ } catch (err: any) {
212
+ console.error('Failed to remove promotion code:', err);
213
+ }
214
+ };
215
+
216
+ const discountAmount = new BN(checkoutSession?.total_details?.amount_discount || '0');
217
+
218
+ const subtotalAmount = fromUnitToToken(
219
+ new BN(fromTokenToUnit(headlines.actualAmount, discountCurrency?.decimal)).add(new BN(staking)).toString(),
220
+ discountCurrency?.decimal
221
+ );
154
222
 
155
223
  const totalAmount = fromUnitToToken(
156
- new BN(fromTokenToUnit(headlines.actualAmount, currency?.decimal)).add(new BN(staking)).toString(),
157
- currency?.decimal
224
+ new BN(fromTokenToUnit(subtotalAmount, discountCurrency?.decimal)).sub(discountAmount).toString(),
225
+ discountCurrency?.decimal
158
226
  );
227
+
159
228
  useBus(
160
229
  'error.REQUIRE_CROSS_SELL',
161
230
  () => {
@@ -217,20 +286,20 @@ export default function PaymentSummary({
217
286
  {items.map((x: TLineItemExpanded) =>
218
287
  x.price.custom_unit_amount && onChangeAmount && donationSettings ? (
219
288
  <ProductDonation
220
- key={`${x.price_id}-${currency.id}`}
289
+ key={`${x.price_id}-${discountCurrency.id}`}
221
290
  item={x}
222
291
  settings={donationSettings}
223
292
  onChange={onChangeAmount}
224
- currency={currency}
293
+ currency={discountCurrency}
225
294
  />
226
295
  ) : (
227
296
  <ProductItem
228
- key={`${x.price_id}-${currency.id}`}
297
+ key={`${x.price_id}-${discountCurrency.id}`}
229
298
  item={x}
230
299
  items={items}
231
300
  trialInDays={trialInDays}
232
301
  trialEnd={trialEnd}
233
- currency={currency}
302
+ currency={discountCurrency}
234
303
  onUpsell={handleUpsell}
235
304
  onDownsell={handleDownsell}
236
305
  adjustableQuantity={x.adjustable_quantity}
@@ -272,7 +341,7 @@ export default function PaymentSummary({
272
341
  item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
273
342
  items={items}
274
343
  trialInDays={trialInDays}
275
- currency={currency}
344
+ currency={discountCurrency}
276
345
  trialEnd={trialEnd}
277
346
  onUpsell={noop}
278
347
  onDownsell={noop}>
@@ -393,11 +462,127 @@ export default function PaymentSummary({
393
462
  </Tooltip>
394
463
  </Stack>
395
464
  <Typography>
396
- {formatAmount(staking, currency.decimal)} {currency.symbol}
465
+ {formatAmount(staking, discountCurrency.decimal)} {discountCurrency.symbol}
397
466
  </Typography>
398
467
  </Stack>
399
468
  </>
400
469
  )}
470
+ {(allowPromotionCodes || hasDiscounts) && (
471
+ <Stack
472
+ direction="row"
473
+ spacing={1}
474
+ sx={{
475
+ justifyContent: 'space-between',
476
+ alignItems: 'center',
477
+ ...(staking > 0 && {
478
+ borderTop: '1px solid',
479
+ borderColor: 'divider',
480
+ pt: 1,
481
+ mt: 1,
482
+ }),
483
+ }}>
484
+ <Typography className="base-label">{t('common.subtotal')}</Typography>
485
+ <Typography>
486
+ {formatNumber(subtotalAmount)} {discountCurrency.symbol}
487
+ </Typography>
488
+ </Stack>
489
+ )}
490
+ {/* Promotion Code Section - only show add button if no discounts applied */}
491
+ {allowPromotionCodes && !hasDiscounts && (
492
+ <Box sx={{ mt: 1 }}>
493
+ <PromotionCode
494
+ checkoutSessionId={checkoutSession.id}
495
+ initialAppliedCodes={getAppliedPromotionCodes()}
496
+ disabled={completed}
497
+ onUpdate={handlePromotionUpdate}
498
+ currencyId={currency.id}
499
+ />
500
+ </Box>
501
+ )}
502
+
503
+ {/* Promotion Code Details */}
504
+ {hasDiscounts && (
505
+ <Box
506
+ sx={{
507
+ py: 1.5,
508
+ }}>
509
+ {sessionDiscounts.map((discount: any) => {
510
+ const promotionCodeInfo = discount.promotion_code_details;
511
+ const couponInfo = discount.coupon_details;
512
+ const discountDescription = couponInfo ? formatCouponTerms(couponInfo, discountCurrency, locale) : '';
513
+ const notSupported = discountDescription === t('payment.checkout.coupon.noDiscount');
514
+
515
+ return (
516
+ <Stack key={discount.promotion_code || discount.coupon || `discount-${discount.discount_amount}`}>
517
+ <Stack
518
+ direction="row"
519
+ spacing={1}
520
+ sx={{
521
+ justifyContent: 'space-between',
522
+ alignItems: 'center',
523
+ }}>
524
+ <Stack
525
+ direction="row"
526
+ spacing={1}
527
+ sx={{
528
+ alignItems: 'center',
529
+ backgroundColor: 'grey.100',
530
+ width: 'fit-content',
531
+ px: 1,
532
+ py: 0.5,
533
+ borderRadius: 1,
534
+ }}>
535
+ <Typography
536
+ sx={{
537
+ fontWeight: 'medium',
538
+ fontSize: 'small',
539
+ display: 'flex',
540
+ alignItems: 'center',
541
+ gap: 0.5,
542
+ }}>
543
+ <LocalOffer sx={{ color: 'warning.main', fontSize: 'small' }} />
544
+ {promotionCodeInfo?.code || discount.verification_data?.code || t('payment.checkout.discount')}
545
+ </Typography>
546
+ {!completed && (
547
+ <Button
548
+ size="small"
549
+ disabled={paymentState.paying || paymentState.stripePaying}
550
+ onClick={() => handleRemovePromotion(checkoutSessionId)}
551
+ sx={{
552
+ minWidth: 'auto',
553
+ width: 16,
554
+ height: 16,
555
+ color: 'text.secondary',
556
+ '&.Mui-disabled': {
557
+ color: 'text.disabled',
558
+ },
559
+ }}>
560
+ <Close sx={{ fontSize: 14 }} />
561
+ </Button>
562
+ )}
563
+ </Stack>
564
+ <Typography sx={{ color: 'text.secondary' }}>
565
+ -{formatAmount(discount.discount_amount || '0', discountCurrency.decimal)}{' '}
566
+ {discountCurrency.symbol}
567
+ </Typography>
568
+ </Stack>
569
+ {/* Show discount description */}
570
+ {discountDescription && (
571
+ <Typography
572
+ sx={{
573
+ fontSize: 'small',
574
+ color: notSupported ? 'error.main' : 'text.secondary',
575
+ mt: 0.5,
576
+ }}>
577
+ {discountDescription}
578
+ </Typography>
579
+ )}
580
+ </Stack>
581
+ );
582
+ })}
583
+ </Box>
584
+ )}
585
+
401
586
  <Stack
402
587
  sx={{
403
588
  display: 'flex',
@@ -407,7 +592,7 @@ export default function PaymentSummary({
407
592
  width: '100%',
408
593
  }}>
409
594
  <Box className="base-label">{t('common.total')} </Box>
410
- <PaymentAmount amount={`${totalAmount} ${currency.symbol}`} sx={{ fontSize: '16px' }} />
595
+ <PaymentAmount amount={`${totalAmount} ${discountCurrency.symbol}`} sx={{ fontSize: '16px' }} />
411
596
  </Stack>
412
597
  {headlines.then && headlines.showThen && (
413
598
  <Typography