payment-kit 1.18.5 → 1.18.7
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/auth.ts +1 -1
- package/api/src/routes/connect/change-payment.ts +47 -22
- package/api/src/routes/connect/change-plan.ts +45 -20
- package/api/src/routes/connect/pay.ts +4 -4
- package/api/src/routes/connect/setup.ts +50 -25
- package/api/src/routes/connect/subscribe.ts +44 -25
- package/api/src/routes/payment-links.ts +1 -1
- package/blocklet.yml +1 -1
- package/package.json +9 -9
- package/src/components/subscription/list.tsx +1 -0
- package/src/components/subscription/portal/actions.tsx +3 -3
- package/src/components/uploader.tsx +1 -0
- package/src/libs/util.ts +13 -0
- package/src/pages/customer/recharge.tsx +35 -6
- package/src/pages/customer/subscription/change-payment.tsx +1 -1
- package/src/pages/customer/subscription/change-plan.tsx +3 -2
- package/src/pages/integrations/overview.tsx +63 -40
package/api/src/libs/auth.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from './shared';
|
|
13
13
|
import { ensureStakeInvoice } from '../../libs/invoice';
|
|
14
14
|
import { EVM_CHAIN_TYPES } from '../../libs/constants';
|
|
15
|
+
import logger from '../../libs/logger';
|
|
15
16
|
|
|
16
17
|
export default {
|
|
17
18
|
action: 'change-payment',
|
|
@@ -26,17 +27,15 @@ export default {
|
|
|
26
27
|
const { subscriptionId } = extraParams;
|
|
27
28
|
const { subscription, paymentMethod, paymentCurrency } = await ensureChangePaymentContext(subscriptionId);
|
|
28
29
|
|
|
29
|
-
const
|
|
30
|
-
|
|
30
|
+
const claimsList: any[] = [];
|
|
31
31
|
// @ts-ignore
|
|
32
32
|
const items = subscription!.items as TLineItemExpanded[];
|
|
33
33
|
const trialing = true;
|
|
34
34
|
const billingThreshold = Number(subscription.billing_thresholds?.amount_gte || 0);
|
|
35
35
|
|
|
36
36
|
if (paymentMethod.type === 'arcblock') {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
await getDelegationTxClaim({
|
|
37
|
+
claimsList.push({
|
|
38
|
+
signature: await getDelegationTxClaim({
|
|
40
39
|
mode: 'setup',
|
|
41
40
|
userDid,
|
|
42
41
|
userPk,
|
|
@@ -48,12 +47,10 @@ export default {
|
|
|
48
47
|
billingThreshold,
|
|
49
48
|
items,
|
|
50
49
|
}),
|
|
51
|
-
|
|
50
|
+
});
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
'prepareTx',
|
|
56
|
-
await getStakeTxClaim({
|
|
52
|
+
claimsList.push({
|
|
53
|
+
prepareTx: await getStakeTxClaim({
|
|
57
54
|
userDid,
|
|
58
55
|
userPk,
|
|
59
56
|
paymentCurrency,
|
|
@@ -61,9 +58,9 @@ export default {
|
|
|
61
58
|
items,
|
|
62
59
|
subscription,
|
|
63
60
|
}),
|
|
64
|
-
|
|
61
|
+
});
|
|
65
62
|
|
|
66
|
-
return
|
|
63
|
+
return claimsList;
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
@@ -71,9 +68,8 @@ export default {
|
|
|
71
68
|
throw new Error(`Payment currency ${paymentMethod.type}:${paymentCurrency.id} does not support subscription`);
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
await getDelegationTxClaim({
|
|
71
|
+
claimsList.push({
|
|
72
|
+
signature: await getDelegationTxClaim({
|
|
77
73
|
mode: 'subscription',
|
|
78
74
|
userDid,
|
|
79
75
|
userPk,
|
|
@@ -85,19 +81,48 @@ export default {
|
|
|
85
81
|
billingThreshold,
|
|
86
82
|
items,
|
|
87
83
|
}),
|
|
88
|
-
|
|
84
|
+
});
|
|
89
85
|
|
|
90
|
-
return
|
|
86
|
+
return claimsList;
|
|
91
87
|
}
|
|
92
88
|
|
|
93
|
-
throw new Error(`
|
|
89
|
+
throw new Error(`ChangePayment: Payment method ${paymentMethod.type} not supported`);
|
|
94
90
|
},
|
|
95
91
|
|
|
96
|
-
onAuth: async ({ request, userDid, userPk, claims, extraParams }: CallbackArgs) => {
|
|
92
|
+
onAuth: async ({ request, userDid, userPk, claims, extraParams, updateSession, step }: CallbackArgs) => {
|
|
97
93
|
const { subscriptionId } = extraParams;
|
|
98
|
-
const { subscription,
|
|
94
|
+
const { setupIntent, subscription, paymentMethod, paymentCurrency, customer } =
|
|
99
95
|
await ensureChangePaymentContext(subscriptionId);
|
|
100
96
|
|
|
97
|
+
const result = request?.context?.store?.result || [];
|
|
98
|
+
result.push({
|
|
99
|
+
step,
|
|
100
|
+
claim: claims?.[0],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// 判断是否为最后一步
|
|
104
|
+
const staking = result.find((x: any) => x.claim?.type === 'prepareTx' && x.claim?.meta?.purpose === 'staking');
|
|
105
|
+
const isFinalStep = (paymentMethod.type === 'arcblock' && staking) || paymentMethod.type !== 'arcblock';
|
|
106
|
+
|
|
107
|
+
if (!isFinalStep) {
|
|
108
|
+
await updateSession({
|
|
109
|
+
result,
|
|
110
|
+
});
|
|
111
|
+
return { result };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 清理 session
|
|
115
|
+
try {
|
|
116
|
+
await updateSession({
|
|
117
|
+
result: [],
|
|
118
|
+
});
|
|
119
|
+
} catch (error) {
|
|
120
|
+
logger.error('updateSession', {
|
|
121
|
+
error,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const claimsList = result.map((x: any) => x.claim);
|
|
125
|
+
|
|
101
126
|
const prepareTxExecution = async () => {
|
|
102
127
|
await subscription?.update({
|
|
103
128
|
payment_settings: {
|
|
@@ -141,7 +166,7 @@ export default {
|
|
|
141
166
|
const { stakingAmount, ...paymentDetails } = await executeOcapTransactions(
|
|
142
167
|
userDid,
|
|
143
168
|
userPk,
|
|
144
|
-
|
|
169
|
+
claimsList,
|
|
145
170
|
paymentMethod,
|
|
146
171
|
request,
|
|
147
172
|
subscription?.id,
|
|
@@ -172,7 +197,7 @@ export default {
|
|
|
172
197
|
|
|
173
198
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
174
199
|
await prepareTxExecution();
|
|
175
|
-
const paymentDetails = await executeEvmTransaction('approve', userDid,
|
|
200
|
+
const paymentDetails = await executeEvmTransaction('approve', userDid, claimsList, paymentMethod);
|
|
176
201
|
waitForEvmTxConfirm(paymentMethod.getEvmClient(), +paymentDetails.block_height, paymentMethod.confirmation.block)
|
|
177
202
|
.then(async () => {
|
|
178
203
|
await afterTxExecution(paymentDetails);
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from './shared';
|
|
17
17
|
import { ensureStakeInvoice } from '../../libs/invoice';
|
|
18
18
|
import { EVM_CHAIN_TYPES } from '../../libs/constants';
|
|
19
|
+
import logger from '../../libs/logger';
|
|
19
20
|
|
|
20
21
|
export default {
|
|
21
22
|
action: 'change-plan',
|
|
@@ -30,7 +31,7 @@ export default {
|
|
|
30
31
|
const { subscriptionId } = extraParams;
|
|
31
32
|
const { paymentMethod, paymentCurrency, subscription, customer } = await ensureSubscription(subscriptionId);
|
|
32
33
|
|
|
33
|
-
const
|
|
34
|
+
const claimsList: any[] = [];
|
|
34
35
|
// @ts-ignore
|
|
35
36
|
const items = subscription!.items as TLineItemExpanded[];
|
|
36
37
|
const trialing = false;
|
|
@@ -45,11 +46,9 @@ export default {
|
|
|
45
46
|
amount: fastCheckoutAmount,
|
|
46
47
|
});
|
|
47
48
|
|
|
48
|
-
// if we can complete purchase without any wallet interaction
|
|
49
49
|
if (delegation.sufficient === false) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await getDelegationTxClaim({
|
|
50
|
+
claimsList.push({
|
|
51
|
+
signature: await getDelegationTxClaim({
|
|
53
52
|
mode: 'subscription',
|
|
54
53
|
userDid,
|
|
55
54
|
userPk,
|
|
@@ -61,13 +60,11 @@ export default {
|
|
|
61
60
|
billingThreshold,
|
|
62
61
|
items,
|
|
63
62
|
}),
|
|
64
|
-
|
|
63
|
+
});
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
'prepareTx',
|
|
70
|
-
await getStakeTxClaim({
|
|
66
|
+
claimsList.push({
|
|
67
|
+
prepareTx: await getStakeTxClaim({
|
|
71
68
|
userDid,
|
|
72
69
|
userPk,
|
|
73
70
|
paymentCurrency,
|
|
@@ -75,9 +72,9 @@ export default {
|
|
|
75
72
|
items,
|
|
76
73
|
subscription: subscription!,
|
|
77
74
|
}),
|
|
78
|
-
|
|
75
|
+
});
|
|
79
76
|
|
|
80
|
-
return
|
|
77
|
+
return claimsList;
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
@@ -85,9 +82,8 @@ export default {
|
|
|
85
82
|
throw new Error(`Payment currency ${paymentMethod.type}:${paymentCurrency.id} does not support subscription`);
|
|
86
83
|
}
|
|
87
84
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
await getDelegationTxClaim({
|
|
85
|
+
claimsList.push({
|
|
86
|
+
signature: await getDelegationTxClaim({
|
|
91
87
|
mode: 'subscription',
|
|
92
88
|
userDid,
|
|
93
89
|
userPk,
|
|
@@ -99,19 +95,48 @@ export default {
|
|
|
99
95
|
billingThreshold,
|
|
100
96
|
items,
|
|
101
97
|
}),
|
|
102
|
-
|
|
98
|
+
});
|
|
103
99
|
|
|
104
|
-
return
|
|
100
|
+
return claimsList;
|
|
105
101
|
}
|
|
106
102
|
|
|
107
103
|
throw new Error(`ChangePlan: Payment method ${paymentMethod.type} not supported`);
|
|
108
104
|
},
|
|
109
105
|
|
|
110
|
-
onAuth: async ({ request, userDid, userPk, claims, extraParams }: CallbackArgs) => {
|
|
106
|
+
onAuth: async ({ request, userDid, userPk, claims, extraParams, updateSession, step }: CallbackArgs) => {
|
|
111
107
|
const { subscriptionId } = extraParams;
|
|
112
108
|
const { invoice, paymentMethod, subscription, paymentCurrency, customer } =
|
|
113
109
|
await ensureSubscription(subscriptionId);
|
|
114
110
|
|
|
111
|
+
const result = request?.context?.store?.result || [];
|
|
112
|
+
result.push({
|
|
113
|
+
step,
|
|
114
|
+
claim: claims?.[0],
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// 判断是否为最后一步
|
|
118
|
+
const staking = result.find((x: any) => x.claim?.type === 'prepareTx' && x.claim?.meta?.purpose === 'staking');
|
|
119
|
+
const isFinalStep = (paymentMethod.type === 'arcblock' && staking) || paymentMethod.type !== 'arcblock';
|
|
120
|
+
|
|
121
|
+
if (!isFinalStep) {
|
|
122
|
+
await updateSession({
|
|
123
|
+
result,
|
|
124
|
+
});
|
|
125
|
+
return { result };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 清理 session
|
|
129
|
+
try {
|
|
130
|
+
await updateSession({
|
|
131
|
+
result: [],
|
|
132
|
+
});
|
|
133
|
+
} catch (error) {
|
|
134
|
+
logger.error('updateSession', {
|
|
135
|
+
error,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const claimsList = result.map((x: any) => x.claim);
|
|
139
|
+
|
|
115
140
|
const prepareTxExecution = async () => {
|
|
116
141
|
await subscription?.update({
|
|
117
142
|
payment_settings: {
|
|
@@ -148,7 +173,7 @@ export default {
|
|
|
148
173
|
const { stakingAmount, ...paymentDetails } = await executeOcapTransactions(
|
|
149
174
|
userDid,
|
|
150
175
|
userPk,
|
|
151
|
-
|
|
176
|
+
claimsList,
|
|
152
177
|
paymentMethod,
|
|
153
178
|
request,
|
|
154
179
|
subscription?.id,
|
|
@@ -181,7 +206,7 @@ export default {
|
|
|
181
206
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
182
207
|
await prepareTxExecution();
|
|
183
208
|
|
|
184
|
-
const paymentDetails = await executeEvmTransaction('approve', userDid,
|
|
209
|
+
const paymentDetails = await executeEvmTransaction('approve', userDid, claimsList, paymentMethod);
|
|
185
210
|
waitForEvmTxConfirm(paymentMethod.getEvmClient(), +paymentDetails.block_height, paymentMethod.confirmation.block)
|
|
186
211
|
.then(async () => {
|
|
187
212
|
await afterTxExecution(paymentDetails);
|
|
@@ -27,10 +27,10 @@ export default {
|
|
|
27
27
|
|
|
28
28
|
onConnect: async (args: CallbackArgs) => {
|
|
29
29
|
const { userDid, userPk, extraParams } = args;
|
|
30
|
-
const { checkoutSessionId, connectedDid } = extraParams;
|
|
30
|
+
const { checkoutSessionId, connectedDid, sessionUserDid } = extraParams;
|
|
31
31
|
const { paymentIntent, paymentCurrency, paymentMethod } = await ensurePaymentIntent(
|
|
32
32
|
checkoutSessionId,
|
|
33
|
-
connectedDid || userDid
|
|
33
|
+
connectedDid || sessionUserDid || userDid
|
|
34
34
|
);
|
|
35
35
|
if (!paymentIntent) {
|
|
36
36
|
throw new Error('Payment intent not found');
|
|
@@ -87,10 +87,10 @@ export default {
|
|
|
87
87
|
|
|
88
88
|
onAuth: async (args: CallbackArgs) => {
|
|
89
89
|
const { request, userDid, claims, extraParams } = args;
|
|
90
|
-
const { checkoutSessionId, connectedDid } = extraParams;
|
|
90
|
+
const { checkoutSessionId, connectedDid, sessionUserDid } = extraParams;
|
|
91
91
|
const { checkoutSession, customer, paymentIntent, paymentMethod } = await ensurePaymentIntent(
|
|
92
92
|
checkoutSessionId,
|
|
93
|
-
connectedDid || userDid
|
|
93
|
+
connectedDid || sessionUserDid || userDid
|
|
94
94
|
);
|
|
95
95
|
if (!paymentIntent) {
|
|
96
96
|
throw new Error('Payment intent not found');
|
|
@@ -30,19 +30,18 @@ export default {
|
|
|
30
30
|
},
|
|
31
31
|
onConnect: async (args: CallbackArgs) => {
|
|
32
32
|
const { userDid, userPk, extraParams } = args;
|
|
33
|
-
const { checkoutSessionId, connectedDid } = extraParams;
|
|
33
|
+
const { checkoutSessionId, connectedDid, sessionUserDid } = extraParams;
|
|
34
34
|
const { paymentMethod, paymentCurrency, checkoutSession, subscription, customer } = await ensureSetupIntent(
|
|
35
35
|
checkoutSessionId,
|
|
36
|
-
connectedDid || userDid
|
|
36
|
+
connectedDid || sessionUserDid || userDid
|
|
37
37
|
);
|
|
38
38
|
if (!subscription) {
|
|
39
39
|
throw new Error('Subscription for checkoutSession not found');
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const claimsList: any[] = [];
|
|
43
43
|
const now = dayjs().unix();
|
|
44
44
|
const items = checkoutSession.line_items as TLineItemExpanded[];
|
|
45
|
-
|
|
46
45
|
const { trialEnd, trialInDays } = getSubscriptionTrialSetup(
|
|
47
46
|
checkoutSession.subscription_data as any,
|
|
48
47
|
paymentCurrency.id
|
|
@@ -62,9 +61,8 @@ export default {
|
|
|
62
61
|
});
|
|
63
62
|
// if we can complete purchase without any wallet interaction
|
|
64
63
|
if (delegation.sufficient === false) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
await getDelegationTxClaim({
|
|
64
|
+
claimsList.push({
|
|
65
|
+
signature: await getDelegationTxClaim({
|
|
68
66
|
mode: checkoutSession.mode,
|
|
69
67
|
userDid,
|
|
70
68
|
userPk,
|
|
@@ -76,13 +74,12 @@ export default {
|
|
|
76
74
|
billingThreshold: Math.max(minStakeAmount, billingThreshold),
|
|
77
75
|
items,
|
|
78
76
|
}),
|
|
79
|
-
|
|
77
|
+
});
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
// we always need to stake for the subscription
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
await getStakeTxClaim({
|
|
81
|
+
claimsList.push({
|
|
82
|
+
prepareTx: await getStakeTxClaim({
|
|
86
83
|
userDid,
|
|
87
84
|
userPk,
|
|
88
85
|
paymentCurrency,
|
|
@@ -90,9 +87,9 @@ export default {
|
|
|
90
87
|
items,
|
|
91
88
|
subscription,
|
|
92
89
|
}),
|
|
93
|
-
|
|
90
|
+
});
|
|
94
91
|
|
|
95
|
-
return
|
|
92
|
+
return claimsList;
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
@@ -100,9 +97,8 @@ export default {
|
|
|
100
97
|
throw new Error(`Payment currency ${paymentMethod.type}:${paymentCurrency.id} does not support setup`);
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
await getDelegationTxClaim({
|
|
100
|
+
claimsList.push({
|
|
101
|
+
signature: await getDelegationTxClaim({
|
|
106
102
|
mode: checkoutSession.mode,
|
|
107
103
|
userDid,
|
|
108
104
|
userPk,
|
|
@@ -114,23 +110,52 @@ export default {
|
|
|
114
110
|
billingThreshold,
|
|
115
111
|
items,
|
|
116
112
|
}),
|
|
117
|
-
|
|
113
|
+
});
|
|
118
114
|
|
|
119
|
-
return
|
|
115
|
+
return claimsList;
|
|
120
116
|
}
|
|
121
117
|
|
|
122
118
|
throw new Error(`Payment method ${paymentMethod.type} not supported`);
|
|
123
119
|
},
|
|
124
120
|
onAuth: async (args: CallbackArgs) => {
|
|
125
|
-
const { request, userDid, userPk, claims, extraParams } = args;
|
|
126
|
-
const { checkoutSessionId, connectedDid } = extraParams;
|
|
121
|
+
const { request, userDid, userPk, claims, extraParams, updateSession, step } = args;
|
|
122
|
+
const { checkoutSessionId, connectedDid, sessionUserDid } = extraParams;
|
|
127
123
|
const { setupIntent, checkoutSession, paymentMethod, subscription, invoice, paymentCurrency, customer } =
|
|
128
|
-
await ensureSetupIntent(checkoutSessionId, connectedDid || userDid);
|
|
124
|
+
await ensureSetupIntent(checkoutSessionId, connectedDid || sessionUserDid || userDid);
|
|
129
125
|
|
|
130
126
|
if (!subscription) {
|
|
131
127
|
throw new Error('Subscription for checkoutSession not found');
|
|
132
128
|
}
|
|
133
129
|
|
|
130
|
+
const result = request?.context?.store?.result || [];
|
|
131
|
+
result.push({
|
|
132
|
+
step,
|
|
133
|
+
claim: claims?.[0],
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 判断是否为最后一步
|
|
137
|
+
const staking = result.find((x: any) => x.claim?.type === 'prepareTx' && x.claim?.meta?.purpose === 'staking');
|
|
138
|
+
const isFinalStep = (paymentMethod.type === 'arcblock' && staking) || paymentMethod.type !== 'arcblock';
|
|
139
|
+
|
|
140
|
+
if (!isFinalStep) {
|
|
141
|
+
await updateSession({
|
|
142
|
+
result,
|
|
143
|
+
});
|
|
144
|
+
return { result };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 清理 session
|
|
148
|
+
try {
|
|
149
|
+
await updateSession({
|
|
150
|
+
result: [],
|
|
151
|
+
});
|
|
152
|
+
} catch (error) {
|
|
153
|
+
logger.error('updateSession', {
|
|
154
|
+
error,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const claimsList = result.map((x: any) => x.claim);
|
|
158
|
+
|
|
134
159
|
const paymentSettings = {
|
|
135
160
|
payment_method_types: [paymentMethod.type],
|
|
136
161
|
payment_method_options: {
|
|
@@ -177,7 +202,7 @@ export default {
|
|
|
177
202
|
const { stakingAmount, ...paymentDetails } = await executeOcapTransactions(
|
|
178
203
|
userDid,
|
|
179
204
|
userPk,
|
|
180
|
-
|
|
205
|
+
claimsList,
|
|
181
206
|
paymentMethod,
|
|
182
207
|
request,
|
|
183
208
|
subscription?.id,
|
|
@@ -216,12 +241,12 @@ export default {
|
|
|
216
241
|
|
|
217
242
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
218
243
|
await prepareTxExecution();
|
|
219
|
-
broadcastEvmTransaction(checkoutSessionId, 'pending',
|
|
220
|
-
const paymentDetails = await executeEvmTransaction('approve', userDid,
|
|
244
|
+
broadcastEvmTransaction(checkoutSessionId, 'pending', claimsList);
|
|
245
|
+
const paymentDetails = await executeEvmTransaction('approve', userDid, claimsList, paymentMethod);
|
|
221
246
|
waitForEvmTxConfirm(paymentMethod.getEvmClient(), +paymentDetails.block_height, paymentMethod.confirmation.block)
|
|
222
247
|
.then(async () => {
|
|
223
248
|
await afterTxExecution(paymentDetails);
|
|
224
|
-
broadcastEvmTransaction(checkoutSessionId, 'confirmed',
|
|
249
|
+
broadcastEvmTransaction(checkoutSessionId, 'confirmed', claimsList);
|
|
225
250
|
})
|
|
226
251
|
.catch(console.error);
|
|
227
252
|
|
|
@@ -31,16 +31,15 @@ export default {
|
|
|
31
31
|
},
|
|
32
32
|
onConnect: async (args: CallbackArgs) => {
|
|
33
33
|
const { userDid, userPk, extraParams } = args;
|
|
34
|
-
const { checkoutSessionId, connectedDid } = extraParams;
|
|
34
|
+
const { checkoutSessionId, connectedDid, sessionUserDid } = extraParams;
|
|
35
35
|
const { checkoutSession, paymentMethod, paymentCurrency, subscription, customer } = await ensurePaymentIntent(
|
|
36
36
|
checkoutSessionId,
|
|
37
|
-
connectedDid || userDid
|
|
37
|
+
connectedDid || sessionUserDid || userDid
|
|
38
38
|
);
|
|
39
39
|
if (!subscription) {
|
|
40
40
|
throw new Error('Subscription for checkoutSession not found');
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const claims: { [type: string]: [string, object] } = {};
|
|
44
43
|
const now = dayjs().unix();
|
|
45
44
|
const items = checkoutSession.line_items as TLineItemExpanded[];
|
|
46
45
|
const { trialEnd, trialInDays } = getSubscriptionTrialSetup(
|
|
@@ -51,7 +50,7 @@ export default {
|
|
|
51
50
|
const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
|
|
52
51
|
const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
|
|
53
52
|
const fastCheckoutAmount = getFastCheckoutAmount(items, checkoutSession.mode, paymentCurrency.id, trialing);
|
|
54
|
-
|
|
53
|
+
const claimsList: any[] = [];
|
|
55
54
|
if (paymentMethod.type === 'arcblock') {
|
|
56
55
|
const delegation = await isDelegationSufficientForPayment({
|
|
57
56
|
paymentMethod,
|
|
@@ -62,9 +61,8 @@ export default {
|
|
|
62
61
|
|
|
63
62
|
// if we can complete purchase without any wallet interaction
|
|
64
63
|
if (delegation.sufficient === false) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
await getDelegationTxClaim({
|
|
64
|
+
claimsList.push({
|
|
65
|
+
signature: await getDelegationTxClaim({
|
|
68
66
|
mode: checkoutSession.mode,
|
|
69
67
|
userDid,
|
|
70
68
|
userPk,
|
|
@@ -76,13 +74,12 @@ export default {
|
|
|
76
74
|
billingThreshold: Math.max(minStakeAmount, billingThreshold),
|
|
77
75
|
items,
|
|
78
76
|
}),
|
|
79
|
-
|
|
77
|
+
});
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
// we always need to stake for the subscription
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
await getStakeTxClaim({
|
|
81
|
+
claimsList.push({
|
|
82
|
+
prepareTx: await getStakeTxClaim({
|
|
86
83
|
userDid,
|
|
87
84
|
userPk,
|
|
88
85
|
paymentCurrency,
|
|
@@ -90,9 +87,9 @@ export default {
|
|
|
90
87
|
items,
|
|
91
88
|
subscription,
|
|
92
89
|
}),
|
|
93
|
-
|
|
90
|
+
});
|
|
94
91
|
|
|
95
|
-
return
|
|
92
|
+
return claimsList;
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
@@ -100,9 +97,8 @@ export default {
|
|
|
100
97
|
throw new Error(`Payment currency ${paymentMethod.type}:${paymentCurrency.id} does not support subscription`);
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
await getDelegationTxClaim({
|
|
100
|
+
claimsList.push({
|
|
101
|
+
signature: await getDelegationTxClaim({
|
|
106
102
|
mode: checkoutSession.mode,
|
|
107
103
|
userDid,
|
|
108
104
|
userPk,
|
|
@@ -114,20 +110,43 @@ export default {
|
|
|
114
110
|
billingThreshold,
|
|
115
111
|
items,
|
|
116
112
|
}),
|
|
117
|
-
|
|
113
|
+
});
|
|
118
114
|
|
|
119
|
-
return
|
|
115
|
+
return claimsList;
|
|
120
116
|
}
|
|
121
117
|
|
|
122
118
|
throw new Error(`subscription: Payment method ${paymentMethod.type} not supported`);
|
|
123
119
|
},
|
|
124
120
|
onAuth: async (args: CallbackArgs) => {
|
|
125
|
-
const { request, userDid, userPk, claims, extraParams } = args;
|
|
126
|
-
const { checkoutSessionId, connectedDid } = extraParams;
|
|
121
|
+
const { request, userDid, userPk, claims, extraParams, updateSession, step } = args;
|
|
122
|
+
const { checkoutSessionId, connectedDid, sessionUserDid } = extraParams;
|
|
127
123
|
const { checkoutSession, customer, paymentMethod, subscription, paymentCurrency } = await ensurePaymentIntent(
|
|
128
124
|
checkoutSessionId,
|
|
129
|
-
connectedDid || userDid
|
|
125
|
+
connectedDid || sessionUserDid || userDid
|
|
130
126
|
);
|
|
127
|
+
const result = request?.context?.store?.result || [];
|
|
128
|
+
result.push({
|
|
129
|
+
step,
|
|
130
|
+
claim: claims?.[0],
|
|
131
|
+
});
|
|
132
|
+
const staking = result.find((x: any) => x.claim?.type === 'prepareTx' && x.claim?.meta?.purpose === 'staking');
|
|
133
|
+
const isFinalStep = (paymentMethod.type === 'arcblock' && staking) || paymentMethod.type !== 'arcblock';
|
|
134
|
+
if (!isFinalStep) {
|
|
135
|
+
await updateSession({
|
|
136
|
+
result,
|
|
137
|
+
});
|
|
138
|
+
return { result };
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
await updateSession({
|
|
142
|
+
result: [],
|
|
143
|
+
});
|
|
144
|
+
} catch (error) {
|
|
145
|
+
logger.error('updateSession', {
|
|
146
|
+
error,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const claimsList = result.map((x: any) => x.claim);
|
|
131
150
|
|
|
132
151
|
if (!subscription) {
|
|
133
152
|
throw new Error('Subscription for checkoutSession not found');
|
|
@@ -164,7 +183,7 @@ export default {
|
|
|
164
183
|
const { stakingAmount, ...paymentDetails } = await executeOcapTransactions(
|
|
165
184
|
userDid,
|
|
166
185
|
userPk,
|
|
167
|
-
|
|
186
|
+
claimsList,
|
|
168
187
|
paymentMethod,
|
|
169
188
|
request,
|
|
170
189
|
subscription?.id,
|
|
@@ -198,9 +217,9 @@ export default {
|
|
|
198
217
|
if (EVM_CHAIN_TYPES.includes(paymentMethod.type)) {
|
|
199
218
|
await prepareTxExecution();
|
|
200
219
|
const { invoice } = await ensureInvoiceForCheckout({ checkoutSession, customer, subscription });
|
|
201
|
-
broadcastEvmTransaction(checkoutSessionId, 'pending',
|
|
220
|
+
broadcastEvmTransaction(checkoutSessionId, 'pending', claimsList);
|
|
202
221
|
|
|
203
|
-
const paymentDetails = await executeEvmTransaction('approve', userDid,
|
|
222
|
+
const paymentDetails = await executeEvmTransaction('approve', userDid, claimsList, paymentMethod);
|
|
204
223
|
waitForEvmTxConfirm(
|
|
205
224
|
paymentMethod.getEvmClient(),
|
|
206
225
|
Number(paymentDetails.block_height),
|
|
@@ -208,7 +227,7 @@ export default {
|
|
|
208
227
|
)
|
|
209
228
|
.then(async () => {
|
|
210
229
|
await afterTxExecution(invoice!, paymentDetails);
|
|
211
|
-
broadcastEvmTransaction(checkoutSessionId, 'confirmed',
|
|
230
|
+
broadcastEvmTransaction(checkoutSessionId, 'confirmed', claimsList);
|
|
212
231
|
})
|
|
213
232
|
.catch(console.error);
|
|
214
233
|
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.7",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
"@abtnode/cron": "^1.16.38",
|
|
47
47
|
"@arcblock/did": "^1.19.9",
|
|
48
48
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
49
|
-
"@arcblock/did-connect": "^2.11.
|
|
49
|
+
"@arcblock/did-connect": "^2.11.40",
|
|
50
50
|
"@arcblock/did-util": "^1.19.9",
|
|
51
51
|
"@arcblock/jwt": "^1.19.9",
|
|
52
|
-
"@arcblock/ux": "^2.11.
|
|
52
|
+
"@arcblock/ux": "^2.11.40",
|
|
53
53
|
"@arcblock/validator": "^1.19.9",
|
|
54
54
|
"@blocklet/js-sdk": "^1.16.38",
|
|
55
55
|
"@blocklet/logger": "^1.16.38",
|
|
56
|
-
"@blocklet/payment-react": "1.18.
|
|
56
|
+
"@blocklet/payment-react": "1.18.7",
|
|
57
57
|
"@blocklet/sdk": "^1.16.38",
|
|
58
|
-
"@blocklet/ui-react": "^2.11.
|
|
59
|
-
"@blocklet/uploader": "^0.1.
|
|
60
|
-
"@blocklet/xss": "^0.1.
|
|
58
|
+
"@blocklet/ui-react": "^2.11.40",
|
|
59
|
+
"@blocklet/uploader": "^0.1.70",
|
|
60
|
+
"@blocklet/xss": "^0.1.25",
|
|
61
61
|
"@mui/icons-material": "^5.16.6",
|
|
62
62
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
63
63
|
"@mui/material": "^5.16.6",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"devDependencies": {
|
|
122
122
|
"@abtnode/types": "^1.16.38",
|
|
123
123
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
124
|
-
"@blocklet/payment-types": "1.18.
|
|
124
|
+
"@blocklet/payment-types": "1.18.7",
|
|
125
125
|
"@types/cookie-parser": "^1.4.7",
|
|
126
126
|
"@types/cors": "^2.8.17",
|
|
127
127
|
"@types/debug": "^4.1.12",
|
|
@@ -167,5 +167,5 @@
|
|
|
167
167
|
"parser": "typescript"
|
|
168
168
|
}
|
|
169
169
|
},
|
|
170
|
-
"gitHead": "
|
|
170
|
+
"gitHead": "b75168ab5e2cd939571e6e26543374c8d0dab963"
|
|
171
171
|
}
|
|
@@ -140,7 +140,7 @@ export function SubscriptionActionsInner({
|
|
|
140
140
|
const { t, locale } = useLocaleContext();
|
|
141
141
|
const { reset, getValues } = useFormContext();
|
|
142
142
|
const navigate = useNavigate();
|
|
143
|
-
const { connect } = usePaymentContext();
|
|
143
|
+
const { connect, session } = usePaymentContext();
|
|
144
144
|
const [subs, setSubscription] = useState(subscription);
|
|
145
145
|
const { checkUnpaidInvoices } = useUnpaidInvoicesCheckForSubscription(subscription.id, true);
|
|
146
146
|
const action = getSubscriptionAction(subs, actionProps ?? {});
|
|
@@ -239,7 +239,7 @@ export function SubscriptionActionsInner({
|
|
|
239
239
|
saveConnect: false,
|
|
240
240
|
action: 'delegation',
|
|
241
241
|
prefix: joinURL(getPrefix(), '/api/did'),
|
|
242
|
-
extraParams: { subscriptionId: subscription.id },
|
|
242
|
+
extraParams: { subscriptionId: subscription.id, sessionUserDid: session.user.did },
|
|
243
243
|
onSuccess: () => {
|
|
244
244
|
connect.close();
|
|
245
245
|
Toast.success(t('customer.delegation.success'));
|
|
@@ -286,7 +286,7 @@ export function SubscriptionActionsInner({
|
|
|
286
286
|
saveConnect: false,
|
|
287
287
|
action: 'overdraft-protection',
|
|
288
288
|
prefix: joinURL(getPrefix(), '/api/did'),
|
|
289
|
-
extraParams: { subscriptionId: subscription.id, amount },
|
|
289
|
+
extraParams: { subscriptionId: subscription.id, amount, sessionUserDid: session.user.did },
|
|
290
290
|
onSuccess: () => {
|
|
291
291
|
connect.close();
|
|
292
292
|
Toast.success(t('customer.overdraftProtection.settingSuccess'));
|
package/src/libs/util.ts
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
/* eslint-disable @typescript-eslint/indent */
|
|
4
4
|
import { formatCheckoutHeadlines, formatPrice, getPrefix, getPriceCurrencyOptions } from '@blocklet/payment-react';
|
|
5
5
|
import type {
|
|
6
|
+
ChainType,
|
|
6
7
|
LineItem,
|
|
7
8
|
PriceRecurring,
|
|
8
9
|
TInvoiceExpanded,
|
|
9
10
|
TLineItemExpanded,
|
|
10
11
|
TPaymentCurrency,
|
|
11
12
|
TPaymentLinkExpanded,
|
|
13
|
+
TPaymentMethod,
|
|
12
14
|
TPaymentMethodExpanded,
|
|
13
15
|
TPrice,
|
|
14
16
|
TProductExpanded,
|
|
@@ -364,3 +366,14 @@ export function getAppInfo(address: string): { name: string; avatar: string; typ
|
|
|
364
366
|
}
|
|
365
367
|
return null;
|
|
366
368
|
}
|
|
369
|
+
|
|
370
|
+
export function getTokenBalanceLink(method: TPaymentMethod, address: string) {
|
|
371
|
+
const explorerHost = (method?.settings?.[method?.type as ChainType] as any)?.explorer_host || '';
|
|
372
|
+
if (method.type === 'arcblock' && address) {
|
|
373
|
+
return joinURL(explorerHost, 'accounts', address, 'tokens');
|
|
374
|
+
}
|
|
375
|
+
if (['ethereum', 'base'].includes(method.type) && address) {
|
|
376
|
+
return joinURL(explorerHost, 'address', address);
|
|
377
|
+
}
|
|
378
|
+
return '';
|
|
379
|
+
}
|
|
@@ -28,14 +28,14 @@ import {
|
|
|
28
28
|
} from '@blocklet/payment-react';
|
|
29
29
|
import { joinURL } from 'ufo';
|
|
30
30
|
import type { TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
31
|
-
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
31
|
+
import { ArrowBackOutlined, ArrowForwardOutlined } from '@mui/icons-material';
|
|
32
32
|
import { BN, fromUnitToToken } from '@ocap/util';
|
|
33
33
|
import RechargeList from '../../components/invoice/recharge';
|
|
34
34
|
import SubscriptionDescription from '../../components/subscription/description';
|
|
35
35
|
import InfoRow from '../../components/info-row';
|
|
36
36
|
import Currency from '../../components/currency';
|
|
37
37
|
import SubscriptionMetrics from '../../components/subscription/metrics';
|
|
38
|
-
import { goBackOrFallback } from '../../libs/util';
|
|
38
|
+
import { getTokenBalanceLink, goBackOrFallback } from '../../libs/util';
|
|
39
39
|
import CustomerLink from '../../components/customer/link';
|
|
40
40
|
import { useSessionContext } from '../../contexts/session';
|
|
41
41
|
import { formatSmartDuration, TimeUnit } from '../../libs/dayjs';
|
|
@@ -237,6 +237,8 @@ export default function RechargePage() {
|
|
|
237
237
|
});
|
|
238
238
|
};
|
|
239
239
|
|
|
240
|
+
const balanceLink = getTokenBalanceLink(paymentMethod!, payerValue?.paymentAddress || receiveAddress);
|
|
241
|
+
|
|
240
242
|
return (
|
|
241
243
|
<Root>
|
|
242
244
|
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ position: 'relative' }}>
|
|
@@ -336,16 +338,43 @@ export default function RechargePage() {
|
|
|
336
338
|
</BalanceCard>
|
|
337
339
|
|
|
338
340
|
<BalanceCard
|
|
341
|
+
onClick={() => balanceLink && window.open(balanceLink, '_blank')}
|
|
339
342
|
sx={{
|
|
340
343
|
background: 'var(--tags-tag-orange-bg, #B7FEE3)',
|
|
341
344
|
color: 'var(--tags-tag-orange-text, #007C52)',
|
|
342
345
|
borderRadius: 'var(--radius-m, 8px)',
|
|
343
346
|
border: 'none',
|
|
347
|
+
|
|
348
|
+
transition: 'all 0.2s ease-in-out',
|
|
349
|
+
position: 'relative',
|
|
350
|
+
cursor: balanceLink ? 'pointer' : 'default',
|
|
351
|
+
'&:hover': balanceLink
|
|
352
|
+
? {
|
|
353
|
+
'& .MuiSvgIcon-root': {
|
|
354
|
+
opacity: 1,
|
|
355
|
+
transform: 'translateX(0)',
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
: undefined,
|
|
344
359
|
}}>
|
|
345
|
-
<
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
360
|
+
<Stack direction="row" alignItems="center" spacing={1}>
|
|
361
|
+
<Stack flex={1}>
|
|
362
|
+
<Typography variant="subtitle1">{t('admin.customer.summary.balance')}</Typography>
|
|
363
|
+
<Typography variant="h4">
|
|
364
|
+
{currentBalance} {subscription.paymentCurrency.symbol}
|
|
365
|
+
</Typography>
|
|
366
|
+
</Stack>
|
|
367
|
+
{balanceLink && (
|
|
368
|
+
<ArrowForwardOutlined
|
|
369
|
+
sx={{
|
|
370
|
+
opacity: 0,
|
|
371
|
+
transform: 'translateX(-10px)',
|
|
372
|
+
transition: 'all 0.2s ease-in-out',
|
|
373
|
+
color: 'inherit',
|
|
374
|
+
}}
|
|
375
|
+
/>
|
|
376
|
+
)}
|
|
377
|
+
</Stack>
|
|
349
378
|
</BalanceCard>
|
|
350
379
|
|
|
351
380
|
<Paper elevation={0} sx={{ mb: 2, mt: 2, backgroundColor: 'background.default' }}>
|
|
@@ -6,6 +6,7 @@ import Toast from '@arcblock/ux/lib/Toast';
|
|
|
6
6
|
import {
|
|
7
7
|
AddressForm,
|
|
8
8
|
CurrencySelector,
|
|
9
|
+
LoadingButton,
|
|
9
10
|
PaymentSummary,
|
|
10
11
|
StripeForm,
|
|
11
12
|
api,
|
|
@@ -20,7 +21,6 @@ import {
|
|
|
20
21
|
} from '@blocklet/payment-react';
|
|
21
22
|
import type { TCustomer, TPaymentCurrency, TPaymentMethod, TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
22
23
|
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
23
|
-
import { LoadingButton } from '@mui/lab';
|
|
24
24
|
import { Alert, CircularProgress, Stack, Typography } from '@mui/material';
|
|
25
25
|
import { styled } from '@mui/system';
|
|
26
26
|
import { useRequest, useSetState } from 'ahooks';
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
3
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
4
4
|
import {
|
|
5
|
+
LoadingButton,
|
|
5
6
|
PricingTable,
|
|
6
7
|
api,
|
|
7
8
|
formatBNStr,
|
|
@@ -12,7 +13,6 @@ import {
|
|
|
12
13
|
} from '@blocklet/payment-react';
|
|
13
14
|
import type { TLineItemExpanded, TPricingTableExpanded, TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
14
15
|
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
15
|
-
import { LoadingButton } from '@mui/lab';
|
|
16
16
|
import { Alert, CircularProgress, Divider, Stack, Typography } from '@mui/material';
|
|
17
17
|
import { useRequest, useSetState } from 'ahooks';
|
|
18
18
|
import { useRef } from 'react';
|
|
@@ -53,7 +53,7 @@ export default function CustomerSubscriptionChangePlan() {
|
|
|
53
53
|
const navigate = useNavigate();
|
|
54
54
|
const { id } = useParams() as { id: string };
|
|
55
55
|
const { t, locale } = useLocaleContext();
|
|
56
|
-
const { connect } = usePaymentContext();
|
|
56
|
+
const { connect, session } = usePaymentContext();
|
|
57
57
|
const [searchParams] = useSearchParams();
|
|
58
58
|
const redirectUrl = searchParams.get('redirectUrl');
|
|
59
59
|
const confirmRef = useRef<HTMLButtonElement>(null);
|
|
@@ -164,6 +164,7 @@ export default function CustomerSubscriptionChangePlan() {
|
|
|
164
164
|
extraParams: {
|
|
165
165
|
invoiceId: result.data.pending_update?.updates?.latest_invoice_id,
|
|
166
166
|
subscriptionId: result.data.id,
|
|
167
|
+
sessionUserDid: session?.user?.did,
|
|
167
168
|
},
|
|
168
169
|
onSuccess: () => {
|
|
169
170
|
setState({ paid: true, paying: false });
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
-
import { Box,
|
|
2
|
+
import { Box, Grid, Typography, Divider } from '@mui/material';
|
|
3
3
|
import { useNavigate } from 'react-router-dom';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Link as LinkIcon,
|
|
6
|
+
Payment,
|
|
7
|
+
Code,
|
|
8
|
+
Inventory2Outlined,
|
|
9
|
+
TableChartOutlined,
|
|
10
|
+
FavoriteBorderOutlined,
|
|
11
|
+
} from '@mui/icons-material';
|
|
5
12
|
|
|
6
13
|
const basicFeatures = [
|
|
7
14
|
{
|
|
8
15
|
title: 'integrations.features.products.title',
|
|
9
16
|
description: 'integrations.features.products.intro',
|
|
10
|
-
icon: <
|
|
17
|
+
icon: <Inventory2Outlined sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
11
18
|
path: '/admin/products',
|
|
12
19
|
},
|
|
13
20
|
{
|
|
14
21
|
title: 'integrations.features.paymentLinks.title',
|
|
15
22
|
description: 'integrations.features.paymentLinks.intro',
|
|
16
|
-
icon: <LinkIcon
|
|
23
|
+
icon: <LinkIcon sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
17
24
|
path: '/admin/products/links',
|
|
18
25
|
},
|
|
19
26
|
{
|
|
20
27
|
title: 'integrations.features.pricingTables.title',
|
|
21
28
|
description: 'integrations.features.pricingTables.intro',
|
|
22
|
-
icon: <
|
|
29
|
+
icon: <TableChartOutlined sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
23
30
|
path: '/admin/products/pricing-tables',
|
|
24
31
|
},
|
|
25
32
|
];
|
|
@@ -28,20 +35,20 @@ const advancedFeatures = [
|
|
|
28
35
|
{
|
|
29
36
|
title: 'integrations.features.donate.title',
|
|
30
37
|
description: 'integrations.features.donate.intro',
|
|
31
|
-
icon: <
|
|
38
|
+
icon: <FavoriteBorderOutlined sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
32
39
|
path: '/integrations/donations',
|
|
33
40
|
},
|
|
34
41
|
{
|
|
35
42
|
title: 'integrations.features.paymentMethods.title',
|
|
36
43
|
description: 'integrations.features.paymentMethods.intro',
|
|
37
|
-
icon: <Payment
|
|
44
|
+
icon: <Payment sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
38
45
|
path: '/admin/settings/payment-methods',
|
|
39
46
|
},
|
|
40
47
|
{
|
|
41
48
|
title: 'integrations.features.api.title',
|
|
42
49
|
description: 'integrations.features.api.intro',
|
|
43
|
-
icon: <Code
|
|
44
|
-
path: 'https://www.
|
|
50
|
+
icon: <Code sx={{ fontSize: 32, color: 'text.lighter' }} />,
|
|
51
|
+
path: 'https://www.arcblock.io/docs/arcblock-payment-kit/en/start-payment-js',
|
|
45
52
|
external: true,
|
|
46
53
|
},
|
|
47
54
|
];
|
|
@@ -61,7 +68,7 @@ export default function Overview() {
|
|
|
61
68
|
return (
|
|
62
69
|
<Box>
|
|
63
70
|
<Box mb={4}>
|
|
64
|
-
<Typography variant="h2" gutterBottom fontWeight="bold" mb={
|
|
71
|
+
<Typography variant="h2" gutterBottom fontWeight="bold" mb={1}>
|
|
65
72
|
{t('common.welcome')}
|
|
66
73
|
</Typography>
|
|
67
74
|
<Typography variant="body1" color="text.secondary" mb={2}>
|
|
@@ -69,50 +76,66 @@ export default function Overview() {
|
|
|
69
76
|
</Typography>
|
|
70
77
|
</Box>
|
|
71
78
|
|
|
72
|
-
<Typography variant="
|
|
79
|
+
<Typography variant="h3" gutterBottom mb={2}>
|
|
73
80
|
{t('integrations.basicFeatures')} 🚀
|
|
74
81
|
</Typography>
|
|
75
|
-
<Grid container spacing={
|
|
82
|
+
<Grid container spacing={2} mb={4} sx={{ maxWidth: 1200 }}>
|
|
76
83
|
{basicFeatures.map((item) => (
|
|
77
84
|
<Grid item xs={12} sm={6} md={4} key={item.path}>
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
<Box
|
|
86
|
+
className="base-card"
|
|
87
|
+
onClick={() => handleClick(item)}
|
|
88
|
+
sx={{
|
|
89
|
+
height: '100%',
|
|
90
|
+
cursor: 'pointer',
|
|
91
|
+
'&:hover': {
|
|
92
|
+
boxShadow:
|
|
93
|
+
'0px 0px 0px 1px var(--shadows-card-hover-1, rgba(2, 7, 19, 0.08)), 0px 1px 2px -1px var(--shadows-card-hover-2, rgba(2, 7, 19, 0.08)), 0px 2px 8px 0px var(--shadows-card-hover-3, rgba(2, 7, 19, 0.10))',
|
|
94
|
+
},
|
|
95
|
+
}}>
|
|
96
|
+
<Box mb={1}>
|
|
97
|
+
{item.icon}
|
|
98
|
+
<Typography variant="h4" mt={1.5}>
|
|
99
|
+
{t(item.title)}
|
|
100
|
+
</Typography>
|
|
101
|
+
</Box>
|
|
102
|
+
<Typography variant="body2" color="text.secondary">
|
|
103
|
+
{t(item.description)}
|
|
104
|
+
</Typography>
|
|
105
|
+
</Box>
|
|
91
106
|
</Grid>
|
|
92
107
|
))}
|
|
93
108
|
</Grid>
|
|
94
109
|
|
|
95
110
|
<Divider sx={{ my: 4 }} />
|
|
96
111
|
|
|
97
|
-
<Typography variant="
|
|
112
|
+
<Typography variant="h3" gutterBottom mb={2}>
|
|
98
113
|
{t('integrations.advancedFeatures')} 🔥
|
|
99
114
|
</Typography>
|
|
100
|
-
<Grid container spacing={
|
|
115
|
+
<Grid container spacing={2} sx={{ maxWidth: 1200 }}>
|
|
101
116
|
{advancedFeatures.map((item) => (
|
|
102
117
|
<Grid item xs={12} sm={6} md={4} key={item.path}>
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
<Box
|
|
119
|
+
className="base-card"
|
|
120
|
+
onClick={() => handleClick(item)}
|
|
121
|
+
sx={{
|
|
122
|
+
height: '100%',
|
|
123
|
+
cursor: 'pointer',
|
|
124
|
+
'&:hover': {
|
|
125
|
+
boxShadow:
|
|
126
|
+
'0px 0px 0px 1px var(--shadows-card-hover-1, rgba(2, 7, 19, 0.08)), 0px 1px 2px -1px var(--shadows-card-hover-2, rgba(2, 7, 19, 0.08)), 0px 2px 8px 0px var(--shadows-card-hover-3, rgba(2, 7, 19, 0.10))',
|
|
127
|
+
},
|
|
128
|
+
}}>
|
|
129
|
+
<Box mb={1}>
|
|
130
|
+
{item.icon}
|
|
131
|
+
<Typography variant="h6" mt={1.5}>
|
|
132
|
+
{t(item.title)}
|
|
133
|
+
</Typography>
|
|
134
|
+
</Box>
|
|
135
|
+
<Typography variant="body2" color="text.secondary">
|
|
136
|
+
{t(item.description)}
|
|
137
|
+
</Typography>
|
|
138
|
+
</Box>
|
|
116
139
|
</Grid>
|
|
117
140
|
))}
|
|
118
141
|
</Grid>
|