payment-kit 1.14.25 → 1.14.26

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/blocklet.yml +1 -1
  2. package/package.json +4 -4
  3. package/src/components/event/list.tsx +35 -24
  4. package/src/components/filter-toolbar.tsx +15 -10
  5. package/src/components/info-metric.tsx +10 -2
  6. package/src/components/info-row.tsx +2 -1
  7. package/src/components/invoice/list.tsx +11 -3
  8. package/src/components/metadata/editor.tsx +1 -0
  9. package/src/components/metadata/form.tsx +12 -3
  10. package/src/components/payment-currency/form.tsx +4 -0
  11. package/src/components/payment-intent/list.tsx +11 -2
  12. package/src/components/payment-link/before-pay.tsx +25 -2
  13. package/src/components/payment-method/arcblock.tsx +4 -0
  14. package/src/components/payment-method/bitcoin.tsx +4 -0
  15. package/src/components/payment-method/ethereum.tsx +4 -0
  16. package/src/components/payouts/list.tsx +12 -2
  17. package/src/components/pricing-table/price-item.tsx +18 -4
  18. package/src/components/product/actions.tsx +6 -3
  19. package/src/components/refund/list.tsx +11 -3
  20. package/src/components/subscription/description.tsx +3 -2
  21. package/src/components/subscription/list.tsx +3 -2
  22. package/src/components/uploader.tsx +65 -28
  23. package/src/components/webhook/attempts.tsx +40 -33
  24. package/src/libs/util.ts +8 -1
  25. package/src/locales/en.tsx +2 -0
  26. package/src/locales/zh.tsx +2 -0
  27. package/src/pages/admin/billing/index.tsx +3 -0
  28. package/src/pages/admin/billing/invoices/detail.tsx +10 -5
  29. package/src/pages/admin/billing/subscriptions/detail.tsx +10 -5
  30. package/src/pages/admin/customers/customers/detail.tsx +11 -6
  31. package/src/pages/admin/customers/index.tsx +3 -0
  32. package/src/pages/admin/developers/events/detail.tsx +47 -8
  33. package/src/pages/admin/index.tsx +4 -1
  34. package/src/pages/admin/payments/index.tsx +3 -0
  35. package/src/pages/admin/payments/intents/detail.tsx +10 -4
  36. package/src/pages/admin/payments/payouts/detail.tsx +10 -4
  37. package/src/pages/admin/payments/refunds/detail.tsx +10 -4
  38. package/src/pages/admin/products/index.tsx +3 -0
  39. package/src/pages/admin/products/passports/index.tsx +1 -1
  40. package/src/pages/admin/products/prices/detail.tsx +10 -5
  41. package/src/pages/admin/products/products/detail.tsx +18 -11
  42. package/src/pages/admin/settings/index.tsx +3 -0
  43. package/src/pages/customer/subscription/embed.tsx +3 -2
package/blocklet.yml CHANGED
@@ -14,7 +14,7 @@ repository:
14
14
  type: git
15
15
  url: git+https://github.com/blocklet/payment-kit.git
16
16
  specVersion: 1.2.8
17
- version: 1.14.25
17
+ version: 1.14.26
18
18
  logo: logo.png
19
19
  files:
20
20
  - dist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.14.25",
3
+ "version": "1.14.26",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "eject": "vite eject",
@@ -52,7 +52,7 @@
52
52
  "@arcblock/validator": "^1.18.128",
53
53
  "@blocklet/js-sdk": "1.16.28",
54
54
  "@blocklet/logger": "1.16.28",
55
- "@blocklet/payment-react": "1.14.25",
55
+ "@blocklet/payment-react": "1.14.26",
56
56
  "@blocklet/sdk": "1.16.28",
57
57
  "@blocklet/ui-react": "^2.10.16",
58
58
  "@blocklet/uploader": "^0.1.20",
@@ -118,7 +118,7 @@
118
118
  "devDependencies": {
119
119
  "@abtnode/types": "1.16.28",
120
120
  "@arcblock/eslint-config-ts": "^0.3.2",
121
- "@blocklet/payment-types": "1.14.25",
121
+ "@blocklet/payment-types": "1.14.26",
122
122
  "@types/cookie-parser": "^1.4.7",
123
123
  "@types/cors": "^2.8.17",
124
124
  "@types/debug": "^4.1.12",
@@ -160,5 +160,5 @@
160
160
  "parser": "typescript"
161
161
  }
162
162
  },
163
- "gitHead": "d326f7f50aeb5a0b727b1eb1f5b042f82e2e4059"
163
+ "gitHead": "bda6ee657434e48075cebe406a68c4ed67721281"
164
164
  }
@@ -1,13 +1,14 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { getDurableData } from '@arcblock/ux/lib/Datatable';
3
3
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
- import { api, formatTime, Table } from '@blocklet/payment-react';
4
+ import { api, formatTime, Table, useDefaultPageSize } from '@blocklet/payment-react';
5
5
  import type { TEventExpanded } from '@blocklet/payment-types';
6
- import { Alert, CircularProgress, Typography } from '@mui/material';
6
+ import { Alert, Box, CircularProgress, Typography } from '@mui/material';
7
7
  import { useRequest } from 'ahooks';
8
8
  import { useEffect, useState } from 'react';
9
9
  import { useNavigate } from 'react-router-dom';
10
10
 
11
+ import { styled } from '@mui/system';
11
12
  import { useTransitionContext } from '../progress-bar';
12
13
 
13
14
  const fetchData = (params: Record<string, any> = {}): Promise<{ list: TEventExpanded[]; count: number }> => {
@@ -132,11 +133,12 @@ export default function EventList({ type, object_id, features }: ListProps) {
132
133
  const persisted = getDurableData(listKey);
133
134
 
134
135
  const { t } = useLocaleContext();
136
+ const defaultPageSize = useDefaultPageSize(persisted.rowsPerPage || 50);
135
137
  const navigate = useNavigate();
136
138
  const [search, setSearch] = useState<SearchProps>({
137
139
  type,
138
140
  object_id,
139
- pageSize: persisted.rowsPerPage || 50,
141
+ pageSize: defaultPageSize,
140
142
  page: persisted.page ? persisted.page + 1 : 1,
141
143
  });
142
144
  const { startTransition } = useTransitionContext();
@@ -194,26 +196,35 @@ export default function EventList({ type, object_id, features }: ListProps) {
194
196
  };
195
197
 
196
198
  return (
197
- <Table
198
- durable={listKey}
199
- durableKeys={['page', 'rowsPerPage']}
200
- data={data.list}
201
- columns={columns}
202
- loading={loading}
203
- onChange={onTableChange}
204
- options={{
205
- count: data.count,
206
- page: search.page - 1,
207
- rowsPerPage: search.pageSize,
208
- onRowClick: (_: any, { dataIndex }: any) => {
209
- const item = data.list[dataIndex] as TEventExpanded;
210
- startTransition(() => {
211
- navigate(`/admin/developers/${item.id}`);
212
- });
213
- },
214
- }}
215
- toolbar={features?.toolbar}
216
- emptyNodeText={t('empty.events')}
217
- />
199
+ <Root>
200
+ <Table
201
+ hasRowLink
202
+ durable={listKey}
203
+ durableKeys={['page', 'rowsPerPage']}
204
+ data={data.list}
205
+ columns={columns}
206
+ loading={loading}
207
+ onChange={onTableChange}
208
+ options={{
209
+ count: data.count,
210
+ page: search.page - 1,
211
+ rowsPerPage: search.pageSize,
212
+ onRowClick: (_: any, { dataIndex }: any) => {
213
+ const item = data.list[dataIndex] as TEventExpanded;
214
+ startTransition(() => {
215
+ navigate(`/admin/developers/${item.id}`);
216
+ });
217
+ },
218
+ }}
219
+ toolbar={features?.toolbar}
220
+ emptyNodeText={t('empty.events')}
221
+ />
222
+ </Root>
218
223
  );
219
224
  }
225
+
226
+ const Root = styled(Box)`
227
+ td {
228
+ cursor: pointer;
229
+ }
230
+ `;
@@ -1,5 +1,5 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
- import { api, usePaymentContext } from '@blocklet/payment-react';
2
+ import { api, useMobile, usePaymentContext } from '@blocklet/payment-react';
3
3
  import type { TCustomer } from '@blocklet/payment-types';
4
4
  import { Add, Close } from '@mui/icons-material';
5
5
  import { Button, ClickAwayListener, Menu, MenuItem } from '@mui/material';
@@ -44,6 +44,7 @@ type Props = {
44
44
 
45
45
  export default function FilterToolbar(props: Props) {
46
46
  const { setSearch, search, status, currency, donation, formatStatus = (v) => v } = props;
47
+ const { isMobile } = useMobile();
47
48
  const isProduct = window.location.pathname.includes('product');
48
49
  const handleSearch = (obj: any) => {
49
50
  setSearch({
@@ -56,16 +57,20 @@ export default function FilterToolbar(props: Props) {
56
57
  <Root>
57
58
  <Box className="table-toolbar-left">
58
59
  <SearchStatus setSearch={handleSearch} search={search} status={status} formatStatus={formatStatus} />
59
- {Array.isArray(donation) && donation.length > 0 && (
60
- <SearchDonation setSearch={handleSearch} search={search} donation={donation} />
61
- )}
62
- {isProduct ? null : (
60
+ {!isMobile && (
63
61
  <>
64
- <SearchCustomers search={search} setSearch={handleSearch} />
65
- {currency ? (
66
- <SearchCurrency search={search} setSearch={handleSearch} />
67
- ) : (
68
- <SearchProducts search={search} setSearch={handleSearch} />
62
+ {Array.isArray(donation) && donation.length > 0 && (
63
+ <SearchDonation setSearch={handleSearch} search={search} donation={donation} />
64
+ )}
65
+ {isProduct ? null : (
66
+ <>
67
+ <SearchCustomers search={search} setSearch={handleSearch} />
68
+ {currency ? (
69
+ <SearchCurrency search={search} setSearch={handleSearch} />
70
+ ) : (
71
+ <SearchProducts search={search} setSearch={handleSearch} />
72
+ )}
73
+ </>
69
74
  )}
70
75
  </>
71
76
  )}
@@ -1,5 +1,7 @@
1
1
  import { InfoOutlined } from '@mui/icons-material';
2
2
  import { Divider, Stack, Tooltip, Typography } from '@mui/material';
3
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
+ import { isEmptyExceptNumber } from '../libs/util';
3
5
 
4
6
  type Props = {
5
7
  label: string | React.ReactNode;
@@ -9,6 +11,8 @@ type Props = {
9
11
  };
10
12
 
11
13
  export default function InfoMetric(props: Props) {
14
+ const { t } = useLocaleContext();
15
+ const isNone = isEmptyExceptNumber(props.value);
12
16
  return (
13
17
  <>
14
18
  <Stack direction="column" alignItems="flex-start">
@@ -20,8 +24,12 @@ export default function InfoMetric(props: Props) {
20
24
  </Tooltip>
21
25
  )}
22
26
  </Typography>
23
- <Typography component="div" variant="body1" color="text.secondary" sx={{ width: '100%' }}>
24
- {props.value}
27
+ <Typography
28
+ component="div"
29
+ variant="body1"
30
+ color={isNone ? 'text.disabled' : 'text.secondary'}
31
+ sx={{ width: '100%', minHeight: '24px' }}>
32
+ {isNone ? t('common.none') : props.value}
25
33
  </Typography>
26
34
  </Stack>
27
35
  {props.divider && <Divider orientation="vertical" flexItem />}
@@ -1,6 +1,7 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import { Box, Stack, SxProps } from '@mui/material';
3
3
  import type { ReactNode } from 'react';
4
+ import { isEmptyExceptNumber } from '../libs/util';
4
5
 
5
6
  type Props = {
6
7
  label: string | ReactNode;
@@ -21,7 +22,7 @@ InfoRow.defaultProps = {
21
22
 
22
23
  export default function InfoRow(props: Props) {
23
24
  const { t } = useLocaleContext();
24
- const isNone = props.value === '' || typeof props.value === 'undefined';
25
+ const isNone = isEmptyExceptNumber(props.value);
25
26
  const sizes = props.sizes || [1, 3];
26
27
  return (
27
28
  <Stack
@@ -1,12 +1,19 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { Status, api, formatBNStr, formatTime, getInvoiceStatusColor, Table } from '@blocklet/payment-react';
3
+ import {
4
+ Status,
5
+ api,
6
+ formatBNStr,
7
+ formatTime,
8
+ getInvoiceStatusColor,
9
+ Table,
10
+ useDefaultPageSize,
11
+ } from '@blocklet/payment-react';
4
12
  import type { TInvoiceExpanded } from '@blocklet/payment-types';
5
13
  import { CircularProgress, Typography } from '@mui/material';
6
14
  import { useLocalStorageState } from 'ahooks';
7
15
  import { useEffect, useState } from 'react';
8
16
  import { Link } from 'react-router-dom';
9
-
10
17
  import CustomerLink from '../customer/link';
11
18
  import FilterToolbar from '../filter-toolbar';
12
19
  import InvoiceActions from './action';
@@ -88,6 +95,7 @@ export default function InvoiceList({
88
95
  const listKey = getListKey({ customer_id, subscription_id });
89
96
 
90
97
  const { t } = useLocaleContext();
98
+ const defaultPageSize = useDefaultPageSize(20);
91
99
  const [search, setSearch] = useLocalStorageState<SearchProps & { ignore_zero?: boolean; include_staking?: boolean }>(
92
100
  listKey,
93
101
  {
@@ -95,7 +103,7 @@ export default function InvoiceList({
95
103
  status: status as string,
96
104
  customer_id,
97
105
  subscription_id,
98
- pageSize: 20,
106
+ pageSize: defaultPageSize,
99
107
  page: 1,
100
108
  ignore_zero: !!ignore_zero,
101
109
  include_staking: !!include_staking,
@@ -70,6 +70,7 @@ export default function MetadataEditor({
70
70
  </Button>
71
71
  </Stack>
72
72
  }
73
+ minHeight="400px"
73
74
  />
74
75
  </FormProvider>
75
76
  </Dialog>
@@ -5,7 +5,15 @@ import { Box, Button, Divider, IconButton, Stack, Typography } from '@mui/materi
5
5
  import { useEffect, useRef } from 'react';
6
6
  import { useFieldArray, useFormContext } from 'react-hook-form';
7
7
 
8
- export default function MetadataForm({ title, actions }: { title?: string; actions?: React.ReactNode }) {
8
+ export default function MetadataForm({
9
+ title,
10
+ actions,
11
+ minHeight = 'auto',
12
+ }: {
13
+ title?: string;
14
+ actions?: React.ReactNode;
15
+ minHeight?: string;
16
+ }) {
9
17
  const { t } = useLocaleContext();
10
18
  const {
11
19
  control,
@@ -38,11 +46,11 @@ export default function MetadataForm({ title, actions }: { title?: string; actio
38
46
  {!!title && <Typography>{title}</Typography>}
39
47
  <Stack
40
48
  sx={{
41
- height: {
49
+ maxHeight: {
42
50
  xs: 'calc(100vh - 130px)',
43
51
  md: 400,
44
52
  },
45
- minHeight: 400,
53
+ minHeight,
46
54
  overflow: 'auto',
47
55
  pb: 1.5,
48
56
  mr: -1.5,
@@ -105,4 +113,5 @@ export default function MetadataForm({ title, actions }: { title?: string; actio
105
113
  MetadataForm.defaultProps = {
106
114
  title: true,
107
115
  actions: null,
116
+ minHeight: 'auto',
108
117
  };
@@ -12,6 +12,10 @@ export default function PaymentCurrencyForm() {
12
12
  const logo = useWatch({ control, name: 'logo' });
13
13
 
14
14
  const onUploaded = (result: any) => {
15
+ if (!result.url) {
16
+ setValue('logo', '');
17
+ return;
18
+ }
15
19
  const tmp = new URL(result.url);
16
20
  setValue('logo', tmp.pathname);
17
21
  };
@@ -1,6 +1,14 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { Status, api, formatBNStr, formatTime, getPaymentIntentStatusColor, Table } from '@blocklet/payment-react';
3
+ import {
4
+ Status,
5
+ api,
6
+ formatBNStr,
7
+ formatTime,
8
+ getPaymentIntentStatusColor,
9
+ Table,
10
+ useDefaultPageSize,
11
+ } from '@blocklet/payment-react';
4
12
  import type { TPaymentIntentExpanded } from '@blocklet/payment-types';
5
13
  import { CircularProgress, Typography } from '@mui/material';
6
14
  import { useLocalStorageState } from 'ahooks';
@@ -71,12 +79,13 @@ export default function PaymentList({ customer_id, invoice_id, features }: ListP
71
79
  const { t } = useLocaleContext();
72
80
 
73
81
  const listKey = getListKey({ customer_id, invoice_id });
82
+ const defaultPageSize = useDefaultPageSize(20);
74
83
  const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
75
84
  defaultValue: {
76
85
  status: '',
77
86
  customer_id,
78
87
  invoice_id,
79
- pageSize: 20,
88
+ pageSize: defaultPageSize,
80
89
  page: 1,
81
90
  },
82
91
  });
@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
5
5
  import { Controller, useFieldArray, useFormContext, useWatch } from 'react-hook-form';
6
6
  import { useSearchParams } from 'react-router-dom';
7
7
 
8
+ import { get } from 'lodash';
8
9
  import { useProductsContext } from '../../contexts/products';
9
10
  import { getProductByPriceId, isPriceAligned } from '../../libs/util';
10
11
  import CreateProduct from '../product/create';
@@ -15,7 +16,12 @@ export default function BeforePay() {
15
16
  const { t } = useLocaleContext();
16
17
  const [params, setParams] = useSearchParams();
17
18
  const { products, refresh } = useProductsContext();
18
- const { control, setValue, getValues } = useFormContext();
19
+ const {
20
+ control,
21
+ setValue,
22
+ getValues,
23
+ formState: { errors },
24
+ } = useFormContext();
19
25
  const items = useFieldArray({ control, name: 'line_items' });
20
26
  const includeFreeTrial = useWatch({ control, name: 'include_free_trial' });
21
27
  const [state, setState] = useState({ creating: false });
@@ -199,7 +205,24 @@ export default function BeforePay() {
199
205
  <Controller
200
206
  name="subscription_data.trial_period_days"
201
207
  control={control}
202
- render={({ field }) => <TextField {...field} size="small" InputProps={{ endAdornment: t('common.days') }} />}
208
+ rules={{
209
+ required: t('payment.checkout.required'),
210
+ validate: (val) => {
211
+ if (val <= 0) {
212
+ return t('admin.paymentLink.freeTrialDaysPositive');
213
+ }
214
+ return true;
215
+ },
216
+ }}
217
+ render={({ field }) => (
218
+ <TextField
219
+ {...field}
220
+ size="small"
221
+ InputProps={{ endAdornment: t('common.days') }}
222
+ helperText={get(errors, 'subscription_data.trial_period_days')?.message as string}
223
+ error={!!get(errors, 'subscription_data.trial_period_days')}
224
+ />
225
+ )}
203
226
  />
204
227
  )}
205
228
  </Stack>
@@ -12,6 +12,10 @@ export default function ArcBlockMethodForm() {
12
12
  const logo = useWatch({ control, name: 'logo' });
13
13
 
14
14
  const onUploaded = (result: any) => {
15
+ if (!result.url) {
16
+ setValue('logo', '');
17
+ return;
18
+ }
15
19
  const tmp = new URL(result.url);
16
20
  setValue('logo', tmp.pathname);
17
21
  };
@@ -12,6 +12,10 @@ export default function BitcoinMethodForm() {
12
12
  const logo = useWatch({ control, name: 'logo' });
13
13
 
14
14
  const onUploaded = (result: any) => {
15
+ if (!result.url) {
16
+ setValue('logo', '');
17
+ return;
18
+ }
15
19
  const tmp = new URL(result.url);
16
20
  setValue('logo', tmp.pathname);
17
21
  };
@@ -12,6 +12,10 @@ export default function EthereumMethodForm() {
12
12
  const logo = useWatch({ control, name: 'logo' });
13
13
 
14
14
  const onUploaded = (result: any) => {
15
+ if (!result.url) {
16
+ setValue('logo', '');
17
+ return;
18
+ }
15
19
  const tmp = new URL(result.url);
16
20
  setValue('logo', tmp.pathname);
17
21
  };
@@ -1,6 +1,14 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { Status, api, formatBNStr, formatTime, getPayoutStatusColor, Table } from '@blocklet/payment-react';
3
+ import {
4
+ Status,
5
+ api,
6
+ formatBNStr,
7
+ formatTime,
8
+ getPayoutStatusColor,
9
+ Table,
10
+ useDefaultPageSize,
11
+ } from '@blocklet/payment-react';
4
12
  import type { TPayoutExpanded } from '@blocklet/payment-types';
5
13
  import { CircularProgress, Typography } from '@mui/material';
6
14
  import { useLocalStorageState } from 'ahooks';
@@ -73,12 +81,13 @@ export default function PayoutList({ customer_id, payment_intent_id, status, fea
73
81
  const { t } = useLocaleContext();
74
82
 
75
83
  const listKey = getListKey({ customer_id, payment_intent_id });
84
+ const defaultPageSize = useDefaultPageSize(20);
76
85
  const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
77
86
  defaultValue: {
78
87
  status: status as string,
79
88
  customer_id,
80
89
  payment_intent_id,
81
- pageSize: 20,
90
+ pageSize: defaultPageSize,
82
91
  page: 1,
83
92
  },
84
93
  });
@@ -252,6 +261,7 @@ export default function PayoutList({ customer_id, payment_intent_id, status, fea
252
261
  />
253
262
  )
254
263
  }
264
+ emptyNodeText={t('empty.payouts')}
255
265
  />
256
266
  );
257
267
  }
@@ -3,6 +3,7 @@ import { FormInput, formatPrice, usePaymentContext } from '@blocklet/payment-rea
3
3
  import type { TPrice } from '@blocklet/payment-types';
4
4
  import { DeleteOutlineOutlined } from '@mui/icons-material';
5
5
  import { Box, Checkbox, FormControlLabel, IconButton, InputAdornment, Stack, Typography } from '@mui/material';
6
+ import { get } from 'lodash';
6
7
  import { Controller, useFormContext, useWatch } from 'react-hook-form';
7
8
 
8
9
  type Props = {
@@ -15,7 +16,11 @@ export default function PriceItem({ prefix, price, onRemove }: Props) {
15
16
  const { t } = useLocaleContext();
16
17
  const getFieldName = (name: string) => (prefix ? `${prefix}.${name}` : name);
17
18
  const { settings } = usePaymentContext();
18
- const { control, setValue } = useFormContext();
19
+ const {
20
+ control,
21
+ setValue,
22
+ formState: { errors },
23
+ } = useFormContext();
19
24
  const includeFreeTrial = useWatch({ control, name: getFieldName('include_free_trial') });
20
25
 
21
26
  return (
@@ -47,12 +52,21 @@ export default function PriceItem({ prefix, price, onRemove }: Props) {
47
52
  {includeFreeTrial && (
48
53
  <FormInput
49
54
  name={getFieldName('subscription_data.trial_period_days')}
50
- rules={{ required: t('payment.checkout.required') }}
51
- errorPosition="right"
55
+ rules={{
56
+ required: t('payment.checkout.required'),
57
+ validate: (val) => {
58
+ if (val <= 0) {
59
+ return t('admin.paymentLink.freeTrialDaysPositive');
60
+ }
61
+ return true;
62
+ },
63
+ }}
64
+ helperText={get(errors, getFieldName('subscription_data.trial_period_days'))?.message as string}
65
+ error={!!get(errors, getFieldName('subscription_data.trial_period_days'))}
52
66
  sx={{ mt: 0.5 }}
53
67
  fullWidth={false}
54
68
  InputProps={{
55
- endAdornment: <InputAdornment position="end">days</InputAdornment>,
69
+ endAdornment: <InputAdornment position="end">{t('common.days')}</InputAdornment>,
56
70
  }}
57
71
  />
58
72
  )}
@@ -1,9 +1,10 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import Toast from '@arcblock/ux/lib/Toast';
3
3
  import { ConfirmDialog, api, formatError } from '@blocklet/payment-react';
4
- import type { TProduct } from '@blocklet/payment-types';
4
+ import type { TProduct, TProductExpanded } from '@blocklet/payment-types';
5
5
  import { useSetState } from 'ahooks';
6
6
  import type { LiteralUnion } from 'type-fest';
7
+ import { isEmpty } from 'lodash';
7
8
 
8
9
  import Actions from '../actions';
9
10
  import ClickBoundary from '../click-boundary';
@@ -11,7 +12,7 @@ import AssignPassportDialog from '../passport/assign';
11
12
  import EditProduct from './edit';
12
13
 
13
14
  type ProductActionProps = {
14
- data: TProduct;
15
+ data: TProductExpanded;
15
16
  onChange: (action: string) => void;
16
17
  variant?: LiteralUnion<'compact' | 'normal', string>;
17
18
  };
@@ -21,6 +22,7 @@ ProductActions.defaultProps = {
21
22
  };
22
23
 
23
24
  export default function ProductActions({ data, variant, onChange }: ProductActionProps) {
25
+ const isLocked = data.locked || (!isEmpty(data.prices) && data.prices.some((x) => x.locked));
24
26
  const { t } = useLocaleContext();
25
27
  const [state, setState] = useSetState({
26
28
  action: '',
@@ -85,7 +87,8 @@ export default function ProductActions({ data, variant, onChange }: ProductActio
85
87
  {
86
88
  label: t('admin.product.remove'),
87
89
  handler: () => setState({ action: 'remove' }),
88
- color: 'error',
90
+ disabled: isLocked,
91
+ color: isLocked ? 'text.disabled' : 'error',
89
92
  divider: true,
90
93
  },
91
94
  {
@@ -1,6 +1,14 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { Status, api, formatBNStr, formatTime, getPaymentIntentStatusColor, Table } from '@blocklet/payment-react';
3
+ import {
4
+ Status,
5
+ api,
6
+ formatBNStr,
7
+ formatTime,
8
+ getPaymentIntentStatusColor,
9
+ Table,
10
+ useDefaultPageSize,
11
+ } from '@blocklet/payment-react';
4
12
  import type { TRefundExpanded } from '@blocklet/payment-types';
5
13
  import { CircularProgress, Typography } from '@mui/material';
6
14
  import { useLocalStorageState } from 'ahooks';
@@ -92,7 +100,7 @@ export default function RefundList({
92
100
  }: ListProps) {
93
101
  const { t } = useLocaleContext();
94
102
  const listKey = getListKey({ customer_id, invoice_id, subscription_id, payment_intent_id });
95
-
103
+ const defaultPageSize = useDefaultPageSize(20);
96
104
  const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
97
105
  defaultValue: {
98
106
  status: status as string,
@@ -100,7 +108,7 @@ export default function RefundList({
100
108
  invoice_id,
101
109
  subscription_id,
102
110
  payment_intent_id,
103
- pageSize: 20,
111
+ pageSize: defaultPageSize,
104
112
  page: 1,
105
113
  },
106
114
  });
@@ -1,4 +1,4 @@
1
- import { formatSubscriptionProduct } from '@blocklet/payment-react';
1
+ import { formatSubscriptionProduct, 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';
@@ -10,13 +10,14 @@ type Props = {
10
10
  };
11
11
 
12
12
  export default function SubscriptionDescription({ subscription, variant, hideSubscription }: Props) {
13
+ const { isMobile } = useMobile();
13
14
  if (subscription.description) {
14
15
  return (
15
16
  <Stack direction="row" alignItems="center" spacing={1}>
16
17
  <Typography variant={variant} fontWeight={600} className="subscription-description">
17
18
  {subscription.description}
18
19
  </Typography>
19
- {!hideSubscription && (
20
+ {!hideSubscription && !isMobile && (
20
21
  <Tooltip title={formatSubscriptionProduct(subscription.items)}>
21
22
  <InfoOutlined sx={{ color: 'text.secondary' }} fontSize="small" />
22
23
  </Tooltip>
@@ -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 { Status, api, formatTime, Table } from '@blocklet/payment-react';
3
+ import { Status, api, formatTime, Table, useDefaultPageSize } from '@blocklet/payment-react';
4
4
  import type { TSubscriptionExpanded } from '@blocklet/payment-types';
5
5
  import { CircularProgress } from '@mui/material';
6
6
  import { useLocalStorageState } from 'ahooks';
@@ -68,11 +68,12 @@ export default function SubscriptionList({ customer_id, features, status }: List
68
68
  const listKey = getListKey({ customer_id });
69
69
 
70
70
  const { t } = useLocaleContext();
71
+ const defaultPageSize = useDefaultPageSize(20);
71
72
  const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
72
73
  defaultValue: {
73
74
  status: (status || 'active') as string,
74
75
  customer_id,
75
- pageSize: 20,
76
+ pageSize: defaultPageSize,
76
77
  page: 1,
77
78
  },
78
79
  });