payment-kit 1.20.22 → 1.21.1
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/libs/notification/template/subscription-renew-failed.ts +19 -17
- package/api/src/libs/notification/template/subscription-will-renew.ts +19 -17
- package/api/src/libs/vendor-util/adapters/launcher-adapter.ts +7 -6
- package/api/src/libs/vendor-util/adapters/types.ts +2 -2
- package/api/src/libs/vendor-util/fulfillment.ts +1 -1
- package/api/src/routes/vendor.ts +13 -7
- package/blocklet.yml +1 -1
- package/package.json +19 -19
- package/src/locales/en.tsx +37 -0
- package/src/locales/zh.tsx +33 -0
- package/src/pages/integrations/overview.tsx +148 -6
|
@@ -234,23 +234,25 @@ export class SubscriptionRenewFailedEmailTemplate
|
|
|
234
234
|
text: productName,
|
|
235
235
|
},
|
|
236
236
|
},
|
|
237
|
-
...(payer
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
237
|
+
...(payer
|
|
238
|
+
? [
|
|
239
|
+
{
|
|
240
|
+
type: 'text',
|
|
241
|
+
data: {
|
|
242
|
+
type: 'plain',
|
|
243
|
+
color: '#9397A1',
|
|
244
|
+
text: translate('notification.common.payer', locale),
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
type: 'text',
|
|
249
|
+
data: {
|
|
250
|
+
type: 'plain',
|
|
251
|
+
text: payer,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
]
|
|
255
|
+
: []),
|
|
254
256
|
{
|
|
255
257
|
type: 'text',
|
|
256
258
|
data: {
|
|
@@ -390,23 +390,25 @@ export class SubscriptionWillRenewEmailTemplate extends BaseSubscriptionEmailTem
|
|
|
390
390
|
type: 'section',
|
|
391
391
|
fields: [
|
|
392
392
|
...commonFields,
|
|
393
|
-
...(payer
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
393
|
+
...(payer
|
|
394
|
+
? [
|
|
395
|
+
{
|
|
396
|
+
type: 'text',
|
|
397
|
+
data: {
|
|
398
|
+
type: 'plain',
|
|
399
|
+
color: '#9397A1',
|
|
400
|
+
text: translate('notification.common.payer', locale),
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
type: 'text',
|
|
405
|
+
data: {
|
|
406
|
+
type: 'plain',
|
|
407
|
+
text: payer,
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
]
|
|
411
|
+
: []),
|
|
410
412
|
...renewAmountFields,
|
|
411
413
|
...balanceFields,
|
|
412
414
|
...insufficientBalanceFields,
|
|
@@ -17,10 +17,11 @@ import {
|
|
|
17
17
|
} from './types';
|
|
18
18
|
import { formatVendorUrl } from './util';
|
|
19
19
|
|
|
20
|
-
const doRequestVendorData = (vendor: ProductVendor, orderId: string, url: string) => {
|
|
20
|
+
const doRequestVendorData = (vendor: ProductVendor, orderId: string, url: string, options: { shortUrl: boolean }) => {
|
|
21
21
|
const { headers } = VendorAuth.signRequestWithHeaders({});
|
|
22
22
|
const name = vendor?.name;
|
|
23
23
|
const key = vendor?.vendor_key;
|
|
24
|
+
const { shortUrl } = options;
|
|
24
25
|
|
|
25
26
|
return fetch(url, { headers })
|
|
26
27
|
.then(async (r) => {
|
|
@@ -38,7 +39,7 @@ const doRequestVendorData = (vendor: ProductVendor, orderId: string, url: string
|
|
|
38
39
|
`vendor status fetch failed, vendor: ${vendor.vendor_key}, orderId: ${orderId}, status: ${r.status}, url: ${url}`
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
|
-
if (!data.dashboardUrl) {
|
|
42
|
+
if (!shortUrl || !data.dashboardUrl) {
|
|
42
43
|
return {
|
|
43
44
|
...data,
|
|
44
45
|
name,
|
|
@@ -255,15 +256,15 @@ export class LauncherAdapter implements VendorAdapter {
|
|
|
255
256
|
}
|
|
256
257
|
}
|
|
257
258
|
|
|
258
|
-
getOrderStatus(vendor: ProductVendor, orderId: string): Promise<any> {
|
|
259
|
+
getOrderStatus(vendor: ProductVendor, orderId: string, options: { shortUrl: boolean }): Promise<any> {
|
|
259
260
|
const url = formatVendorUrl(vendor, `/api/vendor/status/${orderId}`);
|
|
260
261
|
|
|
261
|
-
return doRequestVendorData(vendor, orderId, url);
|
|
262
|
+
return doRequestVendorData(vendor, orderId, url, options);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
getOrder(vendor: ProductVendor, orderId: string): Promise<any> {
|
|
265
|
+
getOrder(vendor: ProductVendor, orderId: string, options: { shortUrl: boolean }): Promise<any> {
|
|
265
266
|
const url = formatVendorUrl(vendor, `/api/vendor/orders/${orderId}`);
|
|
266
267
|
|
|
267
|
-
return doRequestVendorData(vendor, orderId, url);
|
|
268
|
+
return doRequestVendorData(vendor, orderId, url, options);
|
|
268
269
|
}
|
|
269
270
|
}
|
|
@@ -87,6 +87,6 @@ export interface VendorAdapter {
|
|
|
87
87
|
fulfillOrder(params: FulfillOrderParams): Promise<FulfillOrderResult>;
|
|
88
88
|
requestReturn(params: ReturnRequestParams): Promise<ReturnRequestResult>;
|
|
89
89
|
checkOrderStatus(params: CheckOrderStatusParams): Promise<CheckOrderStatusResult>;
|
|
90
|
-
getOrder(vendor: ProductVendor, orderId: string): Promise<any>;
|
|
91
|
-
getOrderStatus(vendor: ProductVendor, orderId: string): Promise<any>;
|
|
90
|
+
getOrder(vendor: ProductVendor, orderId: string, option?: Record<string, any>): Promise<any>;
|
|
91
|
+
getOrderStatus(vendor: ProductVendor, orderId: string, option?: Record<string, any>): Promise<any>;
|
|
92
92
|
}
|
|
@@ -158,7 +158,7 @@ export class VendorFulfillmentService {
|
|
|
158
158
|
destination,
|
|
159
159
|
amount: result.commissionAmount,
|
|
160
160
|
currency_id: checkoutSession.currency_id,
|
|
161
|
-
customer_id:
|
|
161
|
+
customer_id: '',
|
|
162
162
|
payment_intent_id: paymentIntentId,
|
|
163
163
|
payment_method_id: paymentMethodId,
|
|
164
164
|
status: paymentMethod?.type === 'stripe' ? 'deferred' : 'pending',
|
package/api/src/routes/vendor.ts
CHANGED
|
@@ -316,7 +316,12 @@ async function testVendorConnection(req: any, res: any) {
|
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
async function executeVendorOperation(
|
|
319
|
+
async function executeVendorOperation(
|
|
320
|
+
vendorId: string,
|
|
321
|
+
orderId: string,
|
|
322
|
+
operation: 'getOrder' | 'getOrderStatus',
|
|
323
|
+
shortUrl: boolean
|
|
324
|
+
) {
|
|
320
325
|
if (!vendorId || !orderId) {
|
|
321
326
|
return {
|
|
322
327
|
error: 'Bad Request',
|
|
@@ -336,7 +341,7 @@ async function executeVendorOperation(vendorId: string, orderId: string, operati
|
|
|
336
341
|
|
|
337
342
|
try {
|
|
338
343
|
const vendorAdapter = await VendorFulfillmentService.getVendorAdapter(vendor.vendor_key);
|
|
339
|
-
const data = await vendorAdapter[operation](vendor, orderId);
|
|
344
|
+
const data = await vendorAdapter[operation](vendor, orderId, { shortUrl });
|
|
340
345
|
|
|
341
346
|
return { data: { ...data, vendorType: vendor.vendor_type }, code: 200 };
|
|
342
347
|
} catch (error: any) {
|
|
@@ -355,7 +360,7 @@ async function executeVendorOperation(vendorId: string, orderId: string, operati
|
|
|
355
360
|
}
|
|
356
361
|
}
|
|
357
362
|
|
|
358
|
-
async function processVendorOrders(sessionId: string, operation: 'getOrder' | 'getOrderStatus') {
|
|
363
|
+
async function processVendorOrders(sessionId: string, operation: 'getOrder' | 'getOrderStatus', shortUrl: boolean) {
|
|
359
364
|
const doc = await CheckoutSession.findByPk(sessionId);
|
|
360
365
|
|
|
361
366
|
if (!doc) {
|
|
@@ -397,7 +402,7 @@ async function processVendorOrders(sessionId: string, operation: 'getOrder' | 'g
|
|
|
397
402
|
};
|
|
398
403
|
}
|
|
399
404
|
|
|
400
|
-
const result = await executeVendorOperation(item.vendor_id, item.order_id, operation);
|
|
405
|
+
const result = await executeVendorOperation(item.vendor_id, item.order_id, operation, shortUrl);
|
|
401
406
|
|
|
402
407
|
// Handle error responses from vendor functions
|
|
403
408
|
if (result.error) {
|
|
@@ -431,7 +436,7 @@ async function processVendorOrders(sessionId: string, operation: 'getOrder' | 'g
|
|
|
431
436
|
}
|
|
432
437
|
|
|
433
438
|
async function getVendorStatus(sessionId: string) {
|
|
434
|
-
const result: any = await processVendorOrders(sessionId, 'getOrderStatus');
|
|
439
|
+
const result: any = await processVendorOrders(sessionId, 'getOrderStatus', false);
|
|
435
440
|
|
|
436
441
|
if (result.subscriptionId) {
|
|
437
442
|
const subscriptionUrl = getUrl(`/customer/subscription/${result.subscriptionId}`);
|
|
@@ -463,9 +468,10 @@ async function getVendorFulfillmentStatus(req: any, res: any) {
|
|
|
463
468
|
|
|
464
469
|
async function getVendorFulfillmentDetail(req: any, res: any) {
|
|
465
470
|
const { sessionId } = req.params;
|
|
471
|
+
const { shortUrl } = req.query;
|
|
466
472
|
|
|
467
473
|
try {
|
|
468
|
-
const detail = await processVendorOrders(sessionId, 'getOrder');
|
|
474
|
+
const detail = await processVendorOrders(sessionId, 'getOrder', shortUrl === 'true');
|
|
469
475
|
if (detail.code) {
|
|
470
476
|
return res.status(detail.code).json({ error: detail.error });
|
|
471
477
|
}
|
|
@@ -505,7 +511,7 @@ async function redirectToVendor(req: any, res: any) {
|
|
|
505
511
|
return res.redirect('/404');
|
|
506
512
|
}
|
|
507
513
|
|
|
508
|
-
const result = await executeVendorOperation(vendorId, order.order_id || '', 'getOrder');
|
|
514
|
+
const result = await executeVendorOperation(vendorId, order.order_id || '', 'getOrder', false);
|
|
509
515
|
if (result.error || !result.data) {
|
|
510
516
|
logger.warn('Vendor status detail not found', {
|
|
511
517
|
subscriptionId,
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"lint": "tsc --noEmit && eslint src api/src --ext .mjs,.js,.jsx,.ts,.tsx",
|
|
@@ -45,33 +45,33 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@abtnode/cron": "^1.16.52-beta-20250912-112002-e3499e9c",
|
|
48
|
-
"@arcblock/did": "^1.25.
|
|
49
|
-
"@arcblock/did-connect-react": "^3.1.
|
|
48
|
+
"@arcblock/did": "^1.25.5",
|
|
49
|
+
"@arcblock/did-connect-react": "^3.1.43",
|
|
50
50
|
"@arcblock/did-connect-storage-nedb": "^1.8.0",
|
|
51
|
-
"@arcblock/did-util": "^1.25.
|
|
52
|
-
"@arcblock/jwt": "^1.25.
|
|
53
|
-
"@arcblock/ux": "^3.1.
|
|
54
|
-
"@arcblock/validator": "^1.25.
|
|
51
|
+
"@arcblock/did-util": "^1.25.5",
|
|
52
|
+
"@arcblock/jwt": "^1.25.5",
|
|
53
|
+
"@arcblock/ux": "^3.1.43",
|
|
54
|
+
"@arcblock/validator": "^1.25.5",
|
|
55
55
|
"@blocklet/did-space-js": "^1.1.27",
|
|
56
56
|
"@blocklet/error": "^0.2.5",
|
|
57
57
|
"@blocklet/js-sdk": "^1.16.52-beta-20250912-112002-e3499e9c",
|
|
58
58
|
"@blocklet/logger": "^1.16.52-beta-20250912-112002-e3499e9c",
|
|
59
|
-
"@blocklet/payment-broker-client": "1.
|
|
60
|
-
"@blocklet/payment-react": "1.
|
|
61
|
-
"@blocklet/payment-vendor": "1.
|
|
59
|
+
"@blocklet/payment-broker-client": "1.21.1",
|
|
60
|
+
"@blocklet/payment-react": "1.21.1",
|
|
61
|
+
"@blocklet/payment-vendor": "1.21.1",
|
|
62
62
|
"@blocklet/sdk": "^1.16.52-beta-20250912-112002-e3499e9c",
|
|
63
|
-
"@blocklet/ui-react": "^3.1.
|
|
63
|
+
"@blocklet/ui-react": "^3.1.43",
|
|
64
64
|
"@blocklet/uploader": "^0.2.12",
|
|
65
|
-
"@blocklet/xss": "^0.2.
|
|
65
|
+
"@blocklet/xss": "^0.2.9",
|
|
66
66
|
"@mui/icons-material": "^7.1.2",
|
|
67
67
|
"@mui/lab": "7.0.0-beta.14",
|
|
68
68
|
"@mui/material": "^7.1.2",
|
|
69
69
|
"@mui/system": "^7.1.1",
|
|
70
|
-
"@ocap/asset": "^1.25.
|
|
71
|
-
"@ocap/client": "^1.25.
|
|
72
|
-
"@ocap/mcrypto": "^1.25.
|
|
73
|
-
"@ocap/util": "^1.25.
|
|
74
|
-
"@ocap/wallet": "^1.25.
|
|
70
|
+
"@ocap/asset": "^1.25.5",
|
|
71
|
+
"@ocap/client": "^1.25.5",
|
|
72
|
+
"@ocap/mcrypto": "^1.25.5",
|
|
73
|
+
"@ocap/util": "^1.25.5",
|
|
74
|
+
"@ocap/wallet": "^1.25.5",
|
|
75
75
|
"@stripe/react-stripe-js": "^2.9.0",
|
|
76
76
|
"@stripe/stripe-js": "^2.4.0",
|
|
77
77
|
"ahooks": "^3.8.5",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"devDependencies": {
|
|
129
129
|
"@abtnode/types": "^1.16.52-beta-20250912-112002-e3499e9c",
|
|
130
130
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
131
|
-
"@blocklet/payment-types": "1.
|
|
131
|
+
"@blocklet/payment-types": "1.21.1",
|
|
132
132
|
"@types/cookie-parser": "^1.4.9",
|
|
133
133
|
"@types/cors": "^2.8.19",
|
|
134
134
|
"@types/debug": "^4.1.12",
|
|
@@ -175,5 +175,5 @@
|
|
|
175
175
|
"parser": "typescript"
|
|
176
176
|
}
|
|
177
177
|
},
|
|
178
|
-
"gitHead": "
|
|
178
|
+
"gitHead": "2501d7ffa66139179361f988e4129ee6c0379f76"
|
|
179
179
|
}
|
package/src/locales/en.tsx
CHANGED
|
@@ -94,6 +94,7 @@ export default flat({
|
|
|
94
94
|
promotional: 'Promotional',
|
|
95
95
|
viewInvoice: 'View Invoice',
|
|
96
96
|
viewSourceData: 'View Source',
|
|
97
|
+
goToConfigure: 'Go to Configure',
|
|
97
98
|
},
|
|
98
99
|
notification: {
|
|
99
100
|
preferences: {
|
|
@@ -1685,6 +1686,41 @@ export default flat({
|
|
|
1685
1686
|
title: 'Pricing Tables',
|
|
1686
1687
|
intro: 'Create beautiful pricing tables for your products',
|
|
1687
1688
|
},
|
|
1689
|
+
metering: {
|
|
1690
|
+
title: 'Usage Metering',
|
|
1691
|
+
intro: 'Track usage with meters and sell credits as top-up packages',
|
|
1692
|
+
dialog: {
|
|
1693
|
+
title: 'How to set up credit-based metering',
|
|
1694
|
+
description:
|
|
1695
|
+
'Credit-based metering allows you to track usage and charge customers based on consumption. Follow these steps to get started:',
|
|
1696
|
+
steps: {
|
|
1697
|
+
step1: {
|
|
1698
|
+
title: 'Create a meter to track your usage events',
|
|
1699
|
+
description:
|
|
1700
|
+
'Set up meters to monitor API calls, data usage, or any measurable activity in your application.',
|
|
1701
|
+
},
|
|
1702
|
+
step2: {
|
|
1703
|
+
title: 'Create Credit top-up products and pricing',
|
|
1704
|
+
description:
|
|
1705
|
+
'Define credit packages that customers can purchase, with flexible pricing models and validity periods.',
|
|
1706
|
+
},
|
|
1707
|
+
step3: {
|
|
1708
|
+
title: 'Create a payment link and share it so users can buy Credits',
|
|
1709
|
+
description: 'Generate shareable payment links that allow customers to easily purchase credit packages.',
|
|
1710
|
+
},
|
|
1711
|
+
step4: {
|
|
1712
|
+
title: 'Integrate and report Credit usage',
|
|
1713
|
+
description:
|
|
1714
|
+
'Use our SDK to report usage events and automatically deduct credits from customer balances.',
|
|
1715
|
+
},
|
|
1716
|
+
},
|
|
1717
|
+
docText: 'Read the credit billing guide',
|
|
1718
|
+
},
|
|
1719
|
+
},
|
|
1720
|
+
promotions: {
|
|
1721
|
+
title: 'Promotions',
|
|
1722
|
+
intro: 'Create coupons and promotion codes to drive conversions',
|
|
1723
|
+
},
|
|
1688
1724
|
donate: {
|
|
1689
1725
|
title: 'Donation',
|
|
1690
1726
|
intro: 'Add donation button to your application with <CheckoutDonate />',
|
|
@@ -1699,5 +1735,6 @@ export default flat({
|
|
|
1699
1735
|
link: 'https://www.npmjs.com/package/@blocklet/payment-js',
|
|
1700
1736
|
},
|
|
1701
1737
|
},
|
|
1738
|
+
viewDocs: 'View docs',
|
|
1702
1739
|
},
|
|
1703
1740
|
});
|
package/src/locales/zh.tsx
CHANGED
|
@@ -93,6 +93,7 @@ export default flat({
|
|
|
93
93
|
promotional: '促销',
|
|
94
94
|
viewInvoice: '查看账单',
|
|
95
95
|
viewSourceData: '查看来源',
|
|
96
|
+
goToConfigure: '前往配置',
|
|
96
97
|
},
|
|
97
98
|
notification: {
|
|
98
99
|
preferences: {
|
|
@@ -1632,6 +1633,37 @@ export default flat({
|
|
|
1632
1633
|
title: '定价表',
|
|
1633
1634
|
intro: '为您的产品创建美观的定价表',
|
|
1634
1635
|
},
|
|
1636
|
+
metering: {
|
|
1637
|
+
title: '计量与额度',
|
|
1638
|
+
intro: '使用计量器跟踪用量,并通过额度套餐售卖 Credits',
|
|
1639
|
+
dialog: {
|
|
1640
|
+
title: '如何开启 Credit 计费',
|
|
1641
|
+
description: 'Credit 计费模式让您可以跟踪用量并基于消费向客户收费。按照以下步骤开始配置:',
|
|
1642
|
+
steps: {
|
|
1643
|
+
step1: {
|
|
1644
|
+
title: '创建计量器用于跟踪用量事件',
|
|
1645
|
+
description: '设置计量器来监控 API 调用、数据使用量或应用中任何可测量的活动。',
|
|
1646
|
+
},
|
|
1647
|
+
step2: {
|
|
1648
|
+
title: '创建 Credits 购买套餐和定价',
|
|
1649
|
+
description: '定义客户可以购买的额度套餐,支持灵活的定价模式和有效期设置。',
|
|
1650
|
+
},
|
|
1651
|
+
step3: {
|
|
1652
|
+
title: '创建支付链接并分享给用户',
|
|
1653
|
+
description: '生成可分享的支付链接,让客户轻松购买额度套餐。',
|
|
1654
|
+
},
|
|
1655
|
+
step4: {
|
|
1656
|
+
title: '集成并上报 Credits 用量',
|
|
1657
|
+
description: '使用我们的 SDK 上报使用事件,自动从客户余额中扣除额度。',
|
|
1658
|
+
},
|
|
1659
|
+
},
|
|
1660
|
+
docText: '查看 Credit 计费指南',
|
|
1661
|
+
},
|
|
1662
|
+
},
|
|
1663
|
+
promotions: {
|
|
1664
|
+
title: '促销与优惠',
|
|
1665
|
+
intro: '创建优惠券与促销码,提升转化率',
|
|
1666
|
+
},
|
|
1635
1667
|
donate: {
|
|
1636
1668
|
title: '打赏功能',
|
|
1637
1669
|
intro: '使用 <CheckoutDonate /> 组件为应用添加打赏按钮',
|
|
@@ -1646,5 +1678,6 @@ export default flat({
|
|
|
1646
1678
|
link: 'https://www.npmjs.com/package/@blocklet/payment-js',
|
|
1647
1679
|
},
|
|
1648
1680
|
},
|
|
1681
|
+
viewDocs: '查看文档',
|
|
1649
1682
|
},
|
|
1650
1683
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
-
import { Box, Grid, Typography, Divider } from '@mui/material';
|
|
2
|
+
import { Box, Grid, Typography, Divider, Button, Link, Tooltip } from '@mui/material';
|
|
3
|
+
import Dialog from '@arcblock/ux/lib/Dialog';
|
|
3
4
|
import { useNavigate } from 'react-router-dom';
|
|
4
5
|
import {
|
|
5
6
|
Link as LinkIcon,
|
|
@@ -8,7 +9,11 @@ import {
|
|
|
8
9
|
Inventory2Outlined,
|
|
9
10
|
TableChartOutlined,
|
|
10
11
|
FavoriteBorderOutlined,
|
|
12
|
+
Speed,
|
|
13
|
+
LocalOfferOutlined,
|
|
14
|
+
HelpOutline,
|
|
11
15
|
} from '@mui/icons-material';
|
|
16
|
+
import { useState } from 'react';
|
|
12
17
|
|
|
13
18
|
const basicFeatures = [
|
|
14
19
|
{
|
|
@@ -32,6 +37,24 @@ const basicFeatures = [
|
|
|
32
37
|
];
|
|
33
38
|
|
|
34
39
|
const advancedFeatures = [
|
|
40
|
+
{
|
|
41
|
+
title: 'integrations.features.metering.title',
|
|
42
|
+
description: 'integrations.features.metering.intro',
|
|
43
|
+
icon: <Speed sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
44
|
+
dialog: 'metering',
|
|
45
|
+
doc: {
|
|
46
|
+
url: 'https://www.arcblock.io/blog/en/payment-kit-enhanced-credit-management',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
title: 'integrations.features.promotions.title',
|
|
51
|
+
description: 'integrations.features.promotions.intro',
|
|
52
|
+
icon: <LocalOfferOutlined sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
53
|
+
path: '/admin/products/coupons',
|
|
54
|
+
doc: {
|
|
55
|
+
url: 'https://www.arcblock.io/content/blog/en/payment-kit-promotion-support',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
35
58
|
{
|
|
36
59
|
title: 'integrations.features.donate.title',
|
|
37
60
|
description: 'integrations.features.donate.intro',
|
|
@@ -48,7 +71,7 @@ const advancedFeatures = [
|
|
|
48
71
|
title: 'integrations.features.api.title',
|
|
49
72
|
description: 'integrations.features.api.intro',
|
|
50
73
|
icon: <Code sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
51
|
-
path: 'https://www.arcblock.io/docs/
|
|
74
|
+
path: 'https://www.staging.arcblock.io/content/docs/payment-kit-sdk',
|
|
52
75
|
external: true,
|
|
53
76
|
},
|
|
54
77
|
];
|
|
@@ -56,8 +79,13 @@ const advancedFeatures = [
|
|
|
56
79
|
export default function Overview() {
|
|
57
80
|
const { t } = useLocaleContext();
|
|
58
81
|
const navigate = useNavigate();
|
|
82
|
+
const [openMeterDialog, setOpenMeterDialog] = useState(false);
|
|
59
83
|
|
|
60
84
|
const handleClick = (item: any) => {
|
|
85
|
+
if (item.dialog === 'metering') {
|
|
86
|
+
setOpenMeterDialog(true);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
61
89
|
if (item.external) {
|
|
62
90
|
window.open(item.path, '_blank');
|
|
63
91
|
} else {
|
|
@@ -179,13 +207,37 @@ export default function Overview() {
|
|
|
179
207
|
mb: 1,
|
|
180
208
|
}}>
|
|
181
209
|
{item.icon}
|
|
182
|
-
<
|
|
183
|
-
variant="h4"
|
|
210
|
+
<Box
|
|
184
211
|
sx={{
|
|
212
|
+
display: 'flex',
|
|
213
|
+
alignItems: 'center',
|
|
185
214
|
mt: 1.5,
|
|
186
215
|
}}>
|
|
187
|
-
{t(item.title)}
|
|
188
|
-
|
|
216
|
+
<Typography variant="h4">{t(item.title)}</Typography>
|
|
217
|
+
{item.doc?.url && (
|
|
218
|
+
<Tooltip title={t('integrations.viewDocs')} placement="top">
|
|
219
|
+
<Link
|
|
220
|
+
href={item.doc.url}
|
|
221
|
+
target="_blank"
|
|
222
|
+
rel="noopener"
|
|
223
|
+
onClick={(e) => e.stopPropagation()}
|
|
224
|
+
sx={{
|
|
225
|
+
display: 'flex',
|
|
226
|
+
alignItems: 'center',
|
|
227
|
+
ml: 1,
|
|
228
|
+
color: 'text.secondary',
|
|
229
|
+
'&:hover': { color: 'primary.main' },
|
|
230
|
+
}}>
|
|
231
|
+
<HelpOutline
|
|
232
|
+
fontSize="small"
|
|
233
|
+
sx={{
|
|
234
|
+
cursor: 'pointer',
|
|
235
|
+
}}
|
|
236
|
+
/>
|
|
237
|
+
</Link>
|
|
238
|
+
</Tooltip>
|
|
239
|
+
)}
|
|
240
|
+
</Box>
|
|
189
241
|
</Box>
|
|
190
242
|
<Typography
|
|
191
243
|
variant="body2"
|
|
@@ -198,6 +250,96 @@ export default function Overview() {
|
|
|
198
250
|
</Grid>
|
|
199
251
|
))}
|
|
200
252
|
</Grid>
|
|
253
|
+
|
|
254
|
+
<Dialog
|
|
255
|
+
open={openMeterDialog}
|
|
256
|
+
onClose={() => setOpenMeterDialog(false)}
|
|
257
|
+
maxWidth="sm"
|
|
258
|
+
fullWidth
|
|
259
|
+
className="base-dialog"
|
|
260
|
+
title={t('integrations.features.metering.dialog.title')}
|
|
261
|
+
actions={
|
|
262
|
+
<Box sx={{ display: 'flex', gap: 2 }}>
|
|
263
|
+
<Button onClick={() => setOpenMeterDialog(false)}>{t('common.cancel')}</Button>
|
|
264
|
+
<Button onClick={() => navigate('/admin/meters')} variant="contained">
|
|
265
|
+
{t('common.goToConfigure')}
|
|
266
|
+
</Button>
|
|
267
|
+
</Box>
|
|
268
|
+
}>
|
|
269
|
+
<Typography variant="body2" sx={{ color: 'text.secondary', mb: 3 }}>
|
|
270
|
+
{t('integrations.features.metering.dialog.description')}
|
|
271
|
+
</Typography>
|
|
272
|
+
|
|
273
|
+
<Box
|
|
274
|
+
component="ol"
|
|
275
|
+
sx={{
|
|
276
|
+
pl: 0,
|
|
277
|
+
mb: 3,
|
|
278
|
+
listStyle: 'none',
|
|
279
|
+
counterReset: 'step-counter',
|
|
280
|
+
}}>
|
|
281
|
+
{['step1', 'step2', 'step3', 'step4'].map((stepKey) => (
|
|
282
|
+
<Box
|
|
283
|
+
key={stepKey}
|
|
284
|
+
component="li"
|
|
285
|
+
sx={{
|
|
286
|
+
mb: 3,
|
|
287
|
+
pl: 3,
|
|
288
|
+
position: 'relative',
|
|
289
|
+
counterIncrement: 'step-counter',
|
|
290
|
+
'&::before': {
|
|
291
|
+
content: 'counter(step-counter)',
|
|
292
|
+
position: 'absolute',
|
|
293
|
+
left: 0,
|
|
294
|
+
top: 0,
|
|
295
|
+
width: 24,
|
|
296
|
+
height: 24,
|
|
297
|
+
borderRadius: '50%',
|
|
298
|
+
backgroundColor: 'primary.main',
|
|
299
|
+
color: 'white',
|
|
300
|
+
fontSize: '12px',
|
|
301
|
+
fontWeight: 'bold',
|
|
302
|
+
display: 'flex',
|
|
303
|
+
alignItems: 'center',
|
|
304
|
+
justifyContent: 'center',
|
|
305
|
+
},
|
|
306
|
+
}}>
|
|
307
|
+
<Box sx={{ ml: 0.5 }}>
|
|
308
|
+
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}>
|
|
309
|
+
{t(`integrations.features.metering.dialog.steps.${stepKey}.title`)}
|
|
310
|
+
</Typography>
|
|
311
|
+
<Typography variant="body2" sx={{ color: 'text.secondary', lineHeight: 1.5 }}>
|
|
312
|
+
{t(`integrations.features.metering.dialog.steps.${stepKey}.description`)}
|
|
313
|
+
</Typography>
|
|
314
|
+
</Box>
|
|
315
|
+
</Box>
|
|
316
|
+
))}
|
|
317
|
+
</Box>
|
|
318
|
+
|
|
319
|
+
<Box
|
|
320
|
+
sx={{
|
|
321
|
+
p: 2,
|
|
322
|
+
backgroundColor: 'action.hover',
|
|
323
|
+
borderRadius: 1,
|
|
324
|
+
border: '1px solid',
|
|
325
|
+
borderColor: 'divider',
|
|
326
|
+
}}>
|
|
327
|
+
<Link
|
|
328
|
+
href="https://www.staging.arcblock.io/content/docs/payment-kit-sdk/en/payment-kit-sdk-core-concepts-credit-billing"
|
|
329
|
+
target="_blank"
|
|
330
|
+
rel="noopener"
|
|
331
|
+
underline="hover"
|
|
332
|
+
sx={{
|
|
333
|
+
color: 'primary.main',
|
|
334
|
+
fontWeight: 500,
|
|
335
|
+
display: 'flex',
|
|
336
|
+
alignItems: 'center',
|
|
337
|
+
gap: 0.5,
|
|
338
|
+
}}>
|
|
339
|
+
{t('integrations.features.metering.dialog.docText')}
|
|
340
|
+
</Link>
|
|
341
|
+
</Box>
|
|
342
|
+
</Dialog>
|
|
201
343
|
</Box>
|
|
202
344
|
);
|
|
203
345
|
}
|