@blocklet/payment-react 1.20.20 → 1.20.22

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.
@@ -1,6 +1,19 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
- import { Box, LinearProgress, Typography } from '@mui/material';
2
+ import { Box, LinearProgress, Skeleton, Typography } from '@mui/material';
3
3
  import { useCallback, useEffect, useRef, useState } from 'react';
4
+ import { Check } from '@mui/icons-material';
5
+
6
+ export function VendorPlaceholder() {
7
+ return (
8
+ <Box sx={{ mb: 2 }}>
9
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
10
+ <Skeleton variant="rounded" height={16} width={150} />
11
+ <Skeleton variant="rounded" height={16} width={50} />
12
+ </Box>
13
+ <Skeleton variant="rounded" height={8} width="100%" />
14
+ </Box>
15
+ );
16
+ }
4
17
 
5
18
  interface VendorStatus {
6
19
  success: boolean;
@@ -11,8 +24,33 @@ interface VendorStatus {
11
24
  message: string;
12
25
  appUrl?: string;
13
26
  title?: string;
27
+ vendorType: string;
14
28
  }
15
29
 
30
+ const getVendorLabel = (vendor: VendorStatus, isFailed: boolean, t: any) => {
31
+ const name = vendor.name || vendor.title;
32
+ const isCompleted = vendor.status === 'delivered';
33
+
34
+ if (vendor.vendorType === 'didnames') {
35
+ if (isFailed) {
36
+ return t('payment.checkout.vendor.didnames.failed', { name });
37
+ }
38
+ if (isCompleted) {
39
+ return t('payment.checkout.vendor.didnames.completed', { name });
40
+ }
41
+ return t('payment.checkout.vendor.didnames.processing', { name });
42
+ }
43
+
44
+ // Default to launcher type
45
+ if (isFailed) {
46
+ return t('payment.checkout.vendor.launcher.failed', { name });
47
+ }
48
+ if (isCompleted) {
49
+ return t('payment.checkout.vendor.launcher.completed', { name });
50
+ }
51
+ return t('payment.checkout.vendor.launcher.processing', { name });
52
+ };
53
+
16
54
  export function VendorProgressItem({ vendor }: { vendor: VendorStatus }) {
17
55
  const { t } = useLocaleContext();
18
56
  const [displayProgress, setDisplayProgress] = useState(0);
@@ -49,7 +87,7 @@ export function VendorProgressItem({ vendor }: { vendor: VendorStatus }) {
49
87
 
50
88
  // Ensure progress is an integer
51
89
  newProgress = Math.round(newProgress);
52
- setDisplayProgress((pre) => (pre > newProgress ? pre : newProgress));
90
+ setDisplayProgress((pre) => Math.min(pre > newProgress ? pre : newProgress, 100));
53
91
 
54
92
  // Stop animation immediately when 100%
55
93
  if (realProgress === 100) {
@@ -80,7 +118,7 @@ export function VendorProgressItem({ vendor }: { vendor: VendorStatus }) {
80
118
  const isCompleted = displayProgress >= 100;
81
119
  const isFailed = vendor.status === 'failed';
82
120
 
83
- const nameText = vendor.name || vendor.title;
121
+ const nameText = getVendorLabel(vendor, isFailed, t);
84
122
 
85
123
  // 如果是失败状态,显示错误 UI
86
124
  if (isFailed) {
@@ -88,7 +126,7 @@ export function VendorProgressItem({ vendor }: { vendor: VendorStatus }) {
88
126
  <Box sx={{ mb: 2 }}>
89
127
  <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
90
128
  <Typography variant="body2" sx={{ color: 'text.secondary' }}>
91
- {nameText ? `${nameText} - ${t('payment.checkout.vendor.failed')}` : t('payment.checkout.vendor.failed')}
129
+ {nameText}
92
130
  </Typography>
93
131
  <Typography variant="body2" sx={{ color: 'error.main', fontWeight: 500 }}>
94
132
  {t('payment.checkout.vendor.progress', { progress: 0 })}
@@ -111,20 +149,25 @@ export function VendorProgressItem({ vendor }: { vendor: VendorStatus }) {
111
149
  );
112
150
  }
113
151
 
114
- const statusText = isCompleted ? t('payment.checkout.vendor.delivered') : t('payment.checkout.vendor.processing');
152
+ if (!vendor.name && !vendor.title) {
153
+ return <VendorPlaceholder />;
154
+ }
155
+
115
156
  return (
116
157
  <Box sx={{ mb: 2 }}>
117
158
  <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
118
- <Typography variant="body2" sx={{ color: 'text.secondary' }}>
119
- {nameText ? `${nameText} - ${statusText}` : statusText}
120
- </Typography>
121
- <Typography variant="body2" sx={{ color: 'text.secondary', fontWeight: 500 }}>
122
- {t('payment.checkout.vendor.progress', { progress: displayProgress })}
159
+ <Typography variant="body2" sx={{ color: 'text.secondary', display: 'flex', alignItems: 'center' }}>
160
+ {nameText} {isCompleted ? <Check sx={{ color: 'success.main', ml: 0.5 }} fontSize="small" /> : null}
123
161
  </Typography>
162
+ {isCompleted ? null : (
163
+ <Typography variant="body2" sx={{ color: 'text.secondary', fontWeight: 500 }}>
164
+ {t('payment.checkout.vendor.progress', { progress: displayProgress })}
165
+ </Typography>
166
+ )}
124
167
  </Box>
125
168
  <LinearProgress
126
169
  variant="determinate"
127
- value={Math.min(displayProgress, 100)}
170
+ value={displayProgress || 0}
128
171
  sx={{
129
172
  height: 8,
130
173
  borderRadius: 4,
@@ -5,12 +5,12 @@ import { joinURL } from 'ufo';
5
5
 
6
6
  import { Button } from '@arcblock/ux';
7
7
  import { usePaymentContext } from '../contexts/payment';
8
- import { VendorProgressItem } from './progress-item';
8
+ import { VendorPlaceholder, VendorProgressItem } from './progress-item';
9
9
 
10
10
  type Props = {
11
11
  mode: string;
12
12
  pageInfo?: any;
13
- hasVendor?: boolean;
13
+ vendorCount?: number;
14
14
  sessionId?: string;
15
15
  message: string;
16
16
  action: string;
@@ -27,6 +27,9 @@ interface VendorStatus {
27
27
  message: string;
28
28
  appUrl?: string;
29
29
  title?: string;
30
+ name?: string;
31
+ key?: string;
32
+ vendorType: string;
30
33
  }
31
34
 
32
35
  interface VendorResponse {
@@ -39,7 +42,7 @@ interface VendorResponse {
39
42
  export default function PaymentSuccess({
40
43
  mode,
41
44
  pageInfo = {},
42
- hasVendor = false,
45
+ vendorCount = 0,
43
46
  sessionId = '',
44
47
  message,
45
48
  action,
@@ -56,9 +59,9 @@ export default function PaymentSuccess({
56
59
  const timerRef = useRef(Date.now());
57
60
  let next: any = null;
58
61
 
59
- // Fetch vendor status when hasVendor is true
62
+ // Fetch vendor status when vendorCount > 0
60
63
  useEffect(() => {
61
- if (!hasVendor || !sessionId) return undefined;
64
+ if (vendorCount === 0 || !sessionId) return undefined;
62
65
 
63
66
  const fetchVendorStatus = async (interval?: NodeJS.Timeout) => {
64
67
  try {
@@ -89,11 +92,26 @@ export default function PaymentSuccess({
89
92
  }, 5000);
90
93
 
91
94
  return () => clearInterval(interval);
92
- }, [hasVendor, api, prefix, sessionId]);
95
+ }, [vendorCount, api, prefix, sessionId]);
96
+
97
+ const renderPlaceholders = () => {
98
+ const placeholders = [];
99
+ for (let i = 0; i < vendorCount; i++) {
100
+ placeholders.push(<VendorPlaceholder key={`placeholder-${i}`} />);
101
+ }
102
+ return placeholders;
103
+ };
104
+
105
+ const renderVendors = () => {
106
+ if (!vendorStatus) return renderPlaceholders();
107
+ return vendorStatus.vendors?.map((vendor, index) => {
108
+ return <VendorProgressItem key={vendor.title || `vendor-${index}`} vendor={vendor} />;
109
+ });
110
+ };
93
111
 
94
112
  // Render vendor progress component
95
113
  const renderVendorProgress = () => {
96
- if (!hasVendor || !vendorStatus) return null;
114
+ if (vendorCount === 0) return null;
97
115
 
98
116
  return (
99
117
  <Paper
@@ -108,9 +126,7 @@ export default function PaymentSuccess({
108
126
  flexDirection: 'column',
109
127
  gap: 2,
110
128
  }}>
111
- {vendorStatus.vendors?.map((vendor, index) => (
112
- <VendorProgressItem key={vendor.title || `vendor-${index}`} vendor={vendor} />
113
- ))}
129
+ {renderVendors()}
114
130
  {hasFailed ? (
115
131
  <Typography variant="h6" sx={{ color: 'warning.main', mb: 1 }}>
116
132
  {t('payment.checkout.vendor.failedMsg')}
@@ -275,6 +275,7 @@ export default function PaymentSummary({
275
275
  }
276
276
  };
277
277
 
278
+ const hasSubTotal = +staking > 0 || allowPromotionCodes;
278
279
  const ProductCardList = (
279
280
  <Stack
280
281
  className="cko-product-list"
@@ -422,7 +423,7 @@ export default function PaymentSummary({
422
423
  )}
423
424
  <Divider sx={{ mt: 2.5, mb: 2.5 }} />
424
425
  {+staking > 0 && (
425
- <>
426
+ <Stack spacing={1}>
426
427
  <Stack
427
428
  direction="row"
428
429
  spacing={1}
@@ -465,7 +466,7 @@ export default function PaymentSummary({
465
466
  {formatAmount(staking, discountCurrency.decimal)} {discountCurrency.symbol}
466
467
  </Typography>
467
468
  </Stack>
468
- </>
469
+ </Stack>
469
470
  )}
470
471
  {(allowPromotionCodes || hasDiscounts) && (
471
472
  <Stack
@@ -502,10 +503,7 @@ export default function PaymentSummary({
502
503
 
503
504
  {/* Promotion Code Details */}
504
505
  {hasDiscounts && (
505
- <Box
506
- sx={{
507
- py: 1.5,
508
- }}>
506
+ <Box>
509
507
  {sessionDiscounts.map((discount: any) => {
510
508
  const promotionCodeInfo = discount.promotion_code_details;
511
509
  const couponInfo = discount.coupon_details;
@@ -529,13 +527,12 @@ export default function PaymentSummary({
529
527
  backgroundColor: 'grey.100',
530
528
  width: 'fit-content',
531
529
  px: 1,
532
- py: 0.5,
530
+ py: 1,
533
531
  borderRadius: 1,
534
532
  }}>
535
533
  <Typography
536
534
  sx={{
537
535
  fontWeight: 'medium',
538
- fontSize: 'small',
539
536
  display: 'flex',
540
537
  alignItems: 'center',
541
538
  gap: 0.5,
@@ -582,7 +579,7 @@ export default function PaymentSummary({
582
579
  })}
583
580
  </Box>
584
581
  )}
585
-
582
+ {hasSubTotal && <Divider sx={{ my: 1 }} />}
586
583
  <Stack
587
584
  sx={{
588
585
  display: 'flex',