@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.
Files changed (79) hide show
  1. package/es/checkout/donate.d.ts +20 -0
  2. package/es/checkout/donate.js +199 -0
  3. package/es/checkout/form.d.ts +2 -1
  4. package/es/checkout/form.js +13 -2
  5. package/es/components/blockchain/tx.d.ts +2 -0
  6. package/es/components/blockchain/tx.js +16 -5
  7. package/es/components/safe-guard.d.ts +3 -0
  8. package/es/components/safe-guard.js +4 -0
  9. package/es/index.d.ts +3 -1
  10. package/es/index.js +5 -1
  11. package/es/locales/en.js +8 -0
  12. package/es/locales/zh.js +8 -0
  13. package/es/payment/error.d.ts +3 -1
  14. package/es/payment/error.js +4 -3
  15. package/es/payment/form/currency.js +10 -12
  16. package/es/payment/form/index.d.ts +1 -1
  17. package/es/payment/form/index.js +15 -3
  18. package/es/payment/index.d.ts +3 -3
  19. package/es/payment/index.js +38 -13
  20. package/es/payment/product-donation.d.ts +7 -0
  21. package/es/payment/product-donation.js +99 -0
  22. package/es/payment/skeleton/overview.js +2 -2
  23. package/es/payment/skeleton/payment.js +2 -5
  24. package/es/payment/success.d.ts +2 -1
  25. package/es/payment/success.js +21 -12
  26. package/es/payment/summary.d.ts +8 -2
  27. package/es/payment/summary.js +46 -29
  28. package/es/types/index.d.ts +2 -0
  29. package/es/util.d.ts +2 -0
  30. package/es/util.js +47 -3
  31. package/lib/checkout/donate.d.ts +20 -0
  32. package/lib/checkout/donate.js +284 -0
  33. package/lib/checkout/form.d.ts +2 -1
  34. package/lib/checkout/form.js +5 -2
  35. package/lib/components/blockchain/tx.d.ts +2 -0
  36. package/lib/components/blockchain/tx.js +3 -1
  37. package/lib/components/safe-guard.d.ts +3 -0
  38. package/lib/components/safe-guard.js +12 -0
  39. package/lib/index.d.ts +3 -1
  40. package/lib/index.js +16 -0
  41. package/lib/locales/en.js +8 -0
  42. package/lib/locales/zh.js +8 -0
  43. package/lib/payment/error.d.ts +3 -1
  44. package/lib/payment/error.js +5 -3
  45. package/lib/payment/form/currency.js +10 -12
  46. package/lib/payment/form/index.d.ts +1 -1
  47. package/lib/payment/form/index.js +16 -4
  48. package/lib/payment/index.d.ts +3 -3
  49. package/lib/payment/index.js +56 -24
  50. package/lib/payment/product-donation.d.ts +7 -0
  51. package/lib/payment/product-donation.js +169 -0
  52. package/lib/payment/skeleton/overview.js +2 -2
  53. package/lib/payment/skeleton/payment.js +4 -8
  54. package/lib/payment/success.d.ts +2 -1
  55. package/lib/payment/success.js +3 -2
  56. package/lib/payment/summary.d.ts +8 -2
  57. package/lib/payment/summary.js +30 -7
  58. package/lib/types/index.d.ts +2 -0
  59. package/lib/util.d.ts +2 -0
  60. package/lib/util.js +44 -4
  61. package/package.json +6 -6
  62. package/src/checkout/donate.tsx +256 -0
  63. package/src/checkout/form.tsx +13 -4
  64. package/src/components/blockchain/tx.tsx +8 -1
  65. package/src/components/safe-guard.tsx +5 -0
  66. package/src/index.ts +4 -0
  67. package/src/locales/en.tsx +8 -0
  68. package/src/locales/zh.tsx +8 -0
  69. package/src/payment/error.tsx +4 -2
  70. package/src/payment/form/currency.tsx +11 -13
  71. package/src/payment/form/index.tsx +14 -4
  72. package/src/payment/index.tsx +40 -14
  73. package/src/payment/product-donation.tsx +118 -0
  74. package/src/payment/skeleton/overview.tsx +2 -2
  75. package/src/payment/skeleton/payment.tsx +1 -4
  76. package/src/payment/success.tsx +7 -2
  77. package/src/payment/summary.tsx +47 -28
  78. package/src/types/index.ts +2 -0
  79. 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
- tiers: null,
217
- custom_unit_amount: null
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(getPriceUintAmountByCurrency(price, currency)).mul(new _util.BN(x.quantity)));
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(getPriceUintAmountByCurrency(price, currency)).mul(new _util.BN(x.quantity)));
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.210",
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.64",
56
- "@arcblock/ux": "^2.9.64",
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.114",
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.210",
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": "4d13c9b750596c25098c219a6e269ed141734d5e"
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
+ };
@@ -1,5 +1,4 @@
1
- // eslint-disable-next-line import/no-extraneous-dependencies
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
- // FIXME: @wangshijun support popup
35
- export default function CheckoutForm({ id, mode, onPaid, onError, onChange, goBack, extraParams }: CheckoutProps) {
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 component="span" direction="row" alignItems="center" spacing={1}>
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>
@@ -0,0 +1,5 @@
1
+ import { isPaymentKitMounted } from '../util';
2
+
3
+ export default function SafeGuard({ children }: { children: any }) {
4
+ return isPaymentKitMounted() ? children : null;
5
+ }
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
  };
@@ -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:
@@ -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:
@@ -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: 2px solid ${(props) => props.theme.palette.primary.main};
49
- padding: 5px 10px;
50
- margin: 5px 0;
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: 2px solid #ddd;
66
- padding: 5px 10px;
67
- margin: 5px 0;
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: 8px;
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: 2px solid #fff;
84
+ border: 1px solid #fff;
87
85
  border-top-color: transparent;
88
86
  border-left-color: transparent;
89
87
  transform: rotate(35deg);