payment-kit 1.14.30 → 1.14.31

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 (58) hide show
  1. package/api/src/index.ts +4 -0
  2. package/api/src/libs/api.ts +23 -0
  3. package/api/src/libs/subscription.ts +32 -0
  4. package/api/src/queues/refund.ts +38 -1
  5. package/api/src/queues/subscription.ts +218 -21
  6. package/api/src/routes/checkout-sessions.ts +5 -0
  7. package/api/src/routes/customers.ts +27 -1
  8. package/api/src/routes/invoices.ts +5 -1
  9. package/api/src/routes/payment-intents.ts +17 -2
  10. package/api/src/routes/payment-links.ts +105 -3
  11. package/api/src/routes/payouts.ts +5 -1
  12. package/api/src/routes/prices.ts +19 -3
  13. package/api/src/routes/pricing-table.ts +79 -2
  14. package/api/src/routes/products.ts +24 -8
  15. package/api/src/routes/refunds.ts +7 -4
  16. package/api/src/routes/subscription-items.ts +5 -1
  17. package/api/src/routes/subscriptions.ts +25 -5
  18. package/api/src/routes/webhook-endpoints.ts +5 -1
  19. package/api/src/store/models/subscription.ts +1 -0
  20. package/api/tests/libs/api.spec.ts +72 -1
  21. package/api/third.d.ts +2 -0
  22. package/blocklet.yml +1 -1
  23. package/package.json +19 -18
  24. package/src/components/customer/form.tsx +53 -0
  25. package/src/components/filter-toolbar.tsx +1 -1
  26. package/src/components/invoice/list.tsx +8 -8
  27. package/src/components/invoice/table.tsx +42 -36
  28. package/src/components/metadata/form.tsx +24 -3
  29. package/src/components/payment-intent/actions.tsx +17 -5
  30. package/src/components/payment-link/after-pay.tsx +46 -4
  31. package/src/components/payouts/list.tsx +1 -1
  32. package/src/components/price/form.tsx +14 -2
  33. package/src/components/pricing-table/payment-settings.tsx +45 -4
  34. package/src/components/product/features.tsx +16 -2
  35. package/src/components/product/form.tsx +28 -4
  36. package/src/components/subscription/actions/cancel.tsx +10 -0
  37. package/src/components/subscription/description.tsx +2 -2
  38. package/src/components/subscription/items/index.tsx +3 -2
  39. package/src/components/subscription/portal/cancel.tsx +12 -1
  40. package/src/components/subscription/portal/list.tsx +6 -5
  41. package/src/locales/en.tsx +6 -1
  42. package/src/locales/zh.tsx +6 -1
  43. package/src/pages/admin/billing/invoices/detail.tsx +17 -2
  44. package/src/pages/admin/billing/subscriptions/detail.tsx +4 -0
  45. package/src/pages/admin/customers/customers/detail.tsx +4 -0
  46. package/src/pages/admin/customers/customers/index.tsx +1 -1
  47. package/src/pages/admin/payments/intents/detail.tsx +4 -0
  48. package/src/pages/admin/payments/payouts/detail.tsx +4 -0
  49. package/src/pages/admin/payments/refunds/detail.tsx +4 -0
  50. package/src/pages/admin/products/links/detail.tsx +4 -0
  51. package/src/pages/admin/products/prices/detail.tsx +4 -0
  52. package/src/pages/admin/products/pricing-tables/detail.tsx +4 -0
  53. package/src/pages/admin/products/products/detail.tsx +4 -0
  54. package/src/pages/checkout/pricing-table.tsx +9 -3
  55. package/src/pages/customer/index.tsx +28 -17
  56. package/src/pages/customer/invoice/detail.tsx +27 -16
  57. package/src/pages/customer/invoice/past-due.tsx +3 -2
  58. package/src/pages/customer/subscription/detail.tsx +4 -0
@@ -1,11 +1,15 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import { AddOutlined, DeleteOutlineOutlined } from '@mui/icons-material';
3
3
  import { Box, Button, IconButton, TextField, Typography } from '@mui/material';
4
+ import { get } from 'lodash';
4
5
  import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
5
6
 
6
7
  export default function MetadataForm() {
7
8
  const { t } = useLocaleContext();
8
- const { control } = useFormContext();
9
+ const {
10
+ control,
11
+ formState: { errors },
12
+ } = useFormContext();
9
13
  const features = useFieldArray({ control, name: 'features' });
10
14
  return (
11
15
  <Box sx={{ width: 1 }}>
@@ -13,7 +17,17 @@ export default function MetadataForm() {
13
17
  {features.fields.map((feature, index) => (
14
18
  <Box key={feature.id} mt={2} sx={{ width: 1 }}>
15
19
  <Controller
16
- render={({ field }) => <TextField {...field} sx={{ width: '80%' }} size="small" />}
20
+ render={({ field }) => (
21
+ <TextField
22
+ {...field}
23
+ sx={{ width: '80%' }}
24
+ size="small"
25
+ inputProps={{ maxLength: 64 }}
26
+ error={!!get(errors, field.name)}
27
+ helperText={get(errors, field.name)?.message as string}
28
+ />
29
+ )}
30
+ rules={{ maxLength: { value: 64, message: t('common.maxLength', { len: 64 }) } }}
17
31
  name={`features.${index}.name`}
18
32
  control={control}
19
33
  />
@@ -38,16 +38,29 @@ export default function ProductForm(props: Props) {
38
38
  <Stack spacing={2} flex={2} alignItems="flex-start">
39
39
  <FormInput
40
40
  name="name"
41
- rules={{ required: t('admin.product.name.required') }}
41
+ rules={{
42
+ required: t('admin.product.name.required'),
43
+ maxLength: {
44
+ value: 64,
45
+ message: t('common.maxLength', { len: 64 }),
46
+ },
47
+ }}
42
48
  label={t('admin.product.name.label')}
43
49
  placeholder={t('admin.product.name.placeholder')}
44
50
  error={!!formState.errors.name}
45
51
  helperText={formState.errors.name?.message as string}
46
52
  autoFocus
53
+ inputProps={{ maxLength: 64 }}
47
54
  />
48
55
  <FormInput
49
56
  name="description"
50
- rules={{ required: t('admin.product.description.required') }}
57
+ rules={{
58
+ required: t('admin.product.description.required'),
59
+ maxLength: {
60
+ value: 256,
61
+ message: t('common.maxLength', { len: 256 }),
62
+ },
63
+ }}
51
64
  label={t('admin.product.description.label')}
52
65
  placeholder={t('admin.product.description.placeholder')}
53
66
  error={!!formState.errors.description}
@@ -55,11 +68,22 @@ export default function ProductForm(props: Props) {
55
68
  multiline
56
69
  minRows={2}
57
70
  maxRows={4}
71
+ inputProps={{ maxLength: 256 }}
58
72
  />
59
73
  <Collapse trigger={t('admin.product.additional')}>
60
74
  <Stack spacing={2} alignItems="flex-start">
61
- <FormInput name="statement_descriptor" label={t('admin.product.statement_descriptor.label')} />
62
- <FormInput name="unit_label" label={t('admin.product.unit_label.label')} />
75
+ <FormInput
76
+ name="statement_descriptor"
77
+ label={t('admin.product.statement_descriptor.label')}
78
+ rules={{ maxLength: { value: 32, message: t('common.maxLength', { len: 32 }) } }}
79
+ inputProps={{ maxLength: 32 }}
80
+ />
81
+ <FormInput
82
+ name="unit_label"
83
+ label={t('admin.product.unit_label.label')}
84
+ rules={{ maxLength: { value: 32, message: t('common.maxLength', { len: 32 }) } }}
85
+ inputProps={{ maxLength: 32 }}
86
+ />
63
87
  {!props.simple && <ProductFeatures />}
64
88
  {!props.simple && <MetadataForm title={t('common.metadata.label')} />}
65
89
  </Stack>
@@ -147,6 +147,16 @@ export default function SubscriptionCancelForm({ data }: { data: TSubscriptionEx
147
147
  symbol,
148
148
  })}
149
149
  />
150
+ <FormControlLabel
151
+ value="slash"
152
+ disabled={loading || !staking}
153
+ onClick={() => !(loading || !staking) && setValue('cancel.staking', 'slash')}
154
+ control={<Radio checked={stakingType === 'slash'} />}
155
+ label={t('admin.subscription.cancel.staking.slash', {
156
+ unused: formatAmount(staking?.return_amount || '0', decimal),
157
+ symbol,
158
+ })}
159
+ />
150
160
  </RadioGroup>
151
161
  </Stack>
152
162
  </>
@@ -1,4 +1,4 @@
1
- import { formatSubscriptionProduct, useMobile } from '@blocklet/payment-react';
1
+ import { formatSubscriptionProduct, TruncatedText, useMobile } from '@blocklet/payment-react';
2
2
  import type { TSubscriptionExpanded } from '@blocklet/payment-types';
3
3
  import { InfoOutlined } from '@mui/icons-material';
4
4
  import { Stack, Tooltip, Typography } from '@mui/material';
@@ -15,7 +15,7 @@ export default function SubscriptionDescription({ subscription, variant, hideSub
15
15
  return (
16
16
  <Stack direction="row" alignItems="center" spacing={1}>
17
17
  <Typography variant={variant} fontWeight={600} className="subscription-description">
18
- {subscription.description}
18
+ <TruncatedText text={subscription.description} maxLength={80} useWidth />
19
19
  </Typography>
20
20
  {!hideSubscription && !isMobile && (
21
21
  <Tooltip title={formatSubscriptionProduct(subscription.items)}>
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { formatPrice, Table } from '@blocklet/payment-react';
3
+ import { formatPrice, Table, TruncatedText, useMobile } from '@blocklet/payment-react';
4
4
  import type { TPaymentCurrency, TSubscriptionItemExpanded } from '@blocklet/payment-types';
5
5
  import { Avatar, Stack, Typography } from '@mui/material';
6
6
 
@@ -22,6 +22,7 @@ const size = { width: 48, height: 48 };
22
22
 
23
23
  export default function SubscriptionItemList({ data, currency, mode }: ListProps) {
24
24
  const { t } = useLocaleContext();
25
+ const { isMobile } = useMobile();
25
26
  const columns = [
26
27
  {
27
28
  label: t('admin.subscription.product'),
@@ -53,7 +54,7 @@ export default function SubscriptionItemList({ data, currency, mode }: ListProps
53
54
  </Avatar>
54
55
  )}
55
56
  <Typography color="text.primary" fontWeight={600}>
56
- {item?.price.product.name}
57
+ <TruncatedText text={item?.price.product.name} maxLength={isMobile ? 20 : 50} useWidth />
57
58
  {mode === 'customer' ? '' : ` - ${item?.price_id}`}
58
59
  </Typography>
59
60
  <Typography color="text.secondary" whiteSpace="nowrap">
@@ -11,7 +11,9 @@ export default function CustomerCancelForm({ data }: { data: TSubscriptionExpand
11
11
  return (
12
12
  <Stack direction="column" spacing={1} alignItems="flex-start">
13
13
  <Typography>
14
- {t('payment.customer.cancel.description', { date: formatTime(data.current_period_end * 1000) })}
14
+ {data.status === 'trialing'
15
+ ? t('payment.customer.cancel.trialDescription')
16
+ : t('payment.customer.cancel.description', { date: formatTime(data.current_period_end * 1000) })}
15
17
  </Typography>
16
18
  <Controller
17
19
  name="cancel.feedback"
@@ -66,6 +68,12 @@ export default function CustomerCancelForm({ data }: { data: TSubscriptionExpand
66
68
  <Controller
67
69
  name="cancel.comment"
68
70
  control={control}
71
+ rules={{
72
+ maxLength: {
73
+ value: 200,
74
+ message: t('common.maxLength', { len: 200 }),
75
+ },
76
+ }}
69
77
  render={({ field }) => (
70
78
  <TextField
71
79
  variant="outlined"
@@ -76,6 +84,9 @@ export default function CustomerCancelForm({ data }: { data: TSubscriptionExpand
76
84
  maxRows={4}
77
85
  placeholder={t('payment.customer.cancel.comment')}
78
86
  {...field}
87
+ inputProps={{
88
+ maxLength: 200,
89
+ }}
79
90
  />
80
91
  )}
81
92
  />
@@ -64,7 +64,7 @@ export default function CurrentSubscriptions({
64
64
 
65
65
  const showLoadingMore = useDelayedLoading(loadingMore);
66
66
 
67
- if (loading || !data) {
67
+ if (!data || loading) {
68
68
  return <CircularProgress />;
69
69
  }
70
70
 
@@ -75,12 +75,13 @@ export default function CurrentSubscriptions({
75
75
  <Stack direction="column" spacing={2} sx={{ mt: 2 }}>
76
76
  {data.list?.length > 0 ? (
77
77
  <>
78
- <Box
78
+ <Stack
79
79
  ref={listRef}
80
+ spacing={2}
80
81
  sx={{
81
82
  maxHeight: {
82
83
  xs: '100%',
83
- md: '450px',
84
+ md: '500px',
84
85
  },
85
86
  overflowY: 'auto',
86
87
  }}>
@@ -98,7 +99,7 @@ export default function CurrentSubscriptions({
98
99
  padding: 1.5,
99
100
  background: 'var(--backgrounds-bg-subtle, #F9FAFB)',
100
101
  '&:hover': {
101
- backgroundColor: 'grey.50',
102
+ backgroundColor: 'var(--backgrounds-bg-highlight, #eff6ff)',
102
103
  transition: 'background-color 200ms linear',
103
104
  cursor: 'pointer',
104
105
  },
@@ -215,7 +216,7 @@ export default function CurrentSubscriptions({
215
216
  {t('common.loadingMore', { resource: t('admin.subscriptions') })}
216
217
  </Box>
217
218
  )}
218
- </Box>
219
+ </Stack>
219
220
  {isMobile && (
220
221
  <Box>
221
222
  {hasMore && (
@@ -16,6 +16,9 @@ export default flat({
16
16
  add: 'Add',
17
17
  fullscreen: 'Fullscreen',
18
18
  exit: 'Exit',
19
+ maxLength: 'Max {len} characters',
20
+ minLength: 'Min {len} characters',
21
+ loading: 'Loading...',
19
22
  },
20
23
  admin: {
21
24
  balances: 'Balances',
@@ -459,8 +462,9 @@ export default flat({
459
462
  },
460
463
  staking: {
461
464
  title: 'Stake',
462
- none: 'No return',
465
+ none: 'No return or slash',
463
466
  proration: 'Return Remaining Stake {unused}{symbol}',
467
+ slash: 'Slash Remaining Stake {unused}{symbol}',
464
468
  },
465
469
  },
466
470
  pause: {
@@ -592,6 +596,7 @@ export default flat({
592
596
  payments: 'No Payments',
593
597
  prices: 'No Prices',
594
598
  pricing: 'You haven’t added any prices you can add it',
599
+ summary: 'No Summary',
595
600
  },
596
601
  customer: {
597
602
  subscription: {
@@ -16,6 +16,9 @@ export default flat({
16
16
  add: '添加',
17
17
  fullscreen: '全屏',
18
18
  exit: '退出',
19
+ maxLength: '最多输入{len}个字符',
20
+ minLength: '最少输入{len}个字符',
21
+ loading: '加载中...',
19
22
  },
20
23
  admin: {
21
24
  balances: '余额',
@@ -450,8 +453,9 @@ export default flat({
450
453
  },
451
454
  staking: {
452
455
  title: '质押',
453
- none: '不退还质押',
456
+ none: '不退还 / 罚没质押',
454
457
  proration: '退还剩余部分 {unused}{symbol}',
458
+ slash: '罚没剩余部分 {unused}{symbol}',
455
459
  },
456
460
  },
457
461
  pause: {
@@ -582,6 +586,7 @@ export default flat({
582
586
  payments: '没有付款记录',
583
587
  prices: '没有价格',
584
588
  pricing: '您还没有设置定价,您可以添加它',
589
+ summary: '没有摘要',
585
590
  },
586
591
  customer: {
587
592
  subscription: {
@@ -88,6 +88,17 @@ export default function InvoiceDetail(props: { id: string }) {
88
88
  const handleEditMetadata = () => {
89
89
  setState((prev) => ({ editing: { ...prev.editing, metadata: true } }));
90
90
  };
91
+
92
+ const getDescription = (description: string) => {
93
+ let desc = description;
94
+ if (desc.startsWith('Slash stake')) {
95
+ desc = t('payment.invoice.reason.slashStake');
96
+ }
97
+ if (desc.startsWith('Subscription ')) {
98
+ desc = t(`payment.invoice.reason.${desc.replace('Subscription ', '')}`);
99
+ }
100
+ return desc;
101
+ };
91
102
  return (
92
103
  <Root direction="column" spacing={2.5} sx={{ mb: 4 }}>
93
104
  <Box>
@@ -215,6 +226,10 @@ export default function InvoiceDetail(props: { id: string }) {
215
226
  md: 'repeat(2, 1fr)',
216
227
  lg: 'repeat(3, 1fr)',
217
228
  },
229
+ gap: {
230
+ xs: 0,
231
+ md: 2,
232
+ },
218
233
  }}>
219
234
  <InfoRow
220
235
  label={t('admin.invoice.number')}
@@ -224,7 +239,7 @@ export default function InvoiceDetail(props: { id: string }) {
224
239
  />
225
240
  <InfoRow
226
241
  label={t('admin.invoice.description')}
227
- value={data.description}
242
+ value={getDescription(data.description || '')}
228
243
  direction={InfoDirection}
229
244
  alignItems={InfoAlignItems}
230
245
  />
@@ -325,7 +340,7 @@ export default function InvoiceDetail(props: { id: string }) {
325
340
  <Box className="section">
326
341
  <SectionHeader title={t('admin.summary')} />
327
342
  <Box className="section-body">
328
- <InvoiceTable invoice={data} />
343
+ <InvoiceTable invoice={data} emptyNodeText={t('empty.summary')} />
329
344
  </Box>
330
345
  </Box>
331
346
  <Divider />
@@ -202,6 +202,10 @@ export default function SubscriptionDetail(props: { id: string }) {
202
202
  md: 'repeat(2, 1fr)',
203
203
  lg: 'repeat(3, 1fr)',
204
204
  },
205
+ gap: {
206
+ xs: 0,
207
+ md: 2,
208
+ },
205
209
  }}>
206
210
  <InfoRow
207
211
  label={t('common.customer')}
@@ -283,6 +283,10 @@ export default function CustomerDetail(props: { id: string }) {
283
283
  md: 'repeat(2, 1fr)',
284
284
  lg: 'repeat(3, 1fr)',
285
285
  },
286
+ gap: {
287
+ xs: 0,
288
+ md: 2,
289
+ },
286
290
  }}>
287
291
  <InfoRow
288
292
  label={t('admin.customer.name')}
@@ -112,7 +112,7 @@ export default function CustomersList() {
112
112
  sort: true,
113
113
  customBodyRenderLite: (_: string, index: number) => {
114
114
  const item = data.list[index] as TCustomer;
115
- return <Link to={`/admin/customers/${item.id}`}>{formatTime(item.updated_at)}</Link>;
115
+ return <Link to={`/admin/customers/${item.id}`}>{formatTime(item.created_at)}</Link>;
116
116
  },
117
117
  },
118
118
  },
@@ -219,6 +219,10 @@ export default function PaymentIntentDetail(props: { id: string }) {
219
219
  md: 'repeat(2, 1fr)',
220
220
  lg: 'repeat(3, 1fr)',
221
221
  },
222
+ gap: {
223
+ xs: 0,
224
+ md: 2,
225
+ },
222
226
  }}>
223
227
  <InfoRow label={t('common.amount')} value={total} direction={InfoDirection} alignItems={InfoAlignItems} />
224
228
  <InfoRow
@@ -216,6 +216,10 @@ export default function PayoutDetail(props: { id: string }) {
216
216
  md: 'repeat(2, 1fr)',
217
217
  lg: 'repeat(3, 1fr)',
218
218
  },
219
+ gap: {
220
+ xs: 0,
221
+ md: 2,
222
+ },
219
223
  }}>
220
224
  <InfoRow label={t('common.amount')} value={total} direction={InfoDirection} alignItems={InfoAlignItems} />
221
225
  <InfoRow
@@ -218,6 +218,10 @@ export default function RefundDetail(props: { id: string }) {
218
218
  md: 'repeat(2, 1fr)',
219
219
  lg: 'repeat(3, 1fr)',
220
220
  },
221
+ gap: {
222
+ xs: 0,
223
+ md: 2,
224
+ },
221
225
  }}>
222
226
  <InfoRow
223
227
  label={t('common.amount')}
@@ -298,6 +298,10 @@ export default function PaymentLinkDetail(props: { id: string }) {
298
298
  md: 'repeat(2, 1fr)',
299
299
  lg: 'repeat(3, 1fr)',
300
300
  },
301
+ gap: {
302
+ xs: 0,
303
+ md: 2,
304
+ },
301
305
  }}>
302
306
  <InfoRow
303
307
  sizes={[1, 1]}
@@ -223,6 +223,10 @@ export default function PriceDetail(props: { id: string }) {
223
223
  md: 'repeat(2, 1fr)',
224
224
  lg: 'repeat(3, 1fr)',
225
225
  },
226
+ gap: {
227
+ xs: 0,
228
+ md: 2,
229
+ },
226
230
  }}>
227
231
  <InfoRow
228
232
  label={t('admin.price.type')}
@@ -263,6 +263,10 @@ export default function PricingTableDetail(props: { id: string }) {
263
263
  md: 'repeat(2, 1fr)',
264
264
  lg: 'repeat(3, 1fr)',
265
265
  },
266
+ gap: {
267
+ xs: 0,
268
+ md: 2,
269
+ },
266
270
  }}>
267
271
  <InfoRow
268
272
  sizes={[1, 1]}
@@ -260,6 +260,10 @@ export default function ProductDetail(props: { id: string }) {
260
260
  md: 'repeat(2, 1fr)',
261
261
  lg: 'repeat(3, 1fr)',
262
262
  },
263
+ gap: {
264
+ xs: 0,
265
+ md: 2,
266
+ },
263
267
  }}>
264
268
  <InfoRow
265
269
  label={t('admin.product.name.label')}
@@ -1,4 +1,3 @@
1
- import Center from '@arcblock/ux/lib/Center';
2
1
  import { CheckoutTable } from '@blocklet/payment-react';
3
2
  import Header from '@blocklet/ui-react/lib/Header';
4
3
  import { Box } from '@mui/material';
@@ -26,9 +25,16 @@ export default function PricingTablePage({ id }: Props) {
26
25
  hideNavMenu={undefined}
27
26
  maxWidth={false}
28
27
  />
29
- <Center relative="parent">
28
+
29
+ <Box
30
+ sx={{
31
+ pt: {
32
+ xs: 0,
33
+ md: '60px',
34
+ },
35
+ }}>
30
36
  <CheckoutTable id={id} mode="standalone" />
31
- </Center>
37
+ </Box>
32
38
  </Box>
33
39
  );
34
40
  }
@@ -6,6 +6,7 @@ import {
6
6
  formatBNStr,
7
7
  formatError,
8
8
  getPrefix,
9
+ TruncatedText,
9
10
  useMobile,
10
11
  usePaymentContext,
11
12
  } from '@blocklet/payment-react';
@@ -91,6 +92,7 @@ export default function CustomerHome() {
91
92
  const { events } = useSessionContext();
92
93
  const { settings } = usePaymentContext();
93
94
  const [currency, setCurrency] = useState(settings?.baseCurrency);
95
+ const [subscriptionLoading, setSubscriptionLoading] = useState(false);
94
96
  const currencies = flatten(settings.paymentMethods.map((method) => method.payment_currencies));
95
97
 
96
98
  const { livemode, setLivemode } = usePaymentContext();
@@ -151,7 +153,11 @@ export default function CustomerHome() {
151
153
  };
152
154
 
153
155
  const onToggleActive = (e: SelectChangeEvent) => {
156
+ setSubscriptionLoading(true);
154
157
  setState({ onlyActive: e.target.value === 'active' });
158
+ setTimeout(() => {
159
+ setSubscriptionLoading(false);
160
+ }, 300);
155
161
  };
156
162
 
157
163
  const handleCurrencyChange = (e: SelectChangeEvent) => {
@@ -185,20 +191,24 @@ export default function CustomerHome() {
185
191
  </FormControl>
186
192
  </Box>
187
193
  <Box className="section-body">
188
- <CurrentSubscriptions
189
- id={data.id}
190
- onlyActive={state.onlyActive}
191
- changeActive={(v) => setState({ onlyActive: v })}
192
- status={state.onlyActive ? 'active,trialing' : 'active,trialing,paused,past_due,canceled'}
193
- style={{
194
- cursor: 'pointer',
195
- }}
196
- onClickSubscription={(subscription) => {
197
- startTransition(() => {
198
- navigate(`/customer/subscription/${subscription.id}`);
199
- });
200
- }}
201
- />
194
+ {subscriptionLoading ? (
195
+ <Box>{t('common.loading')}</Box>
196
+ ) : (
197
+ <CurrentSubscriptions
198
+ id={data.id}
199
+ onlyActive={state.onlyActive}
200
+ changeActive={(v) => setState({ onlyActive: v })}
201
+ status={state.onlyActive ? 'active,trialing' : 'active,trialing,paused,past_due,canceled'}
202
+ style={{
203
+ cursor: 'pointer',
204
+ }}
205
+ onClickSubscription={(subscription) => {
206
+ startTransition(() => {
207
+ navigate(`/customer/subscription/${subscription.id}`);
208
+ });
209
+ }}
210
+ />
211
+ )}
202
212
  </Box>
203
213
  </Box>
204
214
  );
@@ -380,21 +390,22 @@ export default function CustomerHome() {
380
390
  />
381
391
  <InfoRow
382
392
  label={t('admin.customer.address.city')}
383
- value={data.address?.city}
393
+ value={<TruncatedText text={data.address?.city} maxLength={280} useWidth />}
394
+ // value={data.address?.city}
384
395
  sizes={[1, 1]}
385
396
  alignItems="normal"
386
397
  direction="column"
387
398
  />
388
399
  <InfoRow
389
400
  label={t('admin.customer.address.line1')}
390
- value={data.address?.line1}
401
+ value={<TruncatedText text={data.address?.line1} maxLength={280} useWidth />}
391
402
  sizes={[1, 1]}
392
403
  alignItems="normal"
393
404
  direction="column"
394
405
  />
395
406
  <InfoRow
396
407
  label={t('admin.customer.address.line2')}
397
- value={data.address?.line2}
408
+ value={<TruncatedText text={data.address?.line2} maxLength={280} useWidth />}
398
409
  sizes={[1, 1]}
399
410
  alignItems="normal"
400
411
  direction="column"
@@ -101,6 +101,9 @@ export default function CustomerInvoiceDetail() {
101
101
  return <CircularProgress />;
102
102
  }
103
103
 
104
+ const isSlash =
105
+ data.paymentMethod?.type === 'arcblock' && data.paymentIntent?.payment_details?.arcblock?.type === 'slash';
106
+
104
107
  return (
105
108
  <InvoiceDetailRoot direction="column" spacing={3} sx={{ my: 2 }}>
106
109
  <Stack direction="row" justifyContent="space-between">
@@ -209,6 +212,10 @@ export default function CustomerInvoiceDetail() {
209
212
  md: 'repeat(2, 1fr)',
210
213
  lg: 'repeat(3, 1fr)',
211
214
  },
215
+ gap: {
216
+ xs: 0,
217
+ md: 2,
218
+ },
212
219
  }}>
213
220
  <InfoRow
214
221
  label={t('admin.invoice.description')}
@@ -282,22 +289,26 @@ export default function CustomerInvoiceDetail() {
282
289
  )}
283
290
  </Stack>
284
291
  </Box>
285
- <Divider />
286
- <Box className="section">
287
- <Typography variant="h3" mb={1.5} className="section-header">
288
- {t('payment.customer.products')}
289
- </Typography>
290
- <InvoiceTable invoice={data} simple />
291
- </Box>
292
- <Divider />
293
- <Box className="section">
294
- <Typography variant="h3" className="section-header">
295
- {t('admin.refunds')}
296
- </Typography>
297
- <Box className="section-body">
298
- <CustomerRefundList invoice_id={data.id} type="table" />
299
- </Box>
300
- </Box>
292
+ {!isSlash && (
293
+ <>
294
+ <Divider />
295
+ <Box className="section">
296
+ <Typography variant="h3" mb={1.5} className="section-header">
297
+ {t('payment.customer.products')}
298
+ </Typography>
299
+ <InvoiceTable invoice={data} simple />
300
+ </Box>
301
+ <Divider />
302
+ <Box className="section">
303
+ <Typography variant="h3" className="section-header">
304
+ {t('admin.refunds')}
305
+ </Typography>
306
+ <Box className="section-body">
307
+ <CustomerRefundList invoice_id={data.id} type="table" />
308
+ </Box>
309
+ </Box>
310
+ </>
311
+ )}
301
312
  </InvoiceDetailRoot>
302
313
  );
303
314
  }
@@ -72,7 +72,7 @@ export default function CustomerInvoicePastDue() {
72
72
  };
73
73
 
74
74
  return (
75
- <Stack direction="column" spacing={3} sx={{ my: 2, maxWidth: '960px' }}>
75
+ <Stack direction="column" spacing={3} sx={{ my: 2 }}>
76
76
  <Stack direction="row" alignItems="center" justifyContent="space-between">
77
77
  <Stack
78
78
  direction="row"
@@ -100,10 +100,11 @@ export default function CustomerInvoicePastDue() {
100
100
  customer_id={data.id}
101
101
  subscription_id={subscriptionId}
102
102
  currency_id={currencyId}
103
- pageSize={100}
103
+ pageSize={10}
104
104
  status="uncollectible"
105
105
  target="_blank"
106
106
  action="pay"
107
+ type="table"
107
108
  />
108
109
  </Box>
109
110
  </Box>