@blocklet/payment-react 1.26.0 → 1.26.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.
Files changed (43) hide show
  1. package/es/checkout-v2/components/left/cross-sell-card.js +3 -3
  2. package/es/checkout-v2/components/left/product-item-card.js +13 -7
  3. package/es/checkout-v2/components/left/promotion-input.d.ts +3 -1
  4. package/es/checkout-v2/components/left/promotion-input.js +4 -2
  5. package/es/checkout-v2/components/right/submit-button.js +3 -1
  6. package/es/checkout-v2/panels/left/composite-panel.js +27 -6
  7. package/es/checkout-v2/panels/left/credit-topup-panel.js +1 -5
  8. package/es/checkout-v2/panels/right/payment-panel.js +37 -8
  9. package/es/checkout-v2/utils/format.d.ts +1 -1
  10. package/es/checkout-v2/utils/format.js +3 -2
  11. package/es/checkout-v2/views/error-view.js +2 -0
  12. package/es/checkout-v2/views/success-view.js +3 -1
  13. package/es/components/over-due-invoice-payment.js +5 -3
  14. package/es/libs/util.d.ts +8 -0
  15. package/es/libs/util.js +3 -0
  16. package/lib/checkout-v2/components/left/cross-sell-card.js +2 -2
  17. package/lib/checkout-v2/components/left/product-item-card.js +13 -6
  18. package/lib/checkout-v2/components/left/promotion-input.d.ts +3 -1
  19. package/lib/checkout-v2/components/left/promotion-input.js +7 -2
  20. package/lib/checkout-v2/components/right/submit-button.js +3 -1
  21. package/lib/checkout-v2/panels/left/composite-panel.js +20 -5
  22. package/lib/checkout-v2/panels/left/credit-topup-panel.js +1 -5
  23. package/lib/checkout-v2/panels/right/payment-panel.js +43 -6
  24. package/lib/checkout-v2/utils/format.d.ts +1 -1
  25. package/lib/checkout-v2/utils/format.js +9 -2
  26. package/lib/checkout-v2/views/error-view.js +2 -0
  27. package/lib/checkout-v2/views/success-view.js +2 -0
  28. package/lib/components/over-due-invoice-payment.js +12 -2
  29. package/lib/libs/util.d.ts +8 -0
  30. package/lib/libs/util.js +4 -0
  31. package/package.json +4 -4
  32. package/src/checkout-v2/components/left/cross-sell-card.tsx +3 -3
  33. package/src/checkout-v2/components/left/product-item-card.tsx +30 -12
  34. package/src/checkout-v2/components/left/promotion-input.tsx +11 -3
  35. package/src/checkout-v2/components/right/submit-button.tsx +2 -0
  36. package/src/checkout-v2/panels/left/composite-panel.tsx +28 -6
  37. package/src/checkout-v2/panels/left/credit-topup-panel.tsx +1 -5
  38. package/src/checkout-v2/panels/right/payment-panel.tsx +30 -5
  39. package/src/checkout-v2/utils/format.ts +5 -2
  40. package/src/checkout-v2/views/error-view.tsx +2 -0
  41. package/src/checkout-v2/views/success-view.tsx +3 -1
  42. package/src/components/over-due-invoice-payment.tsx +6 -3
  43. package/src/libs/util.ts +7 -0
@@ -39,10 +39,10 @@ import {
39
39
  import { joinURL } from 'ufo';
40
40
  import { usePaymentContext } from '../../../contexts/payment';
41
41
  import { useMobile } from '../../../hooks/mobile';
42
- import { getPrefix } from '../../../libs/util';
42
+ import { getPrefix, getStatementDescriptor } from '../../../libs/util';
43
43
  import OverdueInvoicePayment from '../../../components/over-due-invoice-payment';
44
44
 
45
- import { tSafe, whiteTooltipSx } from '../../utils/format';
45
+ import { tSafe, whiteTooltipSx, primaryContrastColor } from '../../utils/format';
46
46
  import CustomerInfoCard from '../../components/right/customer-info-card';
47
47
  import SubscriptionDisclaimer from '../../components/right/subscription-disclaimer';
48
48
  import StatusFeedback from '../../components/right/status-feedback';
@@ -459,6 +459,7 @@ export default function PaymentPanel() {
459
459
  }}
460
460
  discounts={discounts}
461
461
  discountAmount={pricing.discount}
462
+ isAmountLoading={isAmountLoading}
462
463
  />
463
464
  </>
464
465
  )}
@@ -564,15 +565,39 @@ export default function PaymentPanel() {
564
565
  disabled={!canSubmit || submit.status === 'waiting_stripe'}
565
566
  onClick={handleAction}
566
567
  startIcon={isProcessing ? <CircularProgress size={20} color="inherit" /> : null}
567
- endIcon={!isProcessing ? <ArrowForwardIcon /> : undefined}
568
568
  sx={{
569
569
  py: 1.5,
570
570
  fontSize: '1.1rem',
571
571
  fontWeight: 600,
572
572
  textTransform: 'none',
573
573
  borderRadius: '12px',
574
+ color: (theme) => primaryContrastColor(theme),
575
+ position: 'relative',
576
+ overflow: 'hidden',
577
+ '&:hover': { bgcolor: 'primary.main' },
578
+ '&:hover .arrow-icon': { transform: 'translateX(4px)' },
579
+ '&:hover .shine-layer': { transform: 'translateX(100%)' },
574
580
  }}>
575
- {isProcessing ? `${t('payment.checkout.processing')}...` : buttonLabel}
581
+ <Box component="span" sx={{ position: 'relative', zIndex: 1 }}>
582
+ {isProcessing ? `${t('payment.checkout.processing')}...` : buttonLabel}
583
+ </Box>
584
+ {!isProcessing && (
585
+ <ArrowForwardIcon
586
+ className="arrow-icon"
587
+ sx={{ ml: 1, position: 'relative', zIndex: 1, transition: 'transform 0.2s ease' }}
588
+ />
589
+ )}
590
+ <Box
591
+ className="shine-layer"
592
+ sx={{
593
+ position: 'absolute',
594
+ inset: 0,
595
+ background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.12), transparent)',
596
+ transform: 'translateX(-100%)',
597
+ transition: 'transform 0.7s ease',
598
+ pointerEvents: 'none',
599
+ }}
600
+ />
576
601
  </Button>
577
602
 
578
603
  {/* Mobile: SSL footer inside fixed bar, below button */}
@@ -642,7 +667,7 @@ export default function PaymentPanel() {
642
667
  mode={mode}
643
668
  subscription={subscription}
644
669
  staking={pricing.staking}
645
- appName={(session?.metadata as any)?.app_name || 'New Payment Kit'}
670
+ appName={getStatementDescriptor(session?.line_items || [])}
646
671
  />
647
672
 
648
673
  {!isMobile && (
@@ -1,6 +1,8 @@
1
1
  import { fromUnitToToken } from '@ocap/util';
2
2
  import type { TPaymentCurrency } from '@blocklet/payment-types';
3
3
 
4
+ export { primaryContrastColor } from '../../libs/util';
5
+
4
6
  // Interval key → locale key mapping
5
7
  export const INTERVAL_LOCALE_KEY: Record<string, string> = {
6
8
  day: 'common.daily',
@@ -29,7 +31,7 @@ export function formatTokenAmount(unitAmount: string | number | bigint, currency
29
31
  const abs = Math.abs(num);
30
32
  const precision = abs > 0 && abs < 0.01 ? 6 : 2;
31
33
  const formatted = num.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: precision });
32
- return formatted.replace(/\.?0+$/, '') || '0';
34
+ return formatted.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '') || '0';
33
35
  } catch {
34
36
  return '0';
35
37
  }
@@ -90,7 +92,8 @@ export function formatDynamicUnitPrice(
90
92
  return (
91
93
  tokenAmount
92
94
  .toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: precision })
93
- .replace(/\.?0+$/, '') || '0'
95
+ .replace(/(\.\d*?)0+$/, '$1')
96
+ .replace(/\.$/, '') || '0'
94
97
  );
95
98
  }
96
99
  }
@@ -3,6 +3,7 @@ import { alpha, useTheme } from '@mui/material/styles';
3
3
  import ArrowBackIcon from '@mui/icons-material/ArrowBack';
4
4
  import Header from '@blocklet/ui-react/lib/Header';
5
5
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
6
+ import { primaryContrastColor } from '../utils/format';
6
7
 
7
8
  interface ErrorViewProps {
8
9
  error: string;
@@ -191,6 +192,7 @@ function ErrorContent({ error, errorCode = undefined }: { error: string; errorCo
191
192
  fontWeight: 600,
192
193
  fontSize: 16,
193
194
  letterSpacing: '0.02em',
195
+ color: (th) => primaryContrastColor(th),
194
196
  boxShadow: `0 8px 32px -4px ${alpha(primaryColor, 0.3)}`,
195
197
  '&:hover': {
196
198
  boxShadow: `0 12px 40px -4px ${alpha(primaryColor, 0.4)}`,
@@ -23,7 +23,7 @@ import type { TCheckoutSessionExpanded } from '@blocklet/payment-types';
23
23
  import { usePaymentMethodContext } from '@blocklet/payment-react-headless';
24
24
 
25
25
  import { getPrefix } from '../../libs/util';
26
- import { formatTokenAmount } from '../utils/format';
26
+ import { formatTokenAmount, primaryContrastColor } from '../utils/format';
27
27
 
28
28
  // ── Animations ──
29
29
 
@@ -573,6 +573,7 @@ function SubscriptionLinks({
573
573
  fontWeight: 700,
574
574
  fontSize: { xs: 16, md: 17 },
575
575
  letterSpacing: '0.02em',
576
+ color: (theme) => primaryContrastColor(theme),
576
577
  boxShadow: '0 8px 24px -4px rgba(59,130,246,0.25)',
577
578
  '&:hover': {
578
579
  boxShadow: '0 12px 28px -4px rgba(59,130,246,0.35)',
@@ -616,6 +617,7 @@ function InvoiceLink({
616
617
  fontWeight: 700,
617
618
  fontSize: { xs: 16, md: 17 },
618
619
  letterSpacing: '0.02em',
620
+ color: (theme) => primaryContrastColor(theme),
619
621
  boxShadow: '0 8px 24px -4px rgba(59,130,246,0.25)',
620
622
  '&:hover': {
621
623
  boxShadow: '0 12px 28px -4px rgba(59,130,246,0.35)',
@@ -19,7 +19,7 @@ import Dialog from '@arcblock/ux/lib/Dialog/dialog';
19
19
  import { CheckCircle as CheckCircleIcon } from '@mui/icons-material';
20
20
  import debounce from 'lodash/debounce';
21
21
  import { usePaymentContext } from '../contexts/payment';
22
- import { formatAmount, formatError, getPrefix, isCrossOrigin } from '../libs/util';
22
+ import { formatAmount, formatError, getPrefix, isCrossOrigin, primaryContrastColor } from '../libs/util';
23
23
  import { useSubscription } from '../hooks/subscription';
24
24
  import api from '../libs/api';
25
25
  import LoadingButton from './loading-button';
@@ -397,6 +397,8 @@ function OverdueInvoicePayment({
397
397
  const { currency } = item;
398
398
  const inProcess = payLoading && selectCurrencyId === currency.id;
399
399
  const status = paymentStatus[currency.id] || 'idle';
400
+ const containedColorSx =
401
+ (options?.variant || 'contained') === 'contained' ? { color: (th: any) => primaryContrastColor(th) } : {};
400
402
 
401
403
  if (status === 'success') {
402
404
  return (
@@ -404,6 +406,7 @@ function OverdueInvoicePayment({
404
406
  variant={options?.variant || 'contained'}
405
407
  size="small"
406
408
  onClick={() => checkAndHandleInvoicePaid(currency.id)}
409
+ sx={containedColorSx}
407
410
  {...(primaryButton
408
411
  ? {}
409
412
  : {
@@ -442,7 +445,7 @@ function OverdueInvoicePayment({
442
445
  disabled={paying || status === 'processing'}
443
446
  loading={paying || status === 'processing'}
444
447
  onClick={onPay}
445
- sx={options?.sx}>
448
+ sx={{ ...containedColorSx, ...((options?.sx || {}) as any) }}>
446
449
  {buttonText}
447
450
  </LoadingButton>
448
451
  )}
@@ -456,7 +459,7 @@ function OverdueInvoicePayment({
456
459
  disabled={inProcess}
457
460
  loading={inProcess}
458
461
  onClick={() => handlePay(item)}
459
- sx={options?.sx}>
462
+ sx={{ ...containedColorSx, ...((options?.sx || {}) as any) }}>
460
463
  {status === 'error' ? t('payment.subscription.overdue.retry') : t('payment.subscription.overdue.payNow')}
461
464
  </LoadingButton>
462
465
  );
package/src/libs/util.ts CHANGED
@@ -1823,3 +1823,10 @@ export function formatLinkWithLocale(url: string, locale?: string) {
1823
1823
  return `${url}${separator}locale=${locale}`;
1824
1824
  }
1825
1825
  }
1826
+
1827
+ // Compute text color that contrasts with primary.main, works in both light and dark mode
1828
+ export function primaryContrastColor(theme: {
1829
+ palette: { primary: { main: string }; getContrastText: (bg: string) => string };
1830
+ }): string {
1831
+ return theme.palette.getContrastText(theme.palette.primary.main);
1832
+ }