payment-kit 1.15.19 → 1.15.21
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.
- package/api/src/crons/base.ts +69 -7
- package/api/src/crons/subscription-trial-will-end.ts +20 -5
- package/api/src/crons/subscription-will-canceled.ts +22 -6
- package/api/src/crons/subscription-will-renew.ts +13 -4
- package/api/src/index.ts +2 -0
- package/api/src/integrations/arcblock/stake.ts +27 -0
- package/api/src/libs/notification/template/subscription-canceled.ts +4 -0
- package/api/src/libs/notification/template/subscription-trial-will-end.ts +12 -34
- package/api/src/libs/notification/template/subscription-will-canceled.ts +82 -48
- package/api/src/libs/notification/template/subscription-will-renew.ts +16 -45
- package/api/src/libs/time.ts +13 -0
- package/api/src/libs/util.ts +17 -0
- package/api/src/locales/en.ts +12 -2
- package/api/src/locales/zh.ts +11 -2
- package/api/src/queues/subscription.ts +108 -4
- package/api/src/routes/connect/recharge.ts +143 -0
- package/api/src/routes/connect/shared.ts +25 -0
- package/api/src/routes/customers.ts +2 -2
- package/api/src/routes/subscription-items.ts +49 -11
- package/api/src/routes/subscriptions.ts +41 -36
- package/api/src/store/models/subscription.ts +2 -0
- package/api/tests/libs/time.spec.ts +54 -0
- package/blocklet.yml +1 -1
- package/package.json +19 -19
- package/src/app.tsx +10 -0
- package/src/components/subscription/actions/cancel.tsx +30 -9
- package/src/components/subscription/actions/index.tsx +11 -3
- package/src/locales/en.tsx +13 -0
- package/src/locales/zh.tsx +13 -0
- package/src/pages/customer/recharge.tsx +417 -0
- package/src/pages/customer/subscription/detail.tsx +38 -20
- package/tsconfig.json +2 -2
|
@@ -38,7 +38,6 @@ import { PaymentMethod } from '../store/models/payment-method';
|
|
|
38
38
|
import { Price } from '../store/models/price';
|
|
39
39
|
import { PricingTable } from '../store/models/pricing-table';
|
|
40
40
|
import { Product } from '../store/models/product';
|
|
41
|
-
import { Refund } from '../store/models/refund';
|
|
42
41
|
import { SetupIntent } from '../store/models/setup-intent';
|
|
43
42
|
import { Subscription, TSubscription } from '../store/models/subscription';
|
|
44
43
|
import { SubscriptionItem } from '../store/models/subscription-item';
|
|
@@ -46,6 +45,8 @@ import type { LineItem, ServiceAction, SubscriptionUpdateItem } from '../store/m
|
|
|
46
45
|
import { UsageRecord } from '../store/models/usage-record';
|
|
47
46
|
import { cleanupInvoiceAndItems, ensureInvoiceAndItems } from './connect/shared';
|
|
48
47
|
import { createUsageRecordQueryFn } from './usage-records';
|
|
48
|
+
import { SubscriptionWillCanceledSchedule } from '../crons/subscription-will-canceled';
|
|
49
|
+
import { getTokenByAddress } from '../integrations/arcblock/stake';
|
|
49
50
|
|
|
50
51
|
const router = Router();
|
|
51
52
|
const auth = authenticate<Subscription>({ component: true, roles: ['owner', 'admin'] });
|
|
@@ -377,57 +378,35 @@ router.put('/:id/cancel', authPortal, async (req, res) => {
|
|
|
377
378
|
}
|
|
378
379
|
}
|
|
379
380
|
|
|
380
|
-
await subscription.update(updates);
|
|
381
|
-
|
|
382
381
|
// trigger refund
|
|
383
382
|
if (updates.cancel_at < subscription.current_period_end && refund !== 'none') {
|
|
384
383
|
if (['owner', 'admin'].includes(req.user?.role as string) === false) {
|
|
385
|
-
return res.status(403).json({ error: 'Not authorized to
|
|
384
|
+
return res.status(403).json({ error: 'Not authorized to refund' });
|
|
386
385
|
}
|
|
387
|
-
|
|
388
386
|
const result = await getSubscriptionRefundSetup(subscription, updates.cancel_at);
|
|
389
387
|
if (result.unused !== '0') {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
currency_id: subscription.currency_id,
|
|
398
|
-
customer_id: subscription.customer_id,
|
|
399
|
-
payment_method_id: subscription.default_payment_method_id,
|
|
400
|
-
payment_intent_id: result.lastInvoice.payment_intent_id as string,
|
|
401
|
-
invoice_id: result.lastInvoice.id,
|
|
402
|
-
subscription_id: subscription.id,
|
|
403
|
-
attempt_count: 0,
|
|
404
|
-
attempted: false,
|
|
405
|
-
next_attempt: 0,
|
|
406
|
-
last_attempt_error: null,
|
|
407
|
-
starting_balance: '0',
|
|
408
|
-
ending_balance: '0',
|
|
409
|
-
starting_token_balance: {},
|
|
410
|
-
ending_token_balance: {},
|
|
411
|
-
metadata: {
|
|
412
|
-
requested_by: req.user?.did,
|
|
413
|
-
unused_period_start: refund === 'last' ? subscription.current_period_start : updates.cancel_at,
|
|
414
|
-
unused_period_end: subscription.current_period_end,
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
logger.info('subscription cancel refund created', {
|
|
388
|
+
// @ts-ignore
|
|
389
|
+
updates.cancelation_details = {
|
|
390
|
+
...(updates.cancelation_details || {}),
|
|
391
|
+
refund,
|
|
392
|
+
requested_by: req.user?.did,
|
|
393
|
+
};
|
|
394
|
+
logger.info('subscription cancel with refund', {
|
|
418
395
|
...req.params,
|
|
419
396
|
...req.body,
|
|
397
|
+
refund,
|
|
420
398
|
...pick(result, ['total', 'unused']),
|
|
421
|
-
item: item.toJSON(),
|
|
422
399
|
});
|
|
423
400
|
} else {
|
|
424
|
-
logger.info('subscription cancel refund
|
|
401
|
+
logger.info('subscription cancel no refund', {
|
|
425
402
|
...req.params,
|
|
426
403
|
...req.body,
|
|
427
404
|
...pick(result, ['total', 'unused']),
|
|
428
405
|
});
|
|
429
406
|
}
|
|
430
407
|
}
|
|
408
|
+
await subscription.update(updates);
|
|
409
|
+
await new SubscriptionWillCanceledSchedule().reScheduleSubscriptionTasks([subscription]);
|
|
431
410
|
|
|
432
411
|
return res.json(subscription);
|
|
433
412
|
});
|
|
@@ -455,7 +434,7 @@ router.put('/:id/recover', authPortal, async (req, res) => {
|
|
|
455
434
|
}
|
|
456
435
|
|
|
457
436
|
await doc.update({ cancel_at_period_end: false, cancel_at: 0, canceled_at: 0 });
|
|
458
|
-
|
|
437
|
+
await new SubscriptionWillCanceledSchedule().deleteScheduleSubscriptionJobs([doc]);
|
|
459
438
|
// reschedule jobs
|
|
460
439
|
subscriptionQueue
|
|
461
440
|
.delete(`cancel-${doc.id}`)
|
|
@@ -1730,4 +1709,30 @@ router.put('/:id/slash-stake', auth, async (req, res) => {
|
|
|
1730
1709
|
return res.status(400).json({ error: err.message });
|
|
1731
1710
|
}
|
|
1732
1711
|
});
|
|
1712
|
+
|
|
1713
|
+
// get payer token
|
|
1714
|
+
router.get('/:id/payer-token', authMine, async (req, res) => {
|
|
1715
|
+
const subscription = await Subscription.findByPk(req.params.id);
|
|
1716
|
+
if (!subscription) {
|
|
1717
|
+
return res.status(400).json({ error: `Subscription(${req.params.id}) not found` });
|
|
1718
|
+
}
|
|
1719
|
+
const paymentMethod = await PaymentMethod.findByPk(subscription.default_payment_method_id);
|
|
1720
|
+
if (!paymentMethod) {
|
|
1721
|
+
return res.status(400).json({ error: `Payment method(${subscription.default_payment_method_id}) not found` });
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
|
|
1725
|
+
if (!paymentCurrency) {
|
|
1726
|
+
return res.status(400).json({ error: `Payment currency(${subscription.currency_id}) not found` });
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
// @ts-ignore
|
|
1730
|
+
const paymentAddress = subscription.payment_details?.[paymentMethod.type]?.payer ?? undefined;
|
|
1731
|
+
if (!paymentAddress && ['ethereum', 'arcblock'].includes(paymentMethod.type)) {
|
|
1732
|
+
return res.status(400).json({ error: `Payer not found on subscription payment detail: ${subscription.id}` });
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
const token = await getTokenByAddress(paymentAddress, paymentMethod, paymentCurrency);
|
|
1736
|
+
return res.json({ token, paymentAddress });
|
|
1737
|
+
});
|
|
1733
1738
|
export default router;
|
|
@@ -64,6 +64,8 @@ export class Subscription extends Model<InferAttributes<Subscription>, InferCrea
|
|
|
64
64
|
return_stake?: boolean;
|
|
65
65
|
slash_stake?: boolean;
|
|
66
66
|
slash_reason?: string;
|
|
67
|
+
refund?: LiteralUnion<'last' | 'proration' | 'none', string>;
|
|
68
|
+
requested_by?: string;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
declare billing_cycle_anchor: number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getSimplifyDuration } from '../../src/libs/time';
|
|
2
|
+
|
|
3
|
+
describe('getSimplifyDuration', () => {
|
|
4
|
+
const testCasesEn = [
|
|
5
|
+
{ ms: 30 * 1000, expected: '30 seconds' },
|
|
6
|
+
{ ms: 34 * 60 * 1000 + 30 * 1000, expected: '34 minutes' },
|
|
7
|
+
{ ms: 59 * 60 * 1000, expected: '59 minutes' },
|
|
8
|
+
{ ms: 60 * 60 * 1000, expected: '1 hour' },
|
|
9
|
+
{ ms: 23 * 60 * 60 * 1000, expected: '23 hours' },
|
|
10
|
+
{ ms: 24 * 60 * 60 * 1000, expected: '1 day' },
|
|
11
|
+
{ ms: 24 * 60 * 60 * 1000 + 20 * 60 * 1000 + 30 * 1000, expected: '1 day' },
|
|
12
|
+
{ ms: 25 * 24 * 60 * 60 * 1000 + 30 * 60 * 1000 + 10 * 1000, expected: '25 days' },
|
|
13
|
+
{ ms: 32 * 24 * 60 * 60 * 1000 + 30 * 60 * 1000 + 12 * 1000, expected: '32 days' },
|
|
14
|
+
{ ms: 60 * 24 * 60 * 60 * 1000 + 20 * 60 * 1000, expected: '60 days' },
|
|
15
|
+
{ ms: 366 * 24 * 60 * 60 * 1000 + 20 * 60 * 1000, expected: '1 year' },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const testCasesZh = [
|
|
19
|
+
{ ms: 30 * 1000, expected: '30秒' },
|
|
20
|
+
{ ms: 34 * 60 * 1000 + 30 * 1000, expected: '34分钟' },
|
|
21
|
+
{ ms: 59 * 60 * 1000, expected: '59分钟' },
|
|
22
|
+
{ ms: 60 * 60 * 1000, expected: '1小时' },
|
|
23
|
+
{ ms: 23 * 60 * 60 * 1000, expected: '23小时' },
|
|
24
|
+
{ ms: 24 * 60 * 60 * 1000, expected: '1天' },
|
|
25
|
+
{ ms: 24 * 60 * 60 * 1000 + 20 * 60 * 1000 + 30 * 1000, expected: '1天' },
|
|
26
|
+
{ ms: 25 * 24 * 60 * 60 * 1000 + 30 * 60 * 1000 + 10 * 1000, expected: '25天' },
|
|
27
|
+
{ ms: 32 * 24 * 60 * 60 * 1000 + 30 * 60 * 1000 + 12 * 1000, expected: '32天' },
|
|
28
|
+
{ ms: 60 * 24 * 60 * 60 * 1000 + 20 * 60 * 1000, expected: '60天' },
|
|
29
|
+
{ ms: 366 * 24 * 60 * 60 * 1000 + 20 * 60 * 1000, expected: '1年' },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
test.each(testCasesEn)('should return $expected for $ms milliseconds in English', ({ ms, expected }) => {
|
|
33
|
+
expect(getSimplifyDuration(ms, 'en')).toBe(expected);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test.each(testCasesZh)('should return $expected for $ms milliseconds in Chinese', ({ ms, expected }) => {
|
|
37
|
+
expect(getSimplifyDuration(ms, 'zh')).toBe(expected);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should handle zero', () => {
|
|
41
|
+
expect(getSimplifyDuration(0, 'en')).toBe('0ms');
|
|
42
|
+
expect(getSimplifyDuration(0, 'zh')).toBe('0毫秒');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should handle negative values', () => {
|
|
46
|
+
expect(getSimplifyDuration(-24 * 60 * 60 * 1000, 'en')).toBe('-1 days');
|
|
47
|
+
expect(getSimplifyDuration(-24 * 60 * 60 * 1000, 'zh')).toBe('-1天');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('should handle large number of days', () => {
|
|
51
|
+
expect(getSimplifyDuration(1000 * 24 * 60 * 60 * 1000, 'en')).toBe('2 years');
|
|
52
|
+
expect(getSimplifyDuration(1000 * 24 * 60 * 60 * 1000, 'zh')).toBe('2年');
|
|
53
|
+
});
|
|
54
|
+
});
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.21",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -43,29 +43,29 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@abtnode/cron": "^1.16.32",
|
|
46
|
-
"@arcblock/did": "^1.18.
|
|
46
|
+
"@arcblock/did": "^1.18.136",
|
|
47
47
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
48
|
-
"@arcblock/did-connect": "^2.10.
|
|
49
|
-
"@arcblock/did-util": "^1.18.
|
|
50
|
-
"@arcblock/jwt": "^1.18.
|
|
51
|
-
"@arcblock/ux": "^2.10.
|
|
52
|
-
"@arcblock/validator": "^1.18.
|
|
48
|
+
"@arcblock/did-connect": "^2.10.51",
|
|
49
|
+
"@arcblock/did-util": "^1.18.136",
|
|
50
|
+
"@arcblock/jwt": "^1.18.136",
|
|
51
|
+
"@arcblock/ux": "^2.10.51",
|
|
52
|
+
"@arcblock/validator": "^1.18.136",
|
|
53
53
|
"@blocklet/js-sdk": "^1.16.32",
|
|
54
54
|
"@blocklet/logger": "^1.16.32",
|
|
55
|
-
"@blocklet/payment-react": "1.15.
|
|
55
|
+
"@blocklet/payment-react": "1.15.21",
|
|
56
56
|
"@blocklet/sdk": "^1.16.32",
|
|
57
|
-
"@blocklet/ui-react": "^2.10.
|
|
58
|
-
"@blocklet/uploader": "^0.1.
|
|
59
|
-
"@blocklet/xss": "^0.1.
|
|
57
|
+
"@blocklet/ui-react": "^2.10.51",
|
|
58
|
+
"@blocklet/uploader": "^0.1.46",
|
|
59
|
+
"@blocklet/xss": "^0.1.12",
|
|
60
60
|
"@mui/icons-material": "^5.16.6",
|
|
61
61
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
62
62
|
"@mui/material": "^5.16.6",
|
|
63
63
|
"@mui/system": "^5.16.6",
|
|
64
|
-
"@ocap/asset": "^1.18.
|
|
65
|
-
"@ocap/client": "^1.18.
|
|
66
|
-
"@ocap/mcrypto": "^1.18.
|
|
67
|
-
"@ocap/util": "^1.18.
|
|
68
|
-
"@ocap/wallet": "^1.18.
|
|
64
|
+
"@ocap/asset": "^1.18.136",
|
|
65
|
+
"@ocap/client": "^1.18.136",
|
|
66
|
+
"@ocap/mcrypto": "^1.18.136",
|
|
67
|
+
"@ocap/util": "^1.18.136",
|
|
68
|
+
"@ocap/wallet": "^1.18.136",
|
|
69
69
|
"@react-pdf/renderer": "^3.4.4",
|
|
70
70
|
"@stripe/react-stripe-js": "^2.7.3",
|
|
71
71
|
"@stripe/stripe-js": "^2.4.0",
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
},
|
|
118
118
|
"devDependencies": {
|
|
119
119
|
"@abtnode/types": "^1.16.32",
|
|
120
|
-
"@arcblock/eslint-config-ts": "^0.3.
|
|
121
|
-
"@blocklet/payment-types": "1.15.
|
|
120
|
+
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
121
|
+
"@blocklet/payment-types": "1.15.21",
|
|
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": "
|
|
163
|
+
"gitHead": "b27debca52a2ea7f93a2a237053b8e171f8be3a2"
|
|
164
164
|
}
|
package/src/app.tsx
CHANGED
|
@@ -27,6 +27,7 @@ const CustomerSubscriptionDetail = React.lazy(() => import('./pages/customer/sub
|
|
|
27
27
|
const CustomerSubscriptionEmbed = React.lazy(() => import('./pages/customer/subscription/embed'));
|
|
28
28
|
const CustomerSubscriptionChangePlan = React.lazy(() => import('./pages/customer/subscription/change-plan'));
|
|
29
29
|
const CustomerSubscriptionChangePayment = React.lazy(() => import('./pages/customer/subscription/change-payment'));
|
|
30
|
+
const CustomerRecharge = React.lazy(() => import('./pages/customer/recharge'));
|
|
30
31
|
|
|
31
32
|
// const theme = createTheme({
|
|
32
33
|
// typography: {
|
|
@@ -92,6 +93,15 @@ function App() {
|
|
|
92
93
|
</Layout>
|
|
93
94
|
}
|
|
94
95
|
/>
|
|
96
|
+
<Route
|
|
97
|
+
key="customer-recharge"
|
|
98
|
+
path="/customer/subscription/:id/recharge"
|
|
99
|
+
element={
|
|
100
|
+
<Layout>
|
|
101
|
+
<CustomerRecharge />
|
|
102
|
+
</Layout>
|
|
103
|
+
}
|
|
104
|
+
/>
|
|
95
105
|
<Route
|
|
96
106
|
key="customer-embed"
|
|
97
107
|
path="/customer/embed/subscription"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
-
import { api, formatAmount, formatTime } from '@blocklet/payment-react';
|
|
2
|
+
import { api, dayjs, formatAmount, formatTime } from '@blocklet/payment-react';
|
|
3
3
|
import type { TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
4
4
|
import { Box, Divider, FormControlLabel, Radio, RadioGroup, Stack, TextField, Typography, styled } from '@mui/material';
|
|
5
5
|
import { useRequest } from 'ahooks';
|
|
6
|
-
import { useEffect } from 'react';
|
|
6
|
+
import { useEffect, useMemo } from 'react';
|
|
7
7
|
import { Controller, useFormContext, useWatch } from 'react-hook-form';
|
|
8
8
|
|
|
9
9
|
const fetchData = (id: string, time: string): Promise<{ total: string; unused: string }> => {
|
|
@@ -21,13 +21,23 @@ export default function SubscriptionCancelForm({ data }: { data: TSubscriptionEx
|
|
|
21
21
|
const cancelTime = useWatch({ control, name: 'cancel.time' });
|
|
22
22
|
const refundType = useWatch({ control, name: 'cancel.refund' });
|
|
23
23
|
const stakingType = useWatch({ control, name: 'cancel.staking' });
|
|
24
|
-
const {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
const actualCancelAt = useMemo(() => {
|
|
25
|
+
if (cancelAt === 'custom') {
|
|
26
|
+
return cancelTime;
|
|
27
|
+
}
|
|
28
|
+
if (cancelAt === 'current_period_end') {
|
|
29
|
+
return new Date(data.current_period_end * 1000);
|
|
30
|
+
}
|
|
31
|
+
return '';
|
|
32
|
+
}, [cancelAt, cancelTime]);
|
|
33
|
+
const { loading, data: refund, refresh } = useRequest(() => fetchData(data.id, actualCancelAt));
|
|
29
34
|
|
|
30
|
-
const { data: staking } = useRequest(() =>
|
|
35
|
+
const { data: staking } = useRequest(() => {
|
|
36
|
+
if (data.paymentMethod?.type === 'arcblock') {
|
|
37
|
+
return fetchStakingData(data.id, actualCancelAt);
|
|
38
|
+
}
|
|
39
|
+
return Promise.resolve({ return_amount: '0', slash_amount: '0' });
|
|
40
|
+
});
|
|
31
41
|
useEffect(() => {
|
|
32
42
|
if (data) {
|
|
33
43
|
refresh();
|
|
@@ -71,7 +81,18 @@ export default function SubscriptionCancelForm({ data }: { data: TSubscriptionEx
|
|
|
71
81
|
{isCustom && (
|
|
72
82
|
<Controller
|
|
73
83
|
name="cancel.time"
|
|
74
|
-
rules={{
|
|
84
|
+
rules={{
|
|
85
|
+
required: isCustom,
|
|
86
|
+
validate: (value) => {
|
|
87
|
+
const now = dayjs();
|
|
88
|
+
const selectedTime = dayjs(value);
|
|
89
|
+
const periodEndTime = dayjs.unix(data.current_period_end);
|
|
90
|
+
if (selectedTime.isBefore(now) || selectedTime.isAfter(periodEndTime)) {
|
|
91
|
+
return t('admin.subscription.cancel.at.timeError');
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
},
|
|
95
|
+
}}
|
|
75
96
|
control={control}
|
|
76
97
|
render={({ field }) => (
|
|
77
98
|
<TextField
|
|
@@ -44,9 +44,17 @@ function SubscriptionActionsInner({ data, variant, onChange }: Props) {
|
|
|
44
44
|
slash_amount: '0',
|
|
45
45
|
},
|
|
46
46
|
runAsync: fetchStakeResultAsync,
|
|
47
|
-
} = useRequest(
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
} = useRequest(
|
|
48
|
+
() => {
|
|
49
|
+
if (data.paymentMethod?.type === 'arcblock') {
|
|
50
|
+
return fetchStakingData(data.id, '');
|
|
51
|
+
}
|
|
52
|
+
return Promise.resolve({ return_amount: '0', slash_amount: '0', total: '0' });
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
manual: true,
|
|
56
|
+
}
|
|
57
|
+
);
|
|
50
58
|
|
|
51
59
|
const stakeValue = useMemo(() => {
|
|
52
60
|
return formatBNStr(stakeResult?.slash_amount, data?.paymentCurrency?.decimal);
|
package/src/locales/en.tsx
CHANGED
|
@@ -457,6 +457,7 @@ export default flat({
|
|
|
457
457
|
now: 'Immediately ({date})',
|
|
458
458
|
current_period_end: 'End of current period ({date})',
|
|
459
459
|
custom: 'On a custom date',
|
|
460
|
+
timeError: 'Cancel time must be within the current period',
|
|
460
461
|
},
|
|
461
462
|
refund: {
|
|
462
463
|
title: 'Refund',
|
|
@@ -616,5 +617,17 @@ export default flat({
|
|
|
616
617
|
product: {
|
|
617
618
|
empty: 'No Product',
|
|
618
619
|
},
|
|
620
|
+
recharge: {
|
|
621
|
+
title: 'Recharge',
|
|
622
|
+
amount: 'Amount',
|
|
623
|
+
submit: 'Submit',
|
|
624
|
+
unsupported: 'Unsupported currency, please select another one',
|
|
625
|
+
receiveAddress: 'Receive Address',
|
|
626
|
+
view: 'View Subscription',
|
|
627
|
+
success: 'Recharge successfully',
|
|
628
|
+
custom: 'Custom',
|
|
629
|
+
estimatedDuration: '{duration} {unit} est.',
|
|
630
|
+
intervals: 'intervals',
|
|
631
|
+
},
|
|
619
632
|
},
|
|
620
633
|
});
|
package/src/locales/zh.tsx
CHANGED
|
@@ -447,6 +447,7 @@ export default flat({
|
|
|
447
447
|
now: '立即取消({date})',
|
|
448
448
|
current_period_end: '本周期结束后({date})',
|
|
449
449
|
custom: '自定义取消日期',
|
|
450
|
+
timeError: '取消时间必须在当前周期内',
|
|
450
451
|
},
|
|
451
452
|
refund: {
|
|
452
453
|
title: '退款',
|
|
@@ -604,5 +605,17 @@ export default flat({
|
|
|
604
605
|
product: {
|
|
605
606
|
empty: '没有订阅产品',
|
|
606
607
|
},
|
|
608
|
+
recharge: {
|
|
609
|
+
title: '充值',
|
|
610
|
+
amount: '金额',
|
|
611
|
+
submit: '提交',
|
|
612
|
+
unsupported: '暂不支持该货币充值,请选择其他货币',
|
|
613
|
+
receiveAddress: '收款地址',
|
|
614
|
+
view: '查看订阅',
|
|
615
|
+
success: '充值成功',
|
|
616
|
+
estimatedDuration: '预计可用 {duration} {unit}',
|
|
617
|
+
custom: '自定义',
|
|
618
|
+
intervals: '个周期',
|
|
619
|
+
},
|
|
607
620
|
},
|
|
608
621
|
});
|