payment-kit 1.17.3 → 1.17.5
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/currency.ts +1 -1
- package/api/src/integrations/arcblock/nft.ts +1 -1
- package/api/src/integrations/arcblock/stake.ts +4 -3
- package/api/src/libs/constants.ts +3 -0
- package/api/src/libs/invoice.ts +6 -5
- package/api/src/libs/middleware.ts +2 -2
- package/api/src/libs/notification/template/subscription-renew-failed.ts +4 -3
- package/api/src/libs/notification/template/subscription-renewed.ts +4 -3
- package/api/src/libs/notification/template/subscription-succeeded.ts +4 -3
- package/api/src/libs/notification/template/subscription-trial-start.ts +11 -3
- package/api/src/libs/notification/template/subscription-upgraded.ts +2 -1
- package/api/src/libs/payment.ts +5 -4
- package/api/src/libs/product.ts +24 -1
- package/api/src/libs/security.ts +2 -2
- package/api/src/locales/en.ts +2 -2
- package/api/src/queues/payment.ts +7 -5
- package/api/src/queues/refund.ts +8 -6
- package/api/src/routes/connect/change-payment.ts +3 -2
- package/api/src/routes/connect/change-plan.ts +3 -2
- package/api/src/routes/connect/collect-batch.ts +5 -4
- package/api/src/routes/connect/collect.ts +6 -5
- package/api/src/routes/connect/pay.ts +9 -4
- package/api/src/routes/connect/recharge.ts +9 -4
- package/api/src/routes/connect/setup.ts +3 -2
- package/api/src/routes/connect/shared.ts +25 -7
- package/api/src/routes/connect/subscribe.ts +3 -2
- package/api/src/routes/payment-currencies.ts +11 -10
- package/api/src/routes/payment-methods.ts +35 -19
- package/api/src/routes/payment-stats.ts +9 -3
- package/api/src/routes/prices.ts +19 -1
- package/api/src/routes/products.ts +60 -28
- package/api/src/routes/subscriptions.ts +4 -3
- package/api/src/store/models/payment-method.ts +11 -8
- package/api/src/store/models/types.ts +27 -1
- package/blocklet.yml +1 -1
- package/package.json +24 -24
- package/public/methods/base.png +0 -0
- package/src/components/customer/overdraft-protection.tsx +87 -56
- package/src/components/payment-method/base.tsx +79 -0
- package/src/components/payment-method/form.tsx +3 -0
- package/src/components/price/upsell-select.tsx +1 -0
- package/src/components/subscription/metrics.tsx +1 -1
- package/src/components/subscription/portal/actions.tsx +1 -1
- package/src/libs/util.ts +1 -1
- package/src/locales/en.tsx +36 -11
- package/src/locales/zh.tsx +24 -0
- package/src/pages/admin/billing/invoices/detail.tsx +1 -1
- package/src/pages/admin/customers/customers/detail.tsx +2 -2
- package/src/pages/admin/overview.tsx +15 -2
- package/src/pages/admin/payments/intents/detail.tsx +1 -1
- package/src/pages/admin/payments/payouts/detail.tsx +1 -1
- package/src/pages/admin/payments/refunds/detail.tsx +1 -1
- package/src/pages/admin/products/links/detail.tsx +1 -0
- package/src/pages/admin/products/prices/actions.tsx +2 -1
- package/src/pages/admin/products/prices/detail.tsx +1 -0
- package/src/pages/admin/products/products/detail.tsx +1 -0
- package/src/pages/admin/settings/payment-methods/create.tsx +7 -0
- package/src/pages/admin/settings/payment-methods/index.tsx +99 -11
- package/src/pages/customer/index.tsx +1 -1
- package/src/pages/customer/invoice/detail.tsx +1 -1
- package/src/pages/customer/recharge.tsx +1 -1
- package/src/pages/customer/refund/list.tsx +7 -3
- package/src/pages/customer/subscription/change-payment.tsx +1 -1
|
@@ -64,6 +64,7 @@ import { createUsageRecordQueryFn } from './usage-records';
|
|
|
64
64
|
import { SubscriptionWillCanceledSchedule } from '../crons/subscription-will-canceled';
|
|
65
65
|
import { getTokenByAddress } from '../integrations/arcblock/stake';
|
|
66
66
|
import { ensureOverdraftProtectionPrice } from '../libs/overdraft-protection';
|
|
67
|
+
import { CHARGE_SUPPORTED_CHAIN_TYPES } from '../libs/constants';
|
|
67
68
|
|
|
68
69
|
const router = Router();
|
|
69
70
|
const auth = authenticate<Subscription>({ component: true, roles: ['owner', 'admin'] });
|
|
@@ -1766,7 +1767,7 @@ router.get('/:id/cycle-amount', authPortal, async (req, res) => {
|
|
|
1766
1767
|
|
|
1767
1768
|
if (req.query?.overdraftProtection) {
|
|
1768
1769
|
const { price } = await ensureOverdraftProtectionPrice(subscription.livemode);
|
|
1769
|
-
const invoicePrice = price
|
|
1770
|
+
const invoicePrice = (price?.currency_options || []).find((x: any) => x.currency_id === subscription?.currency_id);
|
|
1770
1771
|
const gas = invoicePrice?.unit_amount;
|
|
1771
1772
|
return res.json({
|
|
1772
1773
|
amount: new BN(maxAmount).add(new BN(gas)).toString(),
|
|
@@ -1856,7 +1857,7 @@ router.get('/:id/payer-token', authMine, async (req, res) => {
|
|
|
1856
1857
|
|
|
1857
1858
|
// @ts-ignore
|
|
1858
1859
|
const paymentAddress = getSubscriptionPaymentAddress(subscription, paymentMethod.type);
|
|
1859
|
-
if (!paymentAddress &&
|
|
1860
|
+
if (!paymentAddress && CHARGE_SUPPORTED_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
1860
1861
|
return res.status(400).json({ error: `Payer not found on subscription payment detail: ${subscription.id}` });
|
|
1861
1862
|
}
|
|
1862
1863
|
|
|
@@ -2015,7 +2016,7 @@ router.get('/:id/overdraft-protection', authPortal, async (req, res) => {
|
|
|
2015
2016
|
await isSubscriptionOverdraftProtectionEnabled(subscription);
|
|
2016
2017
|
const upcoming = await getUpcomingInvoiceAmount(req.params.id as string);
|
|
2017
2018
|
const { price } = await ensureOverdraftProtectionPrice(subscription.livemode);
|
|
2018
|
-
const invoicePrice = price
|
|
2019
|
+
const invoicePrice = (price?.currency_options || []).find((x: any) => x.currency_id === subscription?.currency_id);
|
|
2019
2020
|
const gas = invoicePrice?.unit_amount;
|
|
2020
2021
|
return res.json({
|
|
2021
2022
|
enabled,
|
|
@@ -10,6 +10,7 @@ import type { LiteralUnion } from 'type-fest';
|
|
|
10
10
|
import { STRIPE_API_VERSION, createIdGenerator } from '../../libs/util';
|
|
11
11
|
import { sequelize } from '../sequelize';
|
|
12
12
|
import type { PaymentMethodSettings } from './types';
|
|
13
|
+
import { CHARGE_SUPPORTED_CHAIN_TYPES, EVM_CHAIN_TYPES } from '../../libs/constants';
|
|
13
14
|
|
|
14
15
|
const nextId = createIdGenerator('pm', 24);
|
|
15
16
|
|
|
@@ -26,7 +27,7 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
|
|
|
26
27
|
declare livemode: boolean;
|
|
27
28
|
declare locked: boolean;
|
|
28
29
|
|
|
29
|
-
declare type: LiteralUnion<'stripe' | 'arcblock' | 'ethereum' | 'bitcoin', string>;
|
|
30
|
+
declare type: LiteralUnion<'stripe' | 'arcblock' | 'ethereum' | 'bitcoin' | 'base', string>;
|
|
30
31
|
|
|
31
32
|
declare name: string;
|
|
32
33
|
|
|
@@ -77,7 +78,7 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
|
|
|
77
78
|
defaultValue: false,
|
|
78
79
|
},
|
|
79
80
|
type: {
|
|
80
|
-
type: DataTypes.ENUM('stripe', 'arcblock', 'ethereum', 'bitcoin'),
|
|
81
|
+
type: DataTypes.ENUM('stripe', 'arcblock', 'ethereum', 'bitcoin', 'base'),
|
|
81
82
|
},
|
|
82
83
|
name: {
|
|
83
84
|
type: DataTypes.STRING(64),
|
|
@@ -209,11 +210,12 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
|
|
|
209
210
|
}
|
|
210
211
|
|
|
211
212
|
getEvmClient() {
|
|
212
|
-
if (this.type
|
|
213
|
-
throw new Error(
|
|
213
|
+
if (!EVM_CHAIN_TYPES.includes(this.type)) {
|
|
214
|
+
throw new Error(`payment method ${this.type} is not EVM compatible`);
|
|
214
215
|
}
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
|
|
217
|
+
if (!this.settings[this.type as keyof PaymentMethodSettings]) {
|
|
218
|
+
throw new Error(`payment method config insufficient for ${this.type}`);
|
|
217
219
|
}
|
|
218
220
|
|
|
219
221
|
if (evmClients.has(this.id)) {
|
|
@@ -221,7 +223,8 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
|
|
|
221
223
|
}
|
|
222
224
|
|
|
223
225
|
const settings = PaymentMethod.decryptSettings(this.settings);
|
|
224
|
-
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
const client = new ethers.JsonRpcProvider(settings[this.type as keyof PaymentMethodSettings]?.api_host);
|
|
225
228
|
evmClients.set(this.id, client);
|
|
226
229
|
|
|
227
230
|
return client as JsonRpcProvider;
|
|
@@ -229,7 +232,7 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
|
|
|
229
232
|
|
|
230
233
|
public static async supportAutoCharge(id: string) {
|
|
231
234
|
const method = await PaymentMethod.findByPk(id);
|
|
232
|
-
return method &&
|
|
235
|
+
return method && CHARGE_SUPPORTED_CHAIN_TYPES.includes(method.type);
|
|
233
236
|
}
|
|
234
237
|
}
|
|
235
238
|
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/indent */
|
|
2
2
|
import type { LiteralUnion } from 'type-fest';
|
|
3
3
|
|
|
4
|
+
export type EVMChainType = 'ethereum' | 'base';
|
|
5
|
+
|
|
6
|
+
export type NFTMintChainType = 'arcblock' | EVMChainType;
|
|
7
|
+
|
|
8
|
+
export type ChainType = 'arcblock' | 'bitcoin' | 'stripe' | EVMChainType;
|
|
9
|
+
|
|
4
10
|
export type GroupedBN = { [currencyId: string]: string };
|
|
5
11
|
export type GroupedStrList = { [currencyId: string]: string[] };
|
|
6
12
|
|
|
@@ -242,6 +248,10 @@ export type PaymentMethodOptions = {
|
|
|
242
248
|
payer: string;
|
|
243
249
|
hash?: string;
|
|
244
250
|
};
|
|
251
|
+
base?: {
|
|
252
|
+
payer: string;
|
|
253
|
+
hash?: string;
|
|
254
|
+
};
|
|
245
255
|
stripe?: {
|
|
246
256
|
payer: string;
|
|
247
257
|
};
|
|
@@ -271,6 +281,13 @@ export type PaymentMethodSettings = {
|
|
|
271
281
|
api_host: string;
|
|
272
282
|
explorer_host: string;
|
|
273
283
|
};
|
|
284
|
+
base?: {
|
|
285
|
+
chain_id: string;
|
|
286
|
+
api_host: string;
|
|
287
|
+
explorer_host: string;
|
|
288
|
+
native_symbol: string;
|
|
289
|
+
confirmation: number;
|
|
290
|
+
};
|
|
274
291
|
};
|
|
275
292
|
|
|
276
293
|
export type PaymentSettings = {
|
|
@@ -304,6 +321,14 @@ export type PaymentDetails = {
|
|
|
304
321
|
gas_price: string;
|
|
305
322
|
type?: LiteralUnion<'transfer' | 'approve', string>;
|
|
306
323
|
};
|
|
324
|
+
base?: {
|
|
325
|
+
tx_hash: string;
|
|
326
|
+
payer: string;
|
|
327
|
+
block_height: string;
|
|
328
|
+
gas_used: string;
|
|
329
|
+
gas_price: string;
|
|
330
|
+
type?: LiteralUnion<'transfer' | 'approve', string>;
|
|
331
|
+
};
|
|
307
332
|
bitcoin?: {
|
|
308
333
|
tx_hash: string;
|
|
309
334
|
payer: string;
|
|
@@ -370,9 +395,10 @@ export interface NftMintItem {
|
|
|
370
395
|
}
|
|
371
396
|
|
|
372
397
|
export type NftMintDetails = {
|
|
373
|
-
type:
|
|
398
|
+
type: NFTMintChainType;
|
|
374
399
|
arcblock?: NftMintItem;
|
|
375
400
|
ethereum?: NftMintItem;
|
|
401
|
+
base?: NftMintItem;
|
|
376
402
|
};
|
|
377
403
|
|
|
378
404
|
export type SubscriptionData = {
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.5",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -43,30 +43,30 @@
|
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@abtnode/cron": "^1.16.
|
|
47
|
-
"@arcblock/did": "^1.
|
|
46
|
+
"@abtnode/cron": "^1.16.37",
|
|
47
|
+
"@arcblock/did": "^1.19.3",
|
|
48
48
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
49
|
-
"@arcblock/did-connect": "^2.11.
|
|
50
|
-
"@arcblock/did-util": "^1.
|
|
51
|
-
"@arcblock/jwt": "^1.
|
|
52
|
-
"@arcblock/ux": "^2.11.
|
|
53
|
-
"@arcblock/validator": "^1.
|
|
54
|
-
"@blocklet/js-sdk": "^1.16.
|
|
55
|
-
"@blocklet/logger": "^1.16.
|
|
56
|
-
"@blocklet/payment-react": "1.17.
|
|
57
|
-
"@blocklet/sdk": "^1.16.
|
|
58
|
-
"@blocklet/ui-react": "^2.11.
|
|
59
|
-
"@blocklet/uploader": "^0.1.
|
|
60
|
-
"@blocklet/xss": "^0.1.
|
|
49
|
+
"@arcblock/did-connect": "^2.11.27",
|
|
50
|
+
"@arcblock/did-util": "^1.19.3",
|
|
51
|
+
"@arcblock/jwt": "^1.19.3",
|
|
52
|
+
"@arcblock/ux": "^2.11.27",
|
|
53
|
+
"@arcblock/validator": "^1.19.3",
|
|
54
|
+
"@blocklet/js-sdk": "^1.16.37",
|
|
55
|
+
"@blocklet/logger": "^1.16.37",
|
|
56
|
+
"@blocklet/payment-react": "1.17.5",
|
|
57
|
+
"@blocklet/sdk": "^1.16.37",
|
|
58
|
+
"@blocklet/ui-react": "^2.11.27",
|
|
59
|
+
"@blocklet/uploader": "^0.1.64",
|
|
60
|
+
"@blocklet/xss": "^0.1.21",
|
|
61
61
|
"@mui/icons-material": "^5.16.6",
|
|
62
62
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
63
63
|
"@mui/material": "^5.16.6",
|
|
64
64
|
"@mui/system": "^5.16.6",
|
|
65
|
-
"@ocap/asset": "^1.
|
|
66
|
-
"@ocap/client": "^1.
|
|
67
|
-
"@ocap/mcrypto": "^1.
|
|
68
|
-
"@ocap/util": "^1.
|
|
69
|
-
"@ocap/wallet": "^1.
|
|
65
|
+
"@ocap/asset": "^1.19.3",
|
|
66
|
+
"@ocap/client": "^1.19.3",
|
|
67
|
+
"@ocap/mcrypto": "^1.19.3",
|
|
68
|
+
"@ocap/util": "^1.19.3",
|
|
69
|
+
"@ocap/wallet": "^1.19.3",
|
|
70
70
|
"@stripe/react-stripe-js": "^2.7.3",
|
|
71
71
|
"@stripe/stripe-js": "^2.4.0",
|
|
72
72
|
"ahooks": "^3.8.0",
|
|
@@ -118,9 +118,9 @@
|
|
|
118
118
|
"validator": "^13.12.0"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
|
-
"@abtnode/types": "^1.16.
|
|
121
|
+
"@abtnode/types": "^1.16.37",
|
|
122
122
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
123
|
-
"@blocklet/payment-types": "1.17.
|
|
123
|
+
"@blocklet/payment-types": "1.17.5",
|
|
124
124
|
"@types/cookie-parser": "^1.4.7",
|
|
125
125
|
"@types/cors": "^2.8.17",
|
|
126
126
|
"@types/debug": "^4.1.12",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
"vite": "^5.3.5",
|
|
151
151
|
"vite-node": "^2.0.4",
|
|
152
152
|
"vite-plugin-babel-import": "^2.0.5",
|
|
153
|
-
"vite-plugin-blocklet": "^0.9.
|
|
153
|
+
"vite-plugin-blocklet": "^0.9.16",
|
|
154
154
|
"vite-plugin-node-polyfills": "^0.21.0",
|
|
155
155
|
"vite-plugin-svgr": "^4.2.0",
|
|
156
156
|
"vite-tsconfig-paths": "^4.3.2",
|
|
@@ -166,5 +166,5 @@
|
|
|
166
166
|
"parser": "typescript"
|
|
167
167
|
}
|
|
168
168
|
},
|
|
169
|
-
"gitHead": "
|
|
169
|
+
"gitHead": "7713be8272f1056796820a9d52f742ed63899900"
|
|
170
170
|
}
|
|
Binary file
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
RadioGroup,
|
|
18
18
|
Radio,
|
|
19
19
|
Link,
|
|
20
|
+
Skeleton,
|
|
20
21
|
} from '@mui/material';
|
|
21
22
|
import Dialog from '@arcblock/ux/lib/Dialog';
|
|
22
23
|
import { EventHandler, useState } from 'react';
|
|
@@ -105,6 +106,7 @@ export default function OverdraftProtectionDialog({
|
|
|
105
106
|
amount: '0',
|
|
106
107
|
gas: '0',
|
|
107
108
|
},
|
|
109
|
+
loading: cycleAmountLoading,
|
|
108
110
|
} = useRequest(
|
|
109
111
|
() =>
|
|
110
112
|
fetchCycleAmount(subscription.id, {
|
|
@@ -356,62 +358,91 @@ export default function OverdraftProtectionDialog({
|
|
|
356
358
|
</Typography>
|
|
357
359
|
|
|
358
360
|
<Grid container spacing={2} ml={-2} sx={{ mt: -1 }}>
|
|
359
|
-
{
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
height: '100%'
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
361
|
+
{cycleAmountLoading ? (
|
|
362
|
+
// 加载状态的占位
|
|
363
|
+
<>
|
|
364
|
+
{[1, 2, 3, 4, 5].map((key) => (
|
|
365
|
+
<Grid item xs={6} sm={4} key={key}>
|
|
366
|
+
<Card variant="outlined" sx={{ height: '100%' }}>
|
|
367
|
+
<CardActionArea sx={{ height: '100%', p: 1 }}>
|
|
368
|
+
<Stack spacing={1} alignItems="center">
|
|
369
|
+
<Skeleton variant="rectangular" width={80} height={32} />
|
|
370
|
+
<Skeleton width={100} />
|
|
371
|
+
</Stack>
|
|
372
|
+
</CardActionArea>
|
|
373
|
+
</Card>
|
|
374
|
+
</Grid>
|
|
375
|
+
))}
|
|
376
|
+
<Grid item xs={6} sm={4}>
|
|
377
|
+
<Card variant="outlined" sx={{ height: '100%' }}>
|
|
378
|
+
<CardActionArea sx={{ height: '100%', p: 2 }}>
|
|
379
|
+
<Stack spacing={1} alignItems="center">
|
|
380
|
+
<Skeleton variant="rectangular" width={80} height={24} />
|
|
381
|
+
</Stack>
|
|
382
|
+
</CardActionArea>
|
|
383
|
+
</Card>
|
|
384
|
+
</Grid>
|
|
385
|
+
</>
|
|
386
|
+
) : (
|
|
387
|
+
<>
|
|
388
|
+
{presetAmounts.map(({ amount: presetAmount, cycles }) => (
|
|
389
|
+
<Grid item xs={6} sm={4} key={presetAmount}>
|
|
390
|
+
<Card
|
|
391
|
+
variant="outlined"
|
|
392
|
+
sx={{
|
|
393
|
+
height: '100%',
|
|
394
|
+
transition: 'all 0.3s',
|
|
395
|
+
cursor: 'pointer',
|
|
396
|
+
'&:hover': {
|
|
397
|
+
transform: 'translateY(-4px)',
|
|
398
|
+
boxShadow: 3,
|
|
399
|
+
},
|
|
400
|
+
...(amount === presetAmount && !customAmount
|
|
401
|
+
? { borderColor: 'primary.main', borderWidth: 2 }
|
|
402
|
+
: {}),
|
|
403
|
+
}}>
|
|
404
|
+
<CardActionArea
|
|
405
|
+
onClick={() => {
|
|
406
|
+
methods.setValue('amount', presetAmount);
|
|
407
|
+
setCustomAmount(false);
|
|
408
|
+
}}
|
|
409
|
+
sx={{ height: '100%', p: 1 }}>
|
|
410
|
+
<Stack spacing={1} alignItems="center">
|
|
411
|
+
<Typography variant="h6" sx={{ fontWeight: 600 }}>
|
|
412
|
+
{presetAmount} {currency.symbol}
|
|
413
|
+
</Typography>
|
|
414
|
+
<Typography variant="caption" color="text.secondary">
|
|
415
|
+
{formatEstimatedDuration(cycles)}
|
|
416
|
+
</Typography>
|
|
417
|
+
</Stack>
|
|
418
|
+
</CardActionArea>
|
|
419
|
+
</Card>
|
|
420
|
+
</Grid>
|
|
421
|
+
))}
|
|
422
|
+
<Grid item xs={6} sm={4}>
|
|
423
|
+
<Card
|
|
424
|
+
variant="outlined"
|
|
425
|
+
sx={{
|
|
426
|
+
height: '100%',
|
|
427
|
+
transition: 'all 0.3s',
|
|
428
|
+
cursor: 'pointer',
|
|
429
|
+
'&:hover': {
|
|
430
|
+
transform: 'translateY(-4px)',
|
|
431
|
+
boxShadow: 3,
|
|
432
|
+
},
|
|
433
|
+
...(customAmount ? { borderColor: 'primary.main', borderWidth: 2 } : {}),
|
|
434
|
+
}}>
|
|
435
|
+
<CardActionArea onClick={handleCustomSelect} sx={{ height: '100%', p: 2 }}>
|
|
436
|
+
<Stack spacing={1} alignItems="center">
|
|
437
|
+
<Typography variant="h6" sx={{ fontWeight: 600 }}>
|
|
438
|
+
{t('common.custom')}
|
|
439
|
+
</Typography>
|
|
440
|
+
</Stack>
|
|
441
|
+
</CardActionArea>
|
|
442
|
+
</Card>
|
|
443
|
+
</Grid>
|
|
444
|
+
</>
|
|
445
|
+
)}
|
|
415
446
|
</Grid>
|
|
416
447
|
|
|
417
448
|
{customAmount && (
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint-disable no-nested-ternary */
|
|
2
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
|
+
import { FormInput } from '@blocklet/payment-react';
|
|
4
|
+
import { Stack, Typography } from '@mui/material';
|
|
5
|
+
import { useFormContext, useWatch } from 'react-hook-form';
|
|
6
|
+
|
|
7
|
+
import Uploader from '../uploader';
|
|
8
|
+
|
|
9
|
+
export default function BaseMethodForm() {
|
|
10
|
+
const { t } = useLocaleContext();
|
|
11
|
+
const { control, setValue } = useFormContext();
|
|
12
|
+
const logo = useWatch({ control, name: 'logo' });
|
|
13
|
+
|
|
14
|
+
const onUploaded = (result: any) => {
|
|
15
|
+
if (!result.url) {
|
|
16
|
+
setValue('logo', '');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const tmp = new URL(result.url);
|
|
20
|
+
setValue('logo', tmp.pathname);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<FormInput
|
|
26
|
+
key="name"
|
|
27
|
+
name="name"
|
|
28
|
+
type="text"
|
|
29
|
+
rules={{ required: true }}
|
|
30
|
+
label={t('admin.paymentMethod.name.label')}
|
|
31
|
+
placeholder={t('admin.paymentMethod.name.tip')}
|
|
32
|
+
/>
|
|
33
|
+
<FormInput
|
|
34
|
+
key="description"
|
|
35
|
+
name="description"
|
|
36
|
+
type="text"
|
|
37
|
+
rules={{ required: true }}
|
|
38
|
+
label={t('admin.paymentMethod.description.label')}
|
|
39
|
+
placeholder={t('admin.paymentMethod.description.tip')}
|
|
40
|
+
/>
|
|
41
|
+
<FormInput
|
|
42
|
+
key="api_host"
|
|
43
|
+
name="settings.base.api_host"
|
|
44
|
+
type="text"
|
|
45
|
+
rules={{ required: true }}
|
|
46
|
+
label={t('admin.paymentMethod.base.api_host.label')}
|
|
47
|
+
placeholder={t('admin.paymentMethod.base.api_host.tip')}
|
|
48
|
+
/>
|
|
49
|
+
<FormInput
|
|
50
|
+
key="explorer_host"
|
|
51
|
+
name="settings.base.explorer_host"
|
|
52
|
+
type="text"
|
|
53
|
+
rules={{ required: true }}
|
|
54
|
+
label={t('admin.paymentMethod.base.explorer_host.label')}
|
|
55
|
+
placeholder={t('admin.paymentMethod.base.explorer_host.tip')}
|
|
56
|
+
/>
|
|
57
|
+
<FormInput
|
|
58
|
+
key="native_symbol"
|
|
59
|
+
name="settings.base.native_symbol"
|
|
60
|
+
type="text"
|
|
61
|
+
rules={{ required: true }}
|
|
62
|
+
label={t('admin.paymentMethod.base.native_symbol.label')}
|
|
63
|
+
placeholder={t('admin.paymentMethod.base.native_symbol.tip')}
|
|
64
|
+
/>
|
|
65
|
+
<FormInput
|
|
66
|
+
key="confirmation"
|
|
67
|
+
name="settings.base.confirmation"
|
|
68
|
+
type="number"
|
|
69
|
+
rules={{ required: true }}
|
|
70
|
+
label={t('admin.paymentMethod.base.confirmation.label')}
|
|
71
|
+
placeholder={t('admin.paymentMethod.base.confirmation.tip')}
|
|
72
|
+
/>
|
|
73
|
+
<Stack direction="column">
|
|
74
|
+
<Typography mb={1}>{t('admin.paymentCurrency.logo.label')}</Typography>
|
|
75
|
+
<Uploader onUploaded={onUploaded} preview={logo} />
|
|
76
|
+
</Stack>
|
|
77
|
+
</>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -7,6 +7,7 @@ import ArcBlockMethodForm from './arcblock';
|
|
|
7
7
|
import BitcoinMethodForm from './bitcoin';
|
|
8
8
|
import EthereumMethodForm from './ethereum';
|
|
9
9
|
import StripeMethodForm from './stripe';
|
|
10
|
+
import BaseMethodForm from './base';
|
|
10
11
|
|
|
11
12
|
export default function PaymentMethodForm() {
|
|
12
13
|
const { t } = useLocaleContext();
|
|
@@ -31,6 +32,7 @@ export default function PaymentMethodForm() {
|
|
|
31
32
|
<ToggleButton value="arcblock">ArcBlock</ToggleButton>
|
|
32
33
|
<ToggleButton value="stripe">Stripe</ToggleButton>
|
|
33
34
|
<ToggleButton value="ethereum">Ethereum</ToggleButton>
|
|
35
|
+
<ToggleButton value="base">Base</ToggleButton>
|
|
34
36
|
<ToggleButton value="bitcoin" disabled>
|
|
35
37
|
Bitcoin
|
|
36
38
|
</ToggleButton>
|
|
@@ -43,6 +45,7 @@ export default function PaymentMethodForm() {
|
|
|
43
45
|
{type === 'stripe' && <StripeMethodForm />}
|
|
44
46
|
{type === 'arcblock' && <ArcBlockMethodForm />}
|
|
45
47
|
{type === 'ethereum' && <EthereumMethodForm />}
|
|
48
|
+
{type === 'base' && <BaseMethodForm />}
|
|
46
49
|
{type === 'bitcoin' && <BitcoinMethodForm />}
|
|
47
50
|
</Root>
|
|
48
51
|
);
|
|
@@ -32,7 +32,7 @@ export default function SubscriptionMetrics({ subscription, showBalance = true }
|
|
|
32
32
|
ready: showBalance,
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
const supportShowBalance = showBalance && ['arcblock', 'ethereum'].includes(subscription.paymentMethod.type);
|
|
35
|
+
const supportShowBalance = showBalance && ['arcblock', 'ethereum', 'base'].includes(subscription.paymentMethod.type);
|
|
36
36
|
// let scheduleToCancelTime = 0;
|
|
37
37
|
// if (['active', 'trialing', 'past_due'].includes(subscription.status) && subscription.cancel_at) {
|
|
38
38
|
// scheduleToCancelTime = subscription.cancel_at * 1000;
|
|
@@ -121,7 +121,7 @@ const fetchExtraActions = async ({
|
|
|
121
121
|
const supportRecharge = (subscription: TSubscriptionExpanded) => {
|
|
122
122
|
return (
|
|
123
123
|
['active', 'trialing', 'past_due'].includes(subscription?.status) &&
|
|
124
|
-
['arcblock', 'ethereum'].includes(subscription?.paymentMethod?.type)
|
|
124
|
+
['arcblock', 'ethereum', 'base'].includes(subscription?.paymentMethod?.type)
|
|
125
125
|
);
|
|
126
126
|
};
|
|
127
127
|
|
package/src/libs/util.ts
CHANGED
|
@@ -310,7 +310,7 @@ export function getInvoiceUsageReportStartEnd(invoice: TInvoiceExpanded, showPre
|
|
|
310
310
|
}
|
|
311
311
|
const cycle = getRecurringPeriod(subscription.pending_invoice_item_interval);
|
|
312
312
|
let offset = 0;
|
|
313
|
-
if (['arcblock', 'ethereum'].includes(paymentMethod.type)) {
|
|
313
|
+
if (['arcblock', 'ethereum', 'base'].includes(paymentMethod.type)) {
|
|
314
314
|
switch (invoice?.billing_reason) {
|
|
315
315
|
case 'subscription_cycle':
|
|
316
316
|
offset = cycle / 1000;
|