payment-kit 1.18.39 → 1.18.40
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/subscription.ts +107 -97
- package/api/src/routes/checkout-sessions.ts +3 -1
- package/api/src/routes/subscriptions.ts +3 -1
- package/blocklet.yml +1 -1
- package/package.json +9 -9
- package/scripts/sdk.js +27 -1
- package/src/components/customer/link.tsx +6 -0
- package/src/components/info-card.tsx +2 -2
- package/src/components/info-metric.tsx +1 -1
- package/src/components/metadata/list.tsx +4 -2
- package/src/components/subscription/description.tsx +8 -6
- package/src/components/subscription/portal/actions.tsx +105 -36
- package/src/components/subscription/portal/list.tsx +152 -74
- package/src/components/subscription/status.tsx +17 -5
- package/src/locales/en.tsx +12 -7
- package/src/locales/zh.tsx +6 -2
- package/src/pages/admin/billing/invoices/detail.tsx +1 -5
- package/src/pages/admin/billing/subscriptions/detail.tsx +1 -5
- package/src/pages/admin/customers/customers/detail.tsx +1 -5
- package/src/pages/admin/developers/events/detail.tsx +1 -5
- package/src/pages/admin/developers/index.tsx +1 -1
- package/src/pages/admin/developers/webhooks/detail.tsx +1 -3
- package/src/pages/admin/overview.tsx +4 -4
- package/src/pages/admin/payments/intents/detail.tsx +1 -5
- package/src/pages/admin/payments/payouts/detail.tsx +1 -5
- package/src/pages/admin/payments/refunds/detail.tsx +1 -5
- package/src/pages/admin/products/links/detail.tsx +1 -5
- package/src/pages/admin/products/prices/detail.tsx +1 -5
- package/src/pages/admin/products/pricing-tables/detail.tsx +1 -5
- package/src/pages/admin/products/products/detail.tsx +1 -5
- package/src/pages/admin/settings/payment-methods/index.tsx +1 -1
- package/src/pages/customer/index.tsx +67 -138
- package/src/pages/customer/payout/detail.tsx +37 -49
- package/src/pages/customer/subscription/change-payment.tsx +2 -35
- package/src/pages/customer/subscription/detail.tsx +1 -5
- package/src/pages/integrations/donations/index.tsx +1 -1
- package/src/pages/integrations/overview.tsx +1 -1
|
@@ -1354,126 +1354,136 @@ export async function slashOverdraftProtectionStake(subscription: Subscription,
|
|
|
1354
1354
|
|
|
1355
1355
|
let slashAmount = new BN(0);
|
|
1356
1356
|
const slashInvoices: Invoice[] = [];
|
|
1357
|
-
const
|
|
1357
|
+
for (const invoice of invoices) {
|
|
1358
1358
|
if (!invoice.payment_intent_id) {
|
|
1359
1359
|
await emitAsync(
|
|
1360
1360
|
'invoice.queued',
|
|
1361
1361
|
invoice.id,
|
|
1362
1362
|
{ invoiceId: invoice.id, retryOnError: false, justCreate: true },
|
|
1363
|
-
{
|
|
1364
|
-
sync: true,
|
|
1365
|
-
}
|
|
1363
|
+
{ sync: true }
|
|
1366
1364
|
);
|
|
1367
1365
|
await invoice.reload();
|
|
1368
1366
|
}
|
|
1367
|
+
|
|
1369
1368
|
const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
|
|
1370
1369
|
if (paymentIntent) {
|
|
1371
|
-
|
|
1370
|
+
const isAlreadyPaid = paymentIntent.status === 'succeeded' && invoice.status === 'paid';
|
|
1371
|
+
|
|
1372
|
+
if (!isAlreadyPaid) {
|
|
1373
|
+
const tmp = slashAmount.add(new BN(invoice.amount_remaining));
|
|
1374
|
+
if (tmp.lte(new BN(remainingStake))) {
|
|
1375
|
+
slashAmount = tmp;
|
|
1376
|
+
slashInvoices.push(invoice);
|
|
1377
|
+
} else {
|
|
1378
|
+
break;
|
|
1379
|
+
}
|
|
1380
|
+
} else {
|
|
1372
1381
|
logger.info('PaymentIntent and Invoice already updated', {
|
|
1373
1382
|
subscription: subscription.id,
|
|
1374
1383
|
paymentIntent: paymentIntent.id,
|
|
1375
1384
|
invoice: invoice.id,
|
|
1376
1385
|
});
|
|
1377
|
-
return;
|
|
1378
1386
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
const slashedInvoiceIds: string[] = [];
|
|
1391
|
+
const processInvoice = async (invoice: Invoice): Promise<void> => {
|
|
1392
|
+
const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
|
|
1393
|
+
if (!paymentIntent || (paymentIntent.status === 'succeeded' && invoice.status === 'paid')) return;
|
|
1394
|
+
|
|
1395
|
+
try {
|
|
1396
|
+
const stakeEnough = await checkRemainingStake(
|
|
1397
|
+
paymentMethod,
|
|
1398
|
+
paymentCurrency,
|
|
1399
|
+
address,
|
|
1400
|
+
invoice.amount_remaining
|
|
1401
|
+
);
|
|
1402
|
+
if (!stakeEnough.enough) {
|
|
1403
|
+
throw new Error(`Stake slashing aborted because no enough staking for invoice: ${invoice.id}`);
|
|
1404
|
+
}
|
|
1405
|
+
// do the slash
|
|
1406
|
+
const signed = await client.signSlashStakeTx({
|
|
1407
|
+
tx: {
|
|
1408
|
+
itx: {
|
|
1388
1409
|
address,
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
}
|
|
1394
|
-
// do the slash
|
|
1395
|
-
const signed = await client.signSlashStakeTx({
|
|
1396
|
-
tx: {
|
|
1397
|
-
itx: {
|
|
1398
|
-
address,
|
|
1399
|
-
outputs: [
|
|
1400
|
-
{
|
|
1401
|
-
owner: wallet.address,
|
|
1402
|
-
tokens: [{ address: paymentCurrency.contract, value: invoice.amount_remaining }],
|
|
1403
|
-
},
|
|
1404
|
-
],
|
|
1405
|
-
message: 'overdraft_exceeded',
|
|
1406
|
-
data: {
|
|
1407
|
-
typeUrl: 'json',
|
|
1408
|
-
// @ts-ignore
|
|
1409
|
-
value: {
|
|
1410
|
-
appId: wallet.address,
|
|
1411
|
-
reason: 'overdraft_exceeded',
|
|
1412
|
-
subscriptionId: subscription.id,
|
|
1413
|
-
invoiceId: invoice.id,
|
|
1414
|
-
paymentIntentId: paymentIntent.id,
|
|
1415
|
-
},
|
|
1416
|
-
},
|
|
1410
|
+
outputs: [
|
|
1411
|
+
{
|
|
1412
|
+
owner: wallet.address,
|
|
1413
|
+
tokens: [{ address: paymentCurrency.contract, value: invoice.amount_remaining }],
|
|
1417
1414
|
},
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
capture_method: 'manual',
|
|
1430
|
-
last_payment_error: null,
|
|
1431
|
-
payment_details: {
|
|
1432
|
-
arcblock: {
|
|
1433
|
-
tx_hash: txHash,
|
|
1434
|
-
payer:
|
|
1435
|
-
subscription.overdraft_protection?.payment_details?.arcblock?.payer ||
|
|
1436
|
-
getSubscriptionPaymentAddress(subscription, 'arcblock'),
|
|
1437
|
-
type: 'slash',
|
|
1415
|
+
],
|
|
1416
|
+
message: 'overdraft_exceeded',
|
|
1417
|
+
data: {
|
|
1418
|
+
typeUrl: 'json',
|
|
1419
|
+
// @ts-ignore
|
|
1420
|
+
value: {
|
|
1421
|
+
appId: wallet.address,
|
|
1422
|
+
reason: 'overdraft_exceeded',
|
|
1423
|
+
subscriptionId: subscription.id,
|
|
1424
|
+
invoiceId: invoice.id,
|
|
1425
|
+
paymentIntentId: paymentIntent.id,
|
|
1438
1426
|
},
|
|
1439
1427
|
},
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1428
|
+
},
|
|
1429
|
+
},
|
|
1430
|
+
wallet,
|
|
1431
|
+
});
|
|
1432
|
+
// @ts-ignore
|
|
1433
|
+
const { buffer } = await client.encodeSlashStakeTx({ tx: signed });
|
|
1434
|
+
// @ts-ignore
|
|
1435
|
+
const txHash = await client.sendSlashStakeTx({ tx: signed, wallet }, getGasPayerExtra(buffer));
|
|
1436
|
+
|
|
1437
|
+
await paymentIntent.update({
|
|
1438
|
+
status: 'succeeded',
|
|
1439
|
+
amount_received: invoice.amount_remaining,
|
|
1440
|
+
capture_method: 'manual',
|
|
1441
|
+
last_payment_error: null,
|
|
1442
|
+
payment_details: {
|
|
1443
|
+
arcblock: {
|
|
1444
|
+
tx_hash: txHash,
|
|
1445
|
+
payer:
|
|
1446
|
+
subscription.overdraft_protection?.payment_details?.arcblock?.payer ||
|
|
1447
|
+
getSubscriptionPaymentAddress(subscription, 'arcblock'),
|
|
1448
|
+
type: 'slash',
|
|
1449
|
+
},
|
|
1450
|
+
},
|
|
1451
|
+
});
|
|
1452
|
+
logger.info('PaymentIntent updated after stake slash', {
|
|
1453
|
+
subscription: subscription.id,
|
|
1454
|
+
paymentIntent: paymentIntent.id,
|
|
1455
|
+
status: 'succeeded',
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
await invoice.update({
|
|
1459
|
+
status: 'paid',
|
|
1460
|
+
paid: true,
|
|
1461
|
+
amount_paid: invoice.amount_remaining,
|
|
1462
|
+
amount_remaining: '0',
|
|
1463
|
+
attempted: true,
|
|
1464
|
+
attempt_count: invoice.attempt_count + 1,
|
|
1465
|
+
status_transitions: { ...invoice.status_transitions, paid_at: dayjs().unix() },
|
|
1466
|
+
});
|
|
1467
|
+
logger.info('Invoice updated after stake slash', {
|
|
1468
|
+
subscription: subscription.id,
|
|
1469
|
+
invoice: invoice.id,
|
|
1470
|
+
status: 'paid',
|
|
1471
|
+
});
|
|
1472
|
+
slashedInvoiceIds.push(invoice.id);
|
|
1473
|
+
} catch (updateError) {
|
|
1474
|
+
logger.error('stake slash failed', {
|
|
1475
|
+
subscription: subscription.id,
|
|
1476
|
+
invoice: invoice.id,
|
|
1477
|
+
error: updateError,
|
|
1478
|
+
});
|
|
1479
|
+
throw updateError;
|
|
1470
1480
|
}
|
|
1471
|
-
}
|
|
1481
|
+
};
|
|
1472
1482
|
|
|
1473
|
-
await Promise.all(
|
|
1474
|
-
logger.info(`${
|
|
1483
|
+
await Promise.all(slashInvoices.map(processInvoice));
|
|
1484
|
+
logger.info(`${slashedInvoiceIds.length} invoices updated after stake slash`, {
|
|
1475
1485
|
subscription: subscription.id,
|
|
1476
|
-
invoices:
|
|
1486
|
+
invoices: slashedInvoiceIds,
|
|
1477
1487
|
slashAmount: slashAmount.toString(),
|
|
1478
1488
|
});
|
|
1479
1489
|
} catch (error) {
|
|
@@ -346,7 +346,9 @@ const SubscriptionDataSchema = Joi.object({
|
|
|
346
346
|
color: Joi.string().valid('primary', 'secondary', 'success', 'error', 'warning').optional(),
|
|
347
347
|
variant: Joi.string().valid('text', 'contained', 'outlined').optional(),
|
|
348
348
|
text: Joi.object().required(),
|
|
349
|
-
link: Joi.
|
|
349
|
+
link: Joi.alternatives()
|
|
350
|
+
.try(Joi.string().uri(), Joi.string().pattern(/^\/[^\s]*$/))
|
|
351
|
+
.required(),
|
|
350
352
|
type: Joi.string().valid('notification', 'custom').optional(),
|
|
351
353
|
triggerEvents: Joi.array().items(Joi.string()).optional(),
|
|
352
354
|
})
|
|
@@ -691,7 +691,9 @@ const updateSchema = Joi.object<{
|
|
|
691
691
|
color: Joi.string().valid('primary', 'secondary', 'success', 'error', 'warning').optional(),
|
|
692
692
|
variant: Joi.string().valid('text', 'contained', 'outlined').optional(),
|
|
693
693
|
text: Joi.object().required(),
|
|
694
|
-
link: Joi.
|
|
694
|
+
link: Joi.alternatives()
|
|
695
|
+
.try(Joi.string().uri(), Joi.string().pattern(/^\/[^\s]*$/))
|
|
696
|
+
.required(),
|
|
695
697
|
type: Joi.string().valid('notification', 'custom').optional(),
|
|
696
698
|
triggerEvents: Joi.array().items(Joi.string()).optional(),
|
|
697
699
|
})
|
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.40",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -47,18 +47,18 @@
|
|
|
47
47
|
"@abtnode/cron": "^1.16.42",
|
|
48
48
|
"@arcblock/did": "^1.20.6",
|
|
49
49
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
50
|
-
"@arcblock/did-connect": "^2.13.
|
|
50
|
+
"@arcblock/did-connect": "^2.13.24",
|
|
51
51
|
"@arcblock/did-util": "^1.20.6",
|
|
52
52
|
"@arcblock/jwt": "^1.20.6",
|
|
53
|
-
"@arcblock/ux": "^2.13.
|
|
53
|
+
"@arcblock/ux": "^2.13.24",
|
|
54
54
|
"@arcblock/validator": "^1.20.6",
|
|
55
|
-
"@blocklet/did-space-js": "^1.0.
|
|
55
|
+
"@blocklet/did-space-js": "^1.0.51",
|
|
56
56
|
"@blocklet/js-sdk": "^1.16.42",
|
|
57
57
|
"@blocklet/logger": "^1.16.42",
|
|
58
|
-
"@blocklet/payment-react": "1.18.
|
|
58
|
+
"@blocklet/payment-react": "1.18.40",
|
|
59
59
|
"@blocklet/sdk": "^1.16.42",
|
|
60
|
-
"@blocklet/ui-react": "^2.13.
|
|
61
|
-
"@blocklet/uploader": "^0.1.
|
|
60
|
+
"@blocklet/ui-react": "^2.13.24",
|
|
61
|
+
"@blocklet/uploader": "^0.1.89",
|
|
62
62
|
"@blocklet/xss": "^0.1.34",
|
|
63
63
|
"@mui/icons-material": "^5.16.6",
|
|
64
64
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"devDependencies": {
|
|
124
124
|
"@abtnode/types": "^1.16.42",
|
|
125
125
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
126
|
-
"@blocklet/payment-types": "1.18.
|
|
126
|
+
"@blocklet/payment-types": "1.18.40",
|
|
127
127
|
"@types/cookie-parser": "^1.4.7",
|
|
128
128
|
"@types/cors": "^2.8.17",
|
|
129
129
|
"@types/debug": "^4.1.12",
|
|
@@ -169,5 +169,5 @@
|
|
|
169
169
|
"parser": "typescript"
|
|
170
170
|
}
|
|
171
171
|
},
|
|
172
|
-
"gitHead": "
|
|
172
|
+
"gitHead": "53abc664b88898a7cb9afa494f4ace333b1afe9c"
|
|
173
173
|
}
|
package/scripts/sdk.js
CHANGED
|
@@ -196,6 +196,32 @@ const checkoutModule = {
|
|
|
196
196
|
console.log('createCheckoutWithSettingId', checkoutSession);
|
|
197
197
|
return { setting, checkoutSession };
|
|
198
198
|
},
|
|
199
|
+
|
|
200
|
+
async createCheckoutWithServiceAction() {
|
|
201
|
+
const checkoutSession = await payment.checkout.sessions.create({
|
|
202
|
+
mode: 'subscription',
|
|
203
|
+
line_items: [{ price_id: 'price_fQFIS12yi0JR3KePLmitjrhA', quantity: 1 }],
|
|
204
|
+
subscription_data: {
|
|
205
|
+
service_actions: [
|
|
206
|
+
{
|
|
207
|
+
text: {
|
|
208
|
+
zh: '全链接测试',
|
|
209
|
+
en: 'Full Link Test',
|
|
210
|
+
},
|
|
211
|
+
link: 'https://baidu.com',
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
text: {
|
|
215
|
+
zh: '相对路径访问',
|
|
216
|
+
en: 'Relative Path Access',
|
|
217
|
+
},
|
|
218
|
+
link: '/.well-known/service/user/notifications',
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
console.log('createCheckoutWithServiceAction', checkoutSession);
|
|
224
|
+
},
|
|
199
225
|
};
|
|
200
226
|
|
|
201
227
|
const paymentModule = {
|
|
@@ -515,7 +541,6 @@ const subscriptionModule = {
|
|
|
515
541
|
},
|
|
516
542
|
};
|
|
517
543
|
|
|
518
|
-
// 测试模块注册
|
|
519
544
|
const testModules = {
|
|
520
545
|
checkout: checkoutModule,
|
|
521
546
|
payment: paymentModule,
|
|
@@ -523,6 +548,7 @@ const testModules = {
|
|
|
523
548
|
subscription: subscriptionModule,
|
|
524
549
|
};
|
|
525
550
|
|
|
551
|
+
// 测试入口
|
|
526
552
|
async function runTest() {
|
|
527
553
|
payment.environments.setTestMode(true);
|
|
528
554
|
await testModules.checkout.createBatchSubscriptionWithCustomField();
|
|
@@ -2,18 +2,21 @@ import type { TCustomer } from '@blocklet/payment-types';
|
|
|
2
2
|
import { Link } from 'react-router-dom';
|
|
3
3
|
import UserCard from '@arcblock/ux/lib/UserCard';
|
|
4
4
|
import { getCustomerAvatar } from '@blocklet/payment-react';
|
|
5
|
+
import { InfoType, UserCardProps } from '@arcblock/ux/lib/UserCard/types';
|
|
5
6
|
|
|
6
7
|
export default function CustomerLink({
|
|
7
8
|
customer,
|
|
8
9
|
linked,
|
|
9
10
|
linkTo,
|
|
10
11
|
size,
|
|
12
|
+
cardProps,
|
|
11
13
|
}: {
|
|
12
14
|
customer: TCustomer;
|
|
13
15
|
linked?: boolean;
|
|
14
16
|
linkTo?: string;
|
|
15
17
|
size?: 'default' | 'small';
|
|
16
18
|
tooltip?: boolean;
|
|
19
|
+
cardProps?: UserCardProps;
|
|
17
20
|
}) {
|
|
18
21
|
if (!customer) {
|
|
19
22
|
return null;
|
|
@@ -31,6 +34,7 @@ export default function CustomerLink({
|
|
|
31
34
|
avatarProps={{
|
|
32
35
|
size: size === 'small' ? 24 : 40,
|
|
33
36
|
}}
|
|
37
|
+
popupInfoType={InfoType.Minimal}
|
|
34
38
|
showDid={size !== 'small'}
|
|
35
39
|
{...(customer.metadata.anonymous === true
|
|
36
40
|
? {
|
|
@@ -45,6 +49,7 @@ export default function CustomerLink({
|
|
|
45
49
|
},
|
|
46
50
|
}
|
|
47
51
|
: {})}
|
|
52
|
+
{...cardProps}
|
|
48
53
|
/>
|
|
49
54
|
);
|
|
50
55
|
if (linked) {
|
|
@@ -59,4 +64,5 @@ CustomerLink.defaultProps = {
|
|
|
59
64
|
linkTo: '',
|
|
60
65
|
size: 'default',
|
|
61
66
|
tooltip: true,
|
|
67
|
+
cardProps: {},
|
|
62
68
|
};
|
|
@@ -41,11 +41,11 @@ export default function InfoCard(props: Props) {
|
|
|
41
41
|
wordBreak: getWordBreakStyle(props.name),
|
|
42
42
|
minWidth: 140,
|
|
43
43
|
}}>
|
|
44
|
-
<Typography variant="
|
|
44
|
+
<Typography variant="body2" color="text.primary" component="div">
|
|
45
45
|
{props.name}
|
|
46
46
|
</Typography>
|
|
47
47
|
{props.description && (
|
|
48
|
-
<Typography variant="
|
|
48
|
+
<Typography variant="subtitle2" color="text.secondary">
|
|
49
49
|
{props.description}
|
|
50
50
|
</Typography>
|
|
51
51
|
)}
|
|
@@ -16,7 +16,7 @@ export default function InfoMetric(props: Props) {
|
|
|
16
16
|
return (
|
|
17
17
|
<>
|
|
18
18
|
<Stack direction="column" alignItems="flex-start">
|
|
19
|
-
<Typography component="div" variant="
|
|
19
|
+
<Typography component="div" variant="subtitle2" mb={1} color="text.primary">
|
|
20
20
|
{props.label}
|
|
21
21
|
{!!props.tip && (
|
|
22
22
|
<Tooltip title={props.tip}>
|
|
@@ -18,10 +18,12 @@ export default function MetadataList({
|
|
|
18
18
|
if (isEmpty(data)) {
|
|
19
19
|
return (
|
|
20
20
|
<Box sx={{ textAlign: 'center' }}>
|
|
21
|
-
<Typography color="text.primary"
|
|
21
|
+
<Typography variant="subtitle1" color="text.primary">
|
|
22
22
|
{t('common.metadata.empty')}
|
|
23
23
|
</Typography>
|
|
24
|
-
<Typography color="text.lighter">
|
|
24
|
+
<Typography variant="body2" color="text.lighter">
|
|
25
|
+
{t('common.metadata.emptyTip')}
|
|
26
|
+
</Typography>
|
|
25
27
|
<Button sx={{ color: 'text.link' }} onClick={handleEditMetadata}>
|
|
26
28
|
{t('common.add')}
|
|
27
29
|
</Button>
|
|
@@ -5,17 +5,18 @@ import { Stack, Tooltip, Typography } from '@mui/material';
|
|
|
5
5
|
|
|
6
6
|
type Props = {
|
|
7
7
|
subscription: TSubscriptionExpanded;
|
|
8
|
-
variant?: 'body1' | 'h5' | 'h4' | 'h3' | 'h2' | 'h1';
|
|
8
|
+
variant?: 'subtitle1' | 'subtitle2' | 'body1' | 'body2' | 'h5' | 'h4' | 'h3' | 'h2' | 'h1';
|
|
9
9
|
hideSubscription?: boolean;
|
|
10
|
+
maxLength?: number;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export default function SubscriptionDescription({ subscription, variant, hideSubscription }: Props) {
|
|
13
|
+
export default function SubscriptionDescription({ subscription, variant, hideSubscription, maxLength = 80 }: Props) {
|
|
13
14
|
const { isMobile } = useMobile();
|
|
14
15
|
if (subscription.description) {
|
|
15
16
|
return (
|
|
16
17
|
<Stack direction="row" alignItems="center" spacing={1}>
|
|
17
|
-
<Typography variant={variant}
|
|
18
|
-
<TruncatedText text={subscription.description} maxLength={
|
|
18
|
+
<Typography variant={variant} className="subscription-description">
|
|
19
|
+
<TruncatedText text={subscription.description} maxLength={maxLength} useWidth />
|
|
19
20
|
</Typography>
|
|
20
21
|
{!hideSubscription && !isMobile && (
|
|
21
22
|
<Tooltip title={formatSubscriptionProduct(subscription.items)}>
|
|
@@ -27,8 +28,8 @@ export default function SubscriptionDescription({ subscription, variant, hideSub
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
|
-
<Typography variant={variant}
|
|
31
|
-
{formatSubscriptionProduct(subscription.items)}
|
|
31
|
+
<Typography variant={variant}>
|
|
32
|
+
<TruncatedText text={formatSubscriptionProduct(subscription.items)} maxLength={maxLength} useWidth />
|
|
32
33
|
</Typography>
|
|
33
34
|
);
|
|
34
35
|
}
|
|
@@ -36,4 +37,5 @@ export default function SubscriptionDescription({ subscription, variant, hideSub
|
|
|
36
37
|
SubscriptionDescription.defaultProps = {
|
|
37
38
|
variant: 'body1',
|
|
38
39
|
hideSubscription: false,
|
|
40
|
+
maxLength: 80,
|
|
39
41
|
};
|