@blocklet/payment-react 1.13.210 → 1.13.212
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/es/checkout/donate.d.ts +20 -0
- package/es/checkout/donate.js +199 -0
- package/es/checkout/form.d.ts +2 -1
- package/es/checkout/form.js +13 -2
- package/es/components/blockchain/tx.d.ts +2 -0
- package/es/components/blockchain/tx.js +16 -5
- package/es/components/safe-guard.d.ts +3 -0
- package/es/components/safe-guard.js +4 -0
- package/es/index.d.ts +3 -1
- package/es/index.js +5 -1
- package/es/locales/en.js +8 -0
- package/es/locales/zh.js +8 -0
- package/es/payment/error.d.ts +3 -1
- package/es/payment/error.js +4 -3
- package/es/payment/form/currency.js +10 -12
- package/es/payment/form/index.d.ts +1 -1
- package/es/payment/form/index.js +15 -3
- package/es/payment/index.d.ts +3 -3
- package/es/payment/index.js +38 -13
- package/es/payment/product-donation.d.ts +7 -0
- package/es/payment/product-donation.js +99 -0
- package/es/payment/skeleton/overview.js +2 -2
- package/es/payment/skeleton/payment.js +2 -5
- package/es/payment/success.d.ts +2 -1
- package/es/payment/success.js +21 -12
- package/es/payment/summary.d.ts +8 -2
- package/es/payment/summary.js +46 -29
- package/es/types/index.d.ts +2 -0
- package/es/util.d.ts +2 -0
- package/es/util.js +47 -3
- package/lib/checkout/donate.d.ts +20 -0
- package/lib/checkout/donate.js +284 -0
- package/lib/checkout/form.d.ts +2 -1
- package/lib/checkout/form.js +5 -2
- package/lib/components/blockchain/tx.d.ts +2 -0
- package/lib/components/blockchain/tx.js +3 -1
- package/lib/components/safe-guard.d.ts +3 -0
- package/lib/components/safe-guard.js +12 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.js +16 -0
- package/lib/locales/en.js +8 -0
- package/lib/locales/zh.js +8 -0
- package/lib/payment/error.d.ts +3 -1
- package/lib/payment/error.js +5 -3
- package/lib/payment/form/currency.js +10 -12
- package/lib/payment/form/index.d.ts +1 -1
- package/lib/payment/form/index.js +16 -4
- package/lib/payment/index.d.ts +3 -3
- package/lib/payment/index.js +56 -24
- package/lib/payment/product-donation.d.ts +7 -0
- package/lib/payment/product-donation.js +169 -0
- package/lib/payment/skeleton/overview.js +2 -2
- package/lib/payment/skeleton/payment.js +4 -8
- package/lib/payment/success.d.ts +2 -1
- package/lib/payment/success.js +3 -2
- package/lib/payment/summary.d.ts +8 -2
- package/lib/payment/summary.js +30 -7
- package/lib/types/index.d.ts +2 -0
- package/lib/util.d.ts +2 -0
- package/lib/util.js +44 -4
- package/package.json +6 -6
- package/src/checkout/donate.tsx +256 -0
- package/src/checkout/form.tsx +13 -4
- package/src/components/blockchain/tx.tsx +8 -1
- package/src/components/safe-guard.tsx +5 -0
- package/src/index.ts +4 -0
- package/src/locales/en.tsx +8 -0
- package/src/locales/zh.tsx +8 -0
- package/src/payment/error.tsx +4 -2
- package/src/payment/form/currency.tsx +11 -13
- package/src/payment/form/index.tsx +14 -4
- package/src/payment/index.tsx +40 -14
- package/src/payment/product-donation.tsx +118 -0
- package/src/payment/skeleton/overview.tsx +2 -2
- package/src/payment/skeleton/payment.tsx +1 -4
- package/src/payment/success.tsx +7 -2
- package/src/payment/summary.tsx +47 -28
- package/src/types/index.ts +2 -0
- package/src/util.ts +54 -3
package/lib/util.js
CHANGED
|
@@ -24,6 +24,7 @@ exports.formatUpsellSaving = formatUpsellSaving;
|
|
|
24
24
|
exports.getCheckoutAmount = getCheckoutAmount;
|
|
25
25
|
exports.getInvoiceStatusColor = getInvoiceStatusColor;
|
|
26
26
|
exports.getPaymentIntentStatusColor = getPaymentIntentStatusColor;
|
|
27
|
+
exports.getPayoutStatusColor = getPayoutStatusColor;
|
|
27
28
|
exports.getPrefix = void 0;
|
|
28
29
|
exports.getPriceCurrencyOptions = getPriceCurrencyOptions;
|
|
29
30
|
exports.getPriceUintAmountByCurrency = getPriceUintAmountByCurrency;
|
|
@@ -34,6 +35,7 @@ exports.getSubscriptionAction = void 0;
|
|
|
34
35
|
exports.getSubscriptionStatusColor = getSubscriptionStatusColor;
|
|
35
36
|
exports.getTxLink = exports.getSubscriptionTimeSummary = void 0;
|
|
36
37
|
exports.getWebhookStatusColor = getWebhookStatusColor;
|
|
38
|
+
exports.isPaymentKitMounted = void 0;
|
|
37
39
|
exports.isValidCountry = isValidCountry;
|
|
38
40
|
exports.mergeExtraParams = void 0;
|
|
39
41
|
exports.sleep = sleep;
|
|
@@ -47,6 +49,10 @@ var _dayjs = _interopRequireDefault(require("./dayjs"));
|
|
|
47
49
|
var _locales = require("./locales");
|
|
48
50
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
49
51
|
const PAYMENT_KIT_DID = exports.PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
52
|
+
const isPaymentKitMounted = () => {
|
|
53
|
+
return (window.blocklet?.componentMountPoints || []).some(x => x.did === PAYMENT_KIT_DID);
|
|
54
|
+
};
|
|
55
|
+
exports.isPaymentKitMounted = isPaymentKitMounted;
|
|
50
56
|
const getPrefix = () => {
|
|
51
57
|
const componentId = (window?.blocklet?.componentId || "").split("/").pop();
|
|
52
58
|
if (componentId === PAYMENT_KIT_DID) {
|
|
@@ -129,6 +135,9 @@ function formatNumber(n, precision = 6, trim = true) {
|
|
|
129
135
|
return trim ? (0, _trimEnd.default)(num.format(options), "0.") : num.format(options);
|
|
130
136
|
}
|
|
131
137
|
const formatPrice = (price, currency, unit_label, quantity = 1, bn = true, locale = "en") => {
|
|
138
|
+
if (price.custom_unit_amount) {
|
|
139
|
+
return `Custom (${currency.symbol})`;
|
|
140
|
+
}
|
|
132
141
|
const unit = getPriceUintAmountByCurrency(price, currency);
|
|
133
142
|
const amount = bn ? (0, _util.fromUnitToToken)(new _util.BN(unit).mul(new _util.BN(quantity)), currency.decimal).toString() : +unit * quantity;
|
|
134
143
|
if (price?.type === "recurring" && price.recurring) {
|
|
@@ -198,9 +207,15 @@ function getPriceUintAmountByCurrency(price, currency) {
|
|
|
198
207
|
const options = getPriceCurrencyOptions(price);
|
|
199
208
|
const option = options.find(x => x.currency_id === currency.id);
|
|
200
209
|
if (option) {
|
|
210
|
+
if (option.custom_unit_amount) {
|
|
211
|
+
return option.custom_unit_amount.preset || option.custom_unit_amount.presets[0];
|
|
212
|
+
}
|
|
201
213
|
return option.unit_amount;
|
|
202
214
|
}
|
|
203
215
|
if (price.currency_id === currency.id) {
|
|
216
|
+
if (price.custom_unit_amount) {
|
|
217
|
+
return price.custom_unit_amount.preset || price.custom_unit_amount.presets[0];
|
|
218
|
+
}
|
|
204
219
|
return price.unit_amount;
|
|
205
220
|
}
|
|
206
221
|
console.warn(`Currency ${currency.id} not configured for price`, price);
|
|
@@ -213,8 +228,8 @@ function getPriceCurrencyOptions(price) {
|
|
|
213
228
|
return [{
|
|
214
229
|
currency_id: price.currency_id,
|
|
215
230
|
unit_amount: price.unit_amount,
|
|
216
|
-
|
|
217
|
-
|
|
231
|
+
custom_unit_amount: price.custom_unit_amount || null,
|
|
232
|
+
tiers: null
|
|
218
233
|
}];
|
|
219
234
|
}
|
|
220
235
|
function formatLineItemPricing(item, currency, trial, locale = "en") {
|
|
@@ -305,6 +320,19 @@ function getRefundStatusColor(status) {
|
|
|
305
320
|
return "default";
|
|
306
321
|
}
|
|
307
322
|
}
|
|
323
|
+
function getPayoutStatusColor(status) {
|
|
324
|
+
switch (status) {
|
|
325
|
+
case "paid":
|
|
326
|
+
return "success";
|
|
327
|
+
case "failed":
|
|
328
|
+
return "warning";
|
|
329
|
+
case "canceled":
|
|
330
|
+
case "pending":
|
|
331
|
+
case "in_transit":
|
|
332
|
+
default:
|
|
333
|
+
return "default";
|
|
334
|
+
}
|
|
335
|
+
}
|
|
308
336
|
function getInvoiceStatusColor(status) {
|
|
309
337
|
switch (status) {
|
|
310
338
|
case "paid":
|
|
@@ -329,14 +357,26 @@ function getWebhookStatusColor(status) {
|
|
|
329
357
|
}
|
|
330
358
|
}
|
|
331
359
|
function getCheckoutAmount(items, currency, trialing = false, upsell = true) {
|
|
360
|
+
if (items.find(x => (x.upsell_price || x.price).custom_unit_amount) && items.length > 1) {
|
|
361
|
+
throw new Error("Multiple items with custom unit amount are not supported");
|
|
362
|
+
}
|
|
332
363
|
let renew = new _util.BN(0);
|
|
333
364
|
const total = items.filter(x => {
|
|
334
365
|
const price = upsell ? x.upsell_price || x.price : x.price;
|
|
335
366
|
return price != null;
|
|
336
367
|
}).reduce((acc, x) => {
|
|
368
|
+
if (x.custom_amount) {
|
|
369
|
+
return acc.add(new _util.BN(x.custom_amount));
|
|
370
|
+
}
|
|
337
371
|
const price = upsell ? x.upsell_price || x.price : x.price;
|
|
372
|
+
const unitPrice = getPriceUintAmountByCurrency(price, currency);
|
|
373
|
+
if (price.custom_unit_amount) {
|
|
374
|
+
if (unitPrice) {
|
|
375
|
+
return acc.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
338
378
|
if (price?.type === "recurring") {
|
|
339
|
-
renew = renew.add(new _util.BN(
|
|
379
|
+
renew = renew.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
|
|
340
380
|
if (trialing) {
|
|
341
381
|
return acc;
|
|
342
382
|
}
|
|
@@ -344,7 +384,7 @@ function getCheckoutAmount(items, currency, trialing = false, upsell = true) {
|
|
|
344
384
|
return acc;
|
|
345
385
|
}
|
|
346
386
|
}
|
|
347
|
-
return acc.add(new _util.BN(
|
|
387
|
+
return acc.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
|
|
348
388
|
}, new _util.BN(0)).toString();
|
|
349
389
|
return {
|
|
350
390
|
subtotal: total,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.212",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@arcblock/did-connect": "^2.9.
|
|
56
|
-
"@arcblock/ux": "^2.9.
|
|
55
|
+
"@arcblock/did-connect": "^2.9.66",
|
|
56
|
+
"@arcblock/ux": "^2.9.66",
|
|
57
57
|
"@mui/icons-material": "^5.15.14",
|
|
58
58
|
"@mui/lab": "^5.0.0-alpha.169",
|
|
59
59
|
"@mui/material": "^5.15.14",
|
|
60
60
|
"@mui/styles": "^5.15.14",
|
|
61
61
|
"@mui/system": "^5.15.14",
|
|
62
|
-
"@ocap/util": "^1.18.
|
|
62
|
+
"@ocap/util": "^1.18.115",
|
|
63
63
|
"@stripe/react-stripe-js": "^2.4.0",
|
|
64
64
|
"@stripe/stripe-js": "^2.4.0",
|
|
65
65
|
"@vitejs/plugin-legacy": "^5.3.2",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"@babel/core": "^7.23.9",
|
|
91
91
|
"@babel/preset-env": "^7.23.9",
|
|
92
92
|
"@babel/preset-react": "^7.23.3",
|
|
93
|
-
"@blocklet/payment-types": "1.13.
|
|
93
|
+
"@blocklet/payment-types": "1.13.212",
|
|
94
94
|
"@storybook/addon-essentials": "^7.6.13",
|
|
95
95
|
"@storybook/addon-interactions": "^7.6.13",
|
|
96
96
|
"@storybook/addon-links": "^7.6.13",
|
|
@@ -119,5 +119,5 @@
|
|
|
119
119
|
"vite-plugin-babel": "^1.2.0",
|
|
120
120
|
"vite-plugin-node-polyfills": "^0.21.0"
|
|
121
121
|
},
|
|
122
|
-
"gitHead": "
|
|
122
|
+
"gitHead": "942de3b017723af85a6c271a7e4ddd35443bc84d"
|
|
123
123
|
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import Dialog from '@arcblock/ux/lib/Dialog';
|
|
2
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
|
+
import type {
|
|
4
|
+
DonationSettings,
|
|
5
|
+
PaymentDetails,
|
|
6
|
+
TCheckoutSessionExpanded,
|
|
7
|
+
TPaymentCurrency,
|
|
8
|
+
TPaymentLink,
|
|
9
|
+
TPaymentMethod,
|
|
10
|
+
} from '@blocklet/payment-types';
|
|
11
|
+
import {
|
|
12
|
+
Alert,
|
|
13
|
+
Avatar,
|
|
14
|
+
AvatarGroup,
|
|
15
|
+
Box,
|
|
16
|
+
Button,
|
|
17
|
+
CircularProgress,
|
|
18
|
+
Hidden,
|
|
19
|
+
Stack,
|
|
20
|
+
Table,
|
|
21
|
+
TableCell,
|
|
22
|
+
TableRow,
|
|
23
|
+
Typography,
|
|
24
|
+
} from '@mui/material';
|
|
25
|
+
import { useRequest, useSetState } from 'ahooks';
|
|
26
|
+
import omit from 'lodash/omit';
|
|
27
|
+
import uniqBy from 'lodash/unionBy';
|
|
28
|
+
import { useEffect } from 'react';
|
|
29
|
+
|
|
30
|
+
import api from '../api';
|
|
31
|
+
import TxLink from '../components/blockchain/tx';
|
|
32
|
+
import { CheckoutProps } from '../types';
|
|
33
|
+
import { formatAmount, formatDateTime, formatError } from '../util';
|
|
34
|
+
import CheckoutForm from './form';
|
|
35
|
+
|
|
36
|
+
export type DonateHistory = {
|
|
37
|
+
supporters: TCheckoutSessionExpanded[];
|
|
38
|
+
currency: TPaymentCurrency;
|
|
39
|
+
method: TPaymentMethod;
|
|
40
|
+
total: number;
|
|
41
|
+
};
|
|
42
|
+
export type DonateProps = Pick<CheckoutProps, 'onPaid' | 'onError'> & {
|
|
43
|
+
settings: DonationSettings;
|
|
44
|
+
livemode?: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const donationCache: { [key: string]: Promise<TPaymentLink> } = {};
|
|
48
|
+
const createOrUpdateDonation = (settings: DonationSettings, livemode: boolean = true): Promise<TPaymentLink> => {
|
|
49
|
+
if (!donationCache[settings.target]) {
|
|
50
|
+
donationCache[settings.target] = api
|
|
51
|
+
.post(`/api/donations?livemode=${livemode}`, omit(settings, ['appearance']))
|
|
52
|
+
.then((res) => res.data)
|
|
53
|
+
.finally(() => {
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
delete donationCache[settings.target];
|
|
56
|
+
}, 3000);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return donationCache[settings.target];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const supporterCache: { [key: string]: Promise<DonateHistory> } = {};
|
|
64
|
+
const fetchSupporters = (target: string): Promise<DonateHistory> => {
|
|
65
|
+
if (!supporterCache[target]) {
|
|
66
|
+
supporterCache[target] = api
|
|
67
|
+
.get(`/api/donations?&target=${target}`)
|
|
68
|
+
.then((res) => res.data)
|
|
69
|
+
.finally(() => {
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
delete supporterCache[target];
|
|
72
|
+
}, 3000);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return supporterCache[target];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
80
|
+
function SupporterAvatar({ supporters = [], total, currency, method }: DonateHistory) {
|
|
81
|
+
const { t } = useLocaleContext();
|
|
82
|
+
const customers = uniqBy(supporters, 'customer_did');
|
|
83
|
+
return (
|
|
84
|
+
<Box
|
|
85
|
+
display="flex"
|
|
86
|
+
flexDirection="column"
|
|
87
|
+
alignItems="center"
|
|
88
|
+
sx={{
|
|
89
|
+
'.MuiAvatar-root': {
|
|
90
|
+
width: '32px',
|
|
91
|
+
height: '32px',
|
|
92
|
+
},
|
|
93
|
+
}}
|
|
94
|
+
gap={{
|
|
95
|
+
xs: 0.5,
|
|
96
|
+
sm: 1,
|
|
97
|
+
}}>
|
|
98
|
+
<Typography component="p" color="text.secondary">
|
|
99
|
+
{t('payment.checkout.donation.summary', { total })}
|
|
100
|
+
</Typography>
|
|
101
|
+
<AvatarGroup total={total} max={20}>
|
|
102
|
+
{customers.map((x) => (
|
|
103
|
+
<Avatar
|
|
104
|
+
key={x.id}
|
|
105
|
+
title={x.customer?.name}
|
|
106
|
+
src={`/.well-known/service/user/avatar/${x.customer?.did}?imageFilter=resize&w=48&h=48`}
|
|
107
|
+
variant="circular"
|
|
108
|
+
sx={{ width: 32, height: 32 }}
|
|
109
|
+
/>
|
|
110
|
+
))}
|
|
111
|
+
</AvatarGroup>
|
|
112
|
+
</Box>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
117
|
+
function SupporterTable({ supporters = [], total, currency, method }: DonateHistory) {
|
|
118
|
+
const { t } = useLocaleContext();
|
|
119
|
+
return (
|
|
120
|
+
<Box display="flex" flexDirection="column" alignItems="center" sx={{ width: '100%' }} gap={{ xs: 0.5, sm: 1 }}>
|
|
121
|
+
<Typography component="p" color="text.secondary">
|
|
122
|
+
{t('payment.checkout.donation.summary', { total })}
|
|
123
|
+
</Typography>
|
|
124
|
+
<Table size="small" sx={{ width: '100%', overflow: 'hidden' }}>
|
|
125
|
+
{supporters.map((x) => (
|
|
126
|
+
<TableRow
|
|
127
|
+
key={x.id}
|
|
128
|
+
sx={{
|
|
129
|
+
'> td': { padding: '8px 16px 8px 0', borderTop: '1px solid #e0e0e0', borderBottom: '1px solid #e0e0e0' },
|
|
130
|
+
}}>
|
|
131
|
+
<TableCell>
|
|
132
|
+
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
133
|
+
<Avatar
|
|
134
|
+
key={x.id}
|
|
135
|
+
src={`/.well-known/service/user/avatar/${x.customer?.did}?imageFilter=resize&w=48&h=48`}
|
|
136
|
+
variant="circular"
|
|
137
|
+
sx={{ width: 24, height: 24 }}
|
|
138
|
+
/>
|
|
139
|
+
<Hidden smDown>
|
|
140
|
+
<Typography>{x.customer?.name}</Typography>
|
|
141
|
+
</Hidden>
|
|
142
|
+
</Stack>
|
|
143
|
+
</TableCell>
|
|
144
|
+
<TableCell align="right">
|
|
145
|
+
<Stack direction="row" alignItems="center" justifyContent="flex-end" spacing={0.5}>
|
|
146
|
+
<Typography fontWeight={500} component="strong">
|
|
147
|
+
{formatAmount(x.amount_total, currency.decimal)}
|
|
148
|
+
</Typography>
|
|
149
|
+
<Typography component="span">{currency.symbol}</Typography>
|
|
150
|
+
</Stack>
|
|
151
|
+
</TableCell>
|
|
152
|
+
<Hidden smDown>
|
|
153
|
+
<TableCell align="right">
|
|
154
|
+
<Typography>{formatDateTime(x.created_at)}</Typography>
|
|
155
|
+
</TableCell>
|
|
156
|
+
</Hidden>
|
|
157
|
+
<TableCell align="right">
|
|
158
|
+
<TxLink method={method} details={x.payment_details as PaymentDetails} mode="customer" align="right" />
|
|
159
|
+
</TableCell>
|
|
160
|
+
</TableRow>
|
|
161
|
+
))}
|
|
162
|
+
</Table>
|
|
163
|
+
</Box>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export default function CheckoutDonate({ settings, livemode, onPaid, onError }: DonateProps) {
|
|
168
|
+
const [state, setState] = useSetState({
|
|
169
|
+
open: false,
|
|
170
|
+
supporterLoaded: false,
|
|
171
|
+
exist: false,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const donation = useRequest(() => createOrUpdateDonation(settings, livemode));
|
|
175
|
+
const supporters = useRequest(() => (donation.data ? fetchSupporters(donation.data.id) : Promise.resolve({})));
|
|
176
|
+
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (donation.data && state.supporterLoaded === false) {
|
|
179
|
+
setState({ supporterLoaded: true });
|
|
180
|
+
supporters.runAsync().catch(console.error);
|
|
181
|
+
}
|
|
182
|
+
}, [donation.data]); // eslint-disable-line
|
|
183
|
+
|
|
184
|
+
const handlePaid = (...args: any[]) => {
|
|
185
|
+
if (onPaid) {
|
|
186
|
+
// @ts-ignore
|
|
187
|
+
onPaid(...args);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
supporters.runAsync().catch(console.error);
|
|
191
|
+
|
|
192
|
+
setTimeout(() => {
|
|
193
|
+
setState({ open: false });
|
|
194
|
+
}, 3000);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
if (donation.error) {
|
|
198
|
+
return <Alert severity="error">{formatError(donation.error)}</Alert>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (donation.loading || !donation.data) {
|
|
202
|
+
return <CircularProgress />;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<Box
|
|
207
|
+
sx={{ width: '100%', minWidth: 300, maxWidth: 720 }}
|
|
208
|
+
display="flex"
|
|
209
|
+
flexDirection="column"
|
|
210
|
+
alignItems="center"
|
|
211
|
+
gap={{ xs: 1, sm: 2 }}>
|
|
212
|
+
<Button
|
|
213
|
+
size={(settings.appearance?.button?.size || 'medium') as any}
|
|
214
|
+
color={(settings.appearance?.button?.color || 'primary') as any}
|
|
215
|
+
variant={(settings.appearance?.button?.variant || 'contained') as any}
|
|
216
|
+
onClick={() => setState({ open: true })}>
|
|
217
|
+
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
218
|
+
{settings.appearance.button.icon}
|
|
219
|
+
{typeof settings.appearance.button.text === 'string' ? (
|
|
220
|
+
<Typography>{settings.appearance.button.text}</Typography>
|
|
221
|
+
) : (
|
|
222
|
+
settings.appearance.button.text
|
|
223
|
+
)}
|
|
224
|
+
</Stack>
|
|
225
|
+
</Button>
|
|
226
|
+
{supporters.data && settings.appearance.history.variant === 'avatar' && (
|
|
227
|
+
<SupporterAvatar {...(supporters.data as DonateHistory)} />
|
|
228
|
+
)}
|
|
229
|
+
{supporters.data && settings.appearance.history.variant === 'table' && (
|
|
230
|
+
<SupporterTable {...(supporters.data as DonateHistory)} />
|
|
231
|
+
)}
|
|
232
|
+
<Dialog
|
|
233
|
+
open={state.open}
|
|
234
|
+
title={settings.title}
|
|
235
|
+
maxWidth="md"
|
|
236
|
+
showCloseButton
|
|
237
|
+
disableBackdropClick
|
|
238
|
+
disableEscapeKeyDown
|
|
239
|
+
onClose={(e: any, reason: string) => setState({ open: reason === 'backdropClick' })}>
|
|
240
|
+
<Box sx={{ mb: 1, mt: -2 }}>
|
|
241
|
+
<CheckoutForm
|
|
242
|
+
id={donation.data.id}
|
|
243
|
+
onPaid={handlePaid}
|
|
244
|
+
onError={onError}
|
|
245
|
+
action={settings.appearance?.button?.text}
|
|
246
|
+
mode="inline"
|
|
247
|
+
/>
|
|
248
|
+
</Box>
|
|
249
|
+
</Dialog>
|
|
250
|
+
</Box>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
CheckoutDonate.defaultProps = {
|
|
255
|
+
livemode: true,
|
|
256
|
+
};
|
package/src/checkout/form.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { TCheckoutSessionExpanded, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
1
|
+
import type { TCheckoutSessionExpanded, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
3
2
|
import { useRequest, useSetState } from 'ahooks';
|
|
4
3
|
import noop from 'lodash/noop';
|
|
5
4
|
import { useEffect } from 'react';
|
|
@@ -31,8 +30,16 @@ const fetchCheckoutSession = async (id: string): Promise<CheckoutContext> => {
|
|
|
31
30
|
return data;
|
|
32
31
|
};
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
export default function CheckoutForm({
|
|
34
|
+
id,
|
|
35
|
+
mode,
|
|
36
|
+
onPaid,
|
|
37
|
+
onError,
|
|
38
|
+
onChange,
|
|
39
|
+
goBack,
|
|
40
|
+
extraParams,
|
|
41
|
+
action,
|
|
42
|
+
}: CheckoutProps) {
|
|
36
43
|
if (!id.startsWith('plink_') && !id.startsWith('cs_')) {
|
|
37
44
|
throw new Error('Either a checkoutSession or a paymentLink id is required.');
|
|
38
45
|
}
|
|
@@ -80,6 +87,7 @@ export default function CheckoutForm({ id, mode, onPaid, onError, onChange, goBa
|
|
|
80
87
|
onChange={onChange}
|
|
81
88
|
goBack={goBack}
|
|
82
89
|
mode={mode as string}
|
|
90
|
+
action={action}
|
|
83
91
|
/>
|
|
84
92
|
);
|
|
85
93
|
}
|
|
@@ -88,5 +96,6 @@ CheckoutForm.defaultProps = {
|
|
|
88
96
|
onPaid: noop,
|
|
89
97
|
onError: console.error,
|
|
90
98
|
mode: 'inline',
|
|
99
|
+
action: '',
|
|
91
100
|
extraParams: {},
|
|
92
101
|
};
|
|
@@ -7,12 +7,14 @@ import { getTxLink } from '../../util';
|
|
|
7
7
|
|
|
8
8
|
TxLink.defaultProps = {
|
|
9
9
|
mode: 'dashboard',
|
|
10
|
+
align: 'left',
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
export default function TxLink(props: {
|
|
13
14
|
details: PaymentDetails;
|
|
14
15
|
method: TPaymentMethod;
|
|
15
16
|
mode?: 'customer' | 'dashboard';
|
|
17
|
+
align?: 'left' | 'right';
|
|
16
18
|
}) {
|
|
17
19
|
const { t } = useLocaleContext();
|
|
18
20
|
|
|
@@ -29,7 +31,12 @@ export default function TxLink(props: {
|
|
|
29
31
|
if (link) {
|
|
30
32
|
return (
|
|
31
33
|
<Link href={link} target="_blank" rel="noopener noreferrer">
|
|
32
|
-
<Stack
|
|
34
|
+
<Stack
|
|
35
|
+
component="span"
|
|
36
|
+
direction="row"
|
|
37
|
+
alignItems="center"
|
|
38
|
+
justifyContent={props.align === 'left' ? 'flex-start' : 'flex-end'}
|
|
39
|
+
spacing={1}>
|
|
33
40
|
<Typography component="span" color="primary">
|
|
34
41
|
{text.length > 40 ? [text.slice(0, 8), text.slice(-8)].join('...') : text}
|
|
35
42
|
</Typography>
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import api from './api';
|
|
2
|
+
import CheckoutDonate from './checkout/donate';
|
|
2
3
|
import CheckoutForm from './checkout/form';
|
|
3
4
|
import CheckoutTable from './checkout/table';
|
|
4
5
|
import TxLink from './components/blockchain/tx';
|
|
@@ -6,6 +7,7 @@ import ConfirmDialog from './components/confirm';
|
|
|
6
7
|
import FormInput from './components/input';
|
|
7
8
|
import Livemode from './components/livemode';
|
|
8
9
|
import PricingTable from './components/pricing-table';
|
|
10
|
+
import SafeGuard from './components/safe-guard';
|
|
9
11
|
import Status from './components/status';
|
|
10
12
|
import Switch from './components/switch-button';
|
|
11
13
|
import dayjs from './dayjs';
|
|
@@ -39,6 +41,7 @@ export {
|
|
|
39
41
|
ConfirmDialog,
|
|
40
42
|
CheckoutForm,
|
|
41
43
|
CheckoutTable,
|
|
44
|
+
CheckoutDonate,
|
|
42
45
|
CurrencySelector,
|
|
43
46
|
Payment,
|
|
44
47
|
PaymentSummary,
|
|
@@ -49,4 +52,5 @@ export {
|
|
|
49
52
|
CustomerPaymentList,
|
|
50
53
|
MiniInvoiceList,
|
|
51
54
|
TxLink,
|
|
55
|
+
SafeGuard,
|
|
52
56
|
};
|
package/src/locales/en.tsx
CHANGED
|
@@ -88,6 +88,7 @@ export default flat({
|
|
|
88
88
|
try: 'Try for free',
|
|
89
89
|
include: 'This includes:',
|
|
90
90
|
subscription: 'Subscribe',
|
|
91
|
+
donate: 'Donate',
|
|
91
92
|
select: 'Select',
|
|
92
93
|
selected: 'Selected',
|
|
93
94
|
noPricing: 'No items to purchase',
|
|
@@ -104,6 +105,12 @@ export default flat({
|
|
|
104
105
|
tooltip:
|
|
105
106
|
'Staking is used to ensure that future invoices can be paid normally. Revoking the staking from DID Wallet means canceling the subscription.',
|
|
106
107
|
},
|
|
108
|
+
donation: {
|
|
109
|
+
between: 'Please enter an amount between {min} and {max}.',
|
|
110
|
+
custom: 'Custom Amount',
|
|
111
|
+
select: 'Select Amount',
|
|
112
|
+
summary: '{total} supporters',
|
|
113
|
+
},
|
|
107
114
|
cardPay: '{action} with card',
|
|
108
115
|
empty: 'No thing to pay',
|
|
109
116
|
per: 'per',
|
|
@@ -119,6 +126,7 @@ export default flat({
|
|
|
119
126
|
payment: 'Thanks for your purchase',
|
|
120
127
|
subscription: 'Thanks for your subscribing',
|
|
121
128
|
setup: 'Thanks for your subscribing',
|
|
129
|
+
donate: 'Thanks for your support',
|
|
122
130
|
tip: 'A payment to {payee} has been completed. You can view the details of this payment in your account.',
|
|
123
131
|
},
|
|
124
132
|
confirm:
|
package/src/locales/zh.tsx
CHANGED
|
@@ -88,6 +88,7 @@ export default flat({
|
|
|
88
88
|
try: '免费试用',
|
|
89
89
|
include: '包括:',
|
|
90
90
|
subscription: '订阅',
|
|
91
|
+
donate: '捐赠',
|
|
91
92
|
select: '选择',
|
|
92
93
|
selected: '已选',
|
|
93
94
|
noPricing: '没有可购买的物品',
|
|
@@ -103,6 +104,12 @@ export default flat({
|
|
|
103
104
|
title: '质押数量',
|
|
104
105
|
tooltip: '质押相当于保证金,用于确保未来的账单能够正常扣款,如果你从 DID Wallet 撤销质押,订阅也会被取消。',
|
|
105
106
|
},
|
|
107
|
+
donation: {
|
|
108
|
+
between: '金额必须大于 {min} 且小于 {max}',
|
|
109
|
+
custom: '输入金额',
|
|
110
|
+
select: '选择金额',
|
|
111
|
+
summary: '已经有 {total} 人支持',
|
|
112
|
+
},
|
|
106
113
|
cardPay: '使用卡片{action}',
|
|
107
114
|
empty: '没有可支付的项目',
|
|
108
115
|
per: '每',
|
|
@@ -118,6 +125,7 @@ export default flat({
|
|
|
118
125
|
payment: '感谢您的购买',
|
|
119
126
|
subscription: '感谢您的订阅',
|
|
120
127
|
setup: '感谢您的订阅',
|
|
128
|
+
donate: '感谢您的支持',
|
|
121
129
|
tip: '向{payee}的付款已完成。您可以在您的账户中查看此付款的详细信息。',
|
|
122
130
|
},
|
|
123
131
|
confirm:
|
package/src/payment/error.tsx
CHANGED
|
@@ -4,11 +4,12 @@ type Props = {
|
|
|
4
4
|
title: string;
|
|
5
5
|
description: string;
|
|
6
6
|
button?: string;
|
|
7
|
+
mode?: string;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
|
-
export default function PaymentError({ title, description, button }: Props) {
|
|
10
|
+
export default function PaymentError({ title, description, button, mode }: Props) {
|
|
10
11
|
return (
|
|
11
|
-
<Stack sx={{ height: '100vh' }} alignItems="center" justifyContent="center">
|
|
12
|
+
<Stack sx={{ height: mode === 'inline' ? 'auto' : '100vh' }} alignItems="center" justifyContent="center">
|
|
12
13
|
<Stack sx={{ width: '280px' }} direction="column" alignItems="center" justifyContent="center">
|
|
13
14
|
<Typography variant="h5" sx={{ mb: 2 }}>
|
|
14
15
|
{title}
|
|
@@ -26,4 +27,5 @@ export default function PaymentError({ title, description, button }: Props) {
|
|
|
26
27
|
|
|
27
28
|
PaymentError.defaultProps = {
|
|
28
29
|
button: 'Back',
|
|
30
|
+
mode: 'standalone',
|
|
29
31
|
};
|
|
@@ -11,6 +11,7 @@ type Props = {
|
|
|
11
11
|
export default function CurrencySelector({ value, currencies, onChange }: Props) {
|
|
12
12
|
return (
|
|
13
13
|
<Root
|
|
14
|
+
count={currencies.length}
|
|
14
15
|
style={{
|
|
15
16
|
display: currencies.length > 1 ? 'grid' : 'block',
|
|
16
17
|
gridTemplateColumns: '50% 50%',
|
|
@@ -42,12 +43,12 @@ export default function CurrencySelector({ value, currencies, onChange }: Props)
|
|
|
42
43
|
);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
const Root = styled('section')`
|
|
46
|
+
const Root = styled<any>('section')`
|
|
46
47
|
.cko-payment-card {
|
|
47
48
|
position: relative;
|
|
48
|
-
border:
|
|
49
|
-
padding:
|
|
50
|
-
margin:
|
|
49
|
+
border: 1px solid ${(props) => props.theme.palette.primary.main};
|
|
50
|
+
padding: 4px 8px;
|
|
51
|
+
margin: 8px 0 0;
|
|
51
52
|
cursor: pointer;
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -62,18 +63,15 @@ const Root = styled('section')`
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
.cko-payment-card-unselect {
|
|
65
|
-
border:
|
|
66
|
-
padding:
|
|
67
|
-
margin:
|
|
66
|
+
border: 1px solid #ddd;
|
|
67
|
+
padding: 4px 8px;
|
|
68
|
+
margin: 8px 0 0;
|
|
68
69
|
cursor: pointer;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
.cko-payment-card:nth-child(odd)
|
|
72
|
-
margin-right: 8px;
|
|
73
|
-
}
|
|
74
|
-
|
|
72
|
+
.cko-payment-card:nth-child(odd),
|
|
75
73
|
.cko-payment-card-unselect:nth-child(odd) {
|
|
76
|
-
margin-right:
|
|
74
|
+
margin-right: ${(props) => (props.count > 1 ? 8 : 0)}px;
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
.cko-payment-card::after {
|
|
@@ -83,7 +81,7 @@ const Root = styled('section')`
|
|
|
83
81
|
position: absolute;
|
|
84
82
|
right: 3px;
|
|
85
83
|
bottom: 3px;
|
|
86
|
-
border:
|
|
84
|
+
border: 1px solid #fff;
|
|
87
85
|
border-top-color: transparent;
|
|
88
86
|
border-left-color: transparent;
|
|
89
87
|
transform: rotate(35deg);
|