payment-kit 1.19.8 → 1.19.10

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.
@@ -1052,10 +1052,11 @@ router.put('/:id', authPortal, async (req, res) => {
1052
1052
  if (due === '0') {
1053
1053
  hasNext = false;
1054
1054
  } else {
1055
+ const payer = getSubscriptionPaymentAddress(subscription, paymentMethod.type);
1055
1056
  const delegation = await isDelegationSufficientForPayment({
1056
1057
  paymentMethod,
1057
1058
  paymentCurrency,
1058
- userDid: customer.did,
1059
+ userDid: payer,
1059
1060
  amount: setup.amount.setup,
1060
1061
  });
1061
1062
  if (delegation.sufficient) {
@@ -1657,10 +1658,11 @@ router.post('/:id/change-payment', authPortal, async (req, res) => {
1657
1658
  }
1658
1659
  } else {
1659
1660
  // changing from crypto to crypto: just update the subscription
1661
+ const payer = getSubscriptionPaymentAddress(subscription, paymentMethod.type);
1660
1662
  delegation = await isDelegationSufficientForPayment({
1661
1663
  paymentMethod,
1662
1664
  paymentCurrency,
1663
- userDid: customer!.did,
1665
+ userDid: payer,
1664
1666
  amount: getFastCheckoutAmount(lineItems, 'subscription', paymentCurrency.id, false),
1665
1667
  });
1666
1668
  const noStake = subscription.billing_thresholds?.no_stake;
@@ -1679,7 +1681,10 @@ router.post('/:id/change-payment', authPortal, async (req, res) => {
1679
1681
  default_payment_method_id: paymentMethod.id,
1680
1682
  payment_settings: {
1681
1683
  payment_method_types: [paymentMethod.type],
1682
- payment_method_options: {},
1684
+ payment_method_options: {
1685
+ ...(subscription.payment_settings?.payment_method_options || {}),
1686
+ [paymentMethod.type]: { payer },
1687
+ },
1683
1688
  },
1684
1689
  });
1685
1690
  logger.info('Subscription payment change done on delegation enough', {
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.19.8
17
+ version: 1.19.10
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.19.8",
3
+ "version": "1.19.10",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "lint": "tsc --noEmit && eslint src api/src --ext .mjs,.js,.jsx,.ts,.tsx",
@@ -46,17 +46,18 @@
46
46
  "@abtnode/cron": "^1.16.46",
47
47
  "@arcblock/did": "^1.21.0",
48
48
  "@arcblock/did-auth-storage-nedb": "^1.7.1",
49
- "@arcblock/did-connect": "^3.0.32",
49
+ "@arcblock/did-connect": "^3.0.36",
50
50
  "@arcblock/did-util": "^1.21.0",
51
51
  "@arcblock/jwt": "^1.21.0",
52
- "@arcblock/ux": "^3.0.32",
52
+ "@arcblock/ux": "^3.0.36",
53
53
  "@arcblock/validator": "^1.21.0",
54
- "@blocklet/did-space-js": "^1.1.8",
54
+ "@blocklet/did-space-js": "^1.1.10",
55
+ "@blocklet/error": "^0.2.5",
55
56
  "@blocklet/js-sdk": "^1.16.46",
56
57
  "@blocklet/logger": "^1.16.46",
57
- "@blocklet/payment-react": "1.19.8",
58
+ "@blocklet/payment-react": "1.19.10",
58
59
  "@blocklet/sdk": "^1.16.46",
59
- "@blocklet/ui-react": "^3.0.32",
60
+ "@blocklet/ui-react": "^3.0.36",
60
61
  "@blocklet/uploader": "^0.2.4",
61
62
  "@blocklet/xss": "^0.2.2",
62
63
  "@mui/icons-material": "^7.1.2",
@@ -123,7 +124,7 @@
123
124
  "devDependencies": {
124
125
  "@abtnode/types": "^1.16.46",
125
126
  "@arcblock/eslint-config-ts": "^0.3.3",
126
- "@blocklet/payment-types": "1.19.8",
127
+ "@blocklet/payment-types": "1.19.10",
127
128
  "@types/cookie-parser": "^1.4.9",
128
129
  "@types/cors": "^2.8.19",
129
130
  "@types/debug": "^4.1.12",
@@ -169,5 +170,5 @@
169
170
  "parser": "typescript"
170
171
  }
171
172
  },
172
- "gitHead": "59916e7b537b714eb9614365ca144704e7566ad8"
173
+ "gitHead": "96665501b84f130e074df9a3d70f9b6f48cc3309"
173
174
  }
@@ -1,6 +1,6 @@
1
1
  import { formatBNStr, CreditGrantsList, CreditTransactionsList, api } from '@blocklet/payment-react';
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
- import { Avatar, Box, Card, CardContent, Stack, Typography, Tabs, Tab } from '@mui/material';
3
+ import { Box, Card, CardContent, Stack, Typography, Tabs, Tab } from '@mui/material';
4
4
  import { useMemo, useState } from 'react';
5
5
  import type { TPaymentCurrency } from '@blocklet/payment-types';
6
6
  import { useRequest } from 'ahooks';
@@ -103,13 +103,16 @@ export default function CreditOverview({ customerId, settings, mode = 'portal' }
103
103
  <CardContent sx={{ flexGrow: 1 }}>
104
104
  <Stack spacing={2}>
105
105
  {/* 货币信息 */}
106
+
106
107
  <Stack
107
- direction="row"
108
- spacing={1}
108
+ direction="column"
109
+ spacing={0.5}
109
110
  sx={{
110
- alignItems: 'center',
111
+ alignItems: 'flex-start',
112
+ borderBottom: '1px solid',
113
+ borderColor: 'divider',
114
+ pb: 2,
111
115
  }}>
112
- <Avatar src={currency.logo} alt={currency.symbol} sx={{ width: 24, height: 24 }} />
113
116
  <Typography variant="h6" component="div">
114
117
  {currency.name}
115
118
  </Typography>
@@ -127,11 +130,11 @@ export default function CreditOverview({ customerId, settings, mode = 'portal' }
127
130
  </Typography>
128
131
  <Typography variant="h5" component="div" sx={{ fontWeight: 'normal' }}>
129
132
  {totalAmount === '0' && remainingAmount === '0' ? (
130
- <>0 {currency.symbol}</>
133
+ <>0 </>
131
134
  ) : (
132
135
  <>
133
136
  {formatBNStr(remainingAmount, currency.decimal, 6, true)} /{' '}
134
- {formatBNStr(totalAmount, currency.decimal, 6, true)} {currency.symbol}
137
+ {formatBNStr(totalAmount, currency.decimal, 6, true)}
135
138
  </>
136
139
  )}
137
140
  </Typography>
@@ -153,7 +156,7 @@ export default function CreditOverview({ customerId, settings, mode = 'portal' }
153
156
  sx={{
154
157
  color: 'error.main',
155
158
  }}>
156
- {formatBNStr(pendingAmount, currency.decimal, 6, true)} {currency.symbol}
159
+ {formatBNStr(pendingAmount, currency.decimal, 6, true)}
157
160
  </Typography>
158
161
  </Box>
159
162
  )}
@@ -4,10 +4,11 @@ import type { TProductExpanded } from '@blocklet/payment-types';
4
4
  import { AddOutlined } from '@mui/icons-material';
5
5
  import { Avatar, Box, ListSubheader, MenuItem, Select, Stack, Typography } from '@mui/material';
6
6
  import cloneDeep from 'lodash/cloneDeep';
7
- import { useState } from 'react';
7
+ import { useRef, useState } from 'react';
8
8
  import type { LiteralUnion } from 'type-fest';
9
9
 
10
10
  import Empty from '@arcblock/ux/lib/Empty';
11
+ import useBus, { EventAction } from 'use-bus';
11
12
  import { useProductsContext } from '../../contexts/products';
12
13
 
13
14
  type Props = {
@@ -53,14 +54,26 @@ export default function ProductSelect({
53
54
  const { products } = useProductsContext();
54
55
  const { settings } = usePaymentContext();
55
56
  const [value, setValue] = useState('');
57
+ const valueRef = useRef(value);
56
58
  const size = { width: 16, height: 16 };
57
59
 
58
60
  const handleSelect = (e: any) => {
59
61
  setValue(e.target.value);
62
+ valueRef.current = e.target.value;
60
63
  setMode('waiting');
61
64
  onSelect(e.target.value);
62
65
  };
63
66
 
67
+ useBus(
68
+ (event: EventAction) => event.type === 'product.select.price.removed',
69
+ (event: EventAction) => {
70
+ if (valueRef.current === event.priceId) {
71
+ setValue('');
72
+ valueRef.current = '';
73
+ }
74
+ }
75
+ );
76
+
64
77
  const items = (callback?: any) => {
65
78
  const filteredProducts = filterProducts(products, hasSelected, filterPrice);
66
79
 
@@ -5,6 +5,7 @@ import type { PricingTableItem, TProduct, TProductExpanded } from '@blocklet/pay
5
5
  import { Box, Stack } from '@mui/material';
6
6
  import { useSetState } from 'ahooks';
7
7
 
8
+ import { dispatch } from 'use-bus';
8
9
  import { useProductsContext } from '../../contexts/products';
9
10
  import { getPriceFromProducts } from '../../libs/util';
10
11
  import Actions from '../actions';
@@ -74,7 +75,13 @@ export default function ProductItem({ product, prices, valid, onUpdate, onRemove
74
75
  key={x.index}
75
76
  prefix={`items.${x.index}`}
76
77
  price={getPriceFromProducts(products, x.price_id) as any}
77
- onRemove={() => onRemove(x.index)}
78
+ onRemove={() => {
79
+ onRemove(x.index);
80
+ dispatch({
81
+ type: 'product.select.price.removed',
82
+ priceId: x.price_id,
83
+ });
84
+ }}
78
85
  />
79
86
  ))}
80
87
  </Stack>
@@ -33,7 +33,12 @@ const fetchProducts = (forceRefresh = false): Promise<{ list: TProductExpanded[]
33
33
  // eslint-disable-next-line react/prop-types
34
34
  function ProductsProvider({ children }: { children: any }): JSX.Element {
35
35
  const { data, error, run, loading } = useRequest((forceRefresh = false) => fetchProducts(forceRefresh));
36
- useBus('project.created', () => run(true), []);
36
+ useBus('product.created', () => run(true), []);
37
+ useBus('product.updated', () => run(true), []);
38
+ useBus('product.deleted', () => run(true), []);
39
+ useBus('price.created', () => run(true), []);
40
+ useBus('price.updated', () => run(true), []);
41
+ useBus('price.deleted', () => run(true), []);
37
42
  if (error) {
38
43
  return <Alert severity="error">{error.message}</Alert>;
39
44
  }
@@ -102,6 +102,16 @@ export default function PaymentLinkDetail(props: { id: string }) {
102
102
  setState((prev) => ({ editing: { ...prev.editing, metadata: true } }));
103
103
  };
104
104
 
105
+ const renderConfirmPage = (record: any) => {
106
+ if (record.type === 'hosted_confirmation') {
107
+ return <Typography>{record.hosted_confirmation.custom_message || t('common.none')}</Typography>;
108
+ }
109
+ if (record.type === 'redirect' && record.redirect.url) {
110
+ return <Link to={record.redirect.url}>{record.redirect.url}</Link>;
111
+ }
112
+ return t('common.none');
113
+ };
114
+
105
115
  return (
106
116
  <Grid container spacing={4} sx={{ mb: 4 }}>
107
117
  <Grid size={12}>
@@ -362,7 +372,10 @@ export default function PaymentLinkDetail(props: { id: string }) {
362
372
  value={data.phone_number_collection?.enabled ? t('common.yes') : t('common.no')}
363
373
  />
364
374
 
365
- <InfoRow label={t('admin.paymentLink.showConfirmPage')} value={data.after_completion?.type} />
375
+ <InfoRow
376
+ label={t('admin.paymentLink.showConfirmPage')}
377
+ value={renderConfirmPage(data.after_completion)}
378
+ />
366
379
  <InfoRow label={t('admin.paymentLink.mintNft')} value={data.nft_mint_settings?.factory || ''} />
367
380
  <InfoRow label={t('common.createdAt')} value={formatTime(data.created_at)} />
368
381
  <InfoRow label={t('common.updatedAt')} value={formatTime(data.updated_at)} />
@@ -6,6 +6,7 @@ import { useSetState } from 'ahooks';
6
6
  import noop from 'lodash/noop';
7
7
  import { useNavigate } from 'react-router-dom';
8
8
 
9
+ import { dispatch } from 'use-bus';
9
10
  import Actions from '../../../../components/actions';
10
11
  import EditPrice from '../../../../components/product/edit-price';
11
12
 
@@ -45,6 +46,7 @@ export default function PriceActions({
45
46
  setState({ loading: true });
46
47
  await api.put(`/api/prices/${data.id}`, updates).then((res) => res.data);
47
48
  Toast.success(t('common.saved'));
49
+ dispatch('price.updated');
48
50
  onChange(state.action);
49
51
  } catch (err) {
50
52
  console.error(err);
@@ -59,6 +61,7 @@ export default function PriceActions({
59
61
  setState({ loading: true });
60
62
  await api.put(`/api/prices/${data.id}/archive`).then((res) => res.data);
61
63
  Toast.success(t('common.saved'));
64
+ dispatch('price.updated');
62
65
  onChange(state.action);
63
66
  } catch (err) {
64
67
  console.error(err);
@@ -72,6 +75,7 @@ export default function PriceActions({
72
75
  setState({ loading: true });
73
76
  await api.delete(`/api/prices/${data.id}`).then((res) => res.data);
74
77
  Toast.success(t('common.removed'));
78
+ dispatch('price.deleted');
75
79
  onChange(state.action);
76
80
  } catch (err) {
77
81
  console.error(err);
@@ -17,6 +17,7 @@ import { styled } from '@mui/system';
17
17
  import { useRequest, useSetState } from 'ahooks';
18
18
  import { Link, useNavigate } from 'react-router-dom';
19
19
 
20
+ import { dispatch } from 'use-bus';
20
21
  import Copyable from '../../../../components/copyable';
21
22
  import Currency from '../../../../components/currency';
22
23
  import EventList from '../../../../components/event/list';
@@ -68,6 +69,7 @@ export default function PriceDetail(props: { id: string }) {
68
69
  setState((prev) => ({ loading: { ...prev.loading, [key]: true } }));
69
70
  await api.put(`/api/prices/${props.id}`, updates).then((res) => res.data);
70
71
  Toast.success(t('common.saved'));
72
+ dispatch('price.updated');
71
73
  runAsync();
72
74
  } catch (err) {
73
75
  console.error(err);
@@ -159,7 +159,7 @@ export default function ProductsCreate({
159
159
  Toast.success(t('admin.product.saved'));
160
160
  methods.reset();
161
161
  dispatch('drawer.submitted');
162
- dispatch('project.created');
162
+ dispatch('product.created');
163
163
  if (onSubmitCallback) {
164
164
  onSubmitCallback();
165
165
  }
@@ -20,6 +20,7 @@ import { useRequest, useSetState } from 'ahooks';
20
20
  import { useNavigate } from 'react-router-dom';
21
21
 
22
22
  import { isEmpty } from 'lodash';
23
+ import { dispatch } from 'use-bus';
23
24
  import Copyable from '../../../../components/copyable';
24
25
  import EventList from '../../../../components/event/list';
25
26
  import InfoMetric from '../../../../components/info-metric';
@@ -78,6 +79,7 @@ export default function ProductDetail(props: { id: string }) {
78
79
  setState((prev) => ({ loading: { ...prev.loading, [key]: true } }));
79
80
  await api.put(`/api/products/${props.id}`, updates).then((res) => res.data);
80
81
  Toast.success(t('common.saved'));
82
+ dispatch('product.updated');
81
83
  runAsync();
82
84
  } catch (err) {
83
85
  console.error(err);
@@ -92,6 +94,7 @@ export default function ProductDetail(props: { id: string }) {
92
94
  setState((prev) => ({ loading: { ...prev.loading, price: true } }));
93
95
  await api.post('/api/prices', { ...price, product_id: props.id });
94
96
  Toast.success(t('common.saved'));
97
+ dispatch('price.created');
95
98
  runAsync();
96
99
  } catch (err) {
97
100
  console.error(err);
@@ -60,7 +60,9 @@ export default function ProductsList() {
60
60
  setData(res);
61
61
  });
62
62
 
63
- useBus('project.created', () => refresh(), []);
63
+ useBus('product.created', () => refresh(), []);
64
+ useBus('product.updated', () => refresh(), []);
65
+ useBus('product.deleted', () => refresh(), []);
64
66
 
65
67
  useEffect(() => {
66
68
  refresh();