@blocklet/payment-react 1.13.210 → 1.13.211

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 (74) 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/index.d.ts +2 -1
  8. package/es/index.js +2 -0
  9. package/es/locales/en.js +8 -0
  10. package/es/locales/zh.js +8 -0
  11. package/es/payment/error.d.ts +3 -1
  12. package/es/payment/error.js +4 -3
  13. package/es/payment/form/currency.js +10 -12
  14. package/es/payment/form/index.d.ts +1 -1
  15. package/es/payment/form/index.js +15 -3
  16. package/es/payment/index.d.ts +3 -3
  17. package/es/payment/index.js +38 -13
  18. package/es/payment/product-donation.d.ts +7 -0
  19. package/es/payment/product-donation.js +99 -0
  20. package/es/payment/skeleton/overview.js +2 -2
  21. package/es/payment/skeleton/payment.js +2 -5
  22. package/es/payment/success.d.ts +2 -1
  23. package/es/payment/success.js +21 -12
  24. package/es/payment/summary.d.ts +8 -2
  25. package/es/payment/summary.js +46 -29
  26. package/es/types/index.d.ts +2 -0
  27. package/es/util.d.ts +1 -0
  28. package/es/util.js +44 -3
  29. package/lib/checkout/donate.d.ts +20 -0
  30. package/lib/checkout/donate.js +284 -0
  31. package/lib/checkout/form.d.ts +2 -1
  32. package/lib/checkout/form.js +5 -2
  33. package/lib/components/blockchain/tx.d.ts +2 -0
  34. package/lib/components/blockchain/tx.js +3 -1
  35. package/lib/index.d.ts +2 -1
  36. package/lib/index.js +8 -0
  37. package/lib/locales/en.js +8 -0
  38. package/lib/locales/zh.js +8 -0
  39. package/lib/payment/error.d.ts +3 -1
  40. package/lib/payment/error.js +5 -3
  41. package/lib/payment/form/currency.js +10 -12
  42. package/lib/payment/form/index.d.ts +1 -1
  43. package/lib/payment/form/index.js +16 -4
  44. package/lib/payment/index.d.ts +3 -3
  45. package/lib/payment/index.js +56 -24
  46. package/lib/payment/product-donation.d.ts +7 -0
  47. package/lib/payment/product-donation.js +169 -0
  48. package/lib/payment/skeleton/overview.js +2 -2
  49. package/lib/payment/skeleton/payment.js +4 -8
  50. package/lib/payment/success.d.ts +2 -1
  51. package/lib/payment/success.js +3 -2
  52. package/lib/payment/summary.d.ts +8 -2
  53. package/lib/payment/summary.js +30 -7
  54. package/lib/types/index.d.ts +2 -0
  55. package/lib/util.d.ts +1 -0
  56. package/lib/util.js +39 -4
  57. package/package.json +6 -6
  58. package/src/checkout/donate.tsx +256 -0
  59. package/src/checkout/form.tsx +13 -4
  60. package/src/components/blockchain/tx.tsx +8 -1
  61. package/src/index.ts +2 -0
  62. package/src/locales/en.tsx +8 -0
  63. package/src/locales/zh.tsx +8 -0
  64. package/src/payment/error.tsx +4 -2
  65. package/src/payment/form/currency.tsx +11 -13
  66. package/src/payment/form/index.tsx +14 -4
  67. package/src/payment/index.tsx +40 -14
  68. package/src/payment/product-donation.tsx +118 -0
  69. package/src/payment/skeleton/overview.tsx +2 -2
  70. package/src/payment/skeleton/payment.tsx +1 -4
  71. package/src/payment/success.tsx +7 -2
  72. package/src/payment/summary.tsx +47 -28
  73. package/src/types/index.ts +2 -0
  74. package/src/util.ts +50 -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;
@@ -129,6 +130,9 @@ function formatNumber(n, precision = 6, trim = true) {
129
130
  return trim ? (0, _trimEnd.default)(num.format(options), "0.") : num.format(options);
130
131
  }
131
132
  const formatPrice = (price, currency, unit_label, quantity = 1, bn = true, locale = "en") => {
133
+ if (price.custom_unit_amount) {
134
+ return `Custom (${currency.symbol})`;
135
+ }
132
136
  const unit = getPriceUintAmountByCurrency(price, currency);
133
137
  const amount = bn ? (0, _util.fromUnitToToken)(new _util.BN(unit).mul(new _util.BN(quantity)), currency.decimal).toString() : +unit * quantity;
134
138
  if (price?.type === "recurring" && price.recurring) {
@@ -198,9 +202,15 @@ function getPriceUintAmountByCurrency(price, currency) {
198
202
  const options = getPriceCurrencyOptions(price);
199
203
  const option = options.find(x => x.currency_id === currency.id);
200
204
  if (option) {
205
+ if (option.custom_unit_amount) {
206
+ return option.custom_unit_amount.preset || option.custom_unit_amount.presets[0];
207
+ }
201
208
  return option.unit_amount;
202
209
  }
203
210
  if (price.currency_id === currency.id) {
211
+ if (price.custom_unit_amount) {
212
+ return price.custom_unit_amount.preset || price.custom_unit_amount.presets[0];
213
+ }
204
214
  return price.unit_amount;
205
215
  }
206
216
  console.warn(`Currency ${currency.id} not configured for price`, price);
@@ -213,8 +223,8 @@ function getPriceCurrencyOptions(price) {
213
223
  return [{
214
224
  currency_id: price.currency_id,
215
225
  unit_amount: price.unit_amount,
216
- tiers: null,
217
- custom_unit_amount: null
226
+ custom_unit_amount: price.custom_unit_amount || null,
227
+ tiers: null
218
228
  }];
219
229
  }
220
230
  function formatLineItemPricing(item, currency, trial, locale = "en") {
@@ -305,6 +315,19 @@ function getRefundStatusColor(status) {
305
315
  return "default";
306
316
  }
307
317
  }
318
+ function getPayoutStatusColor(status) {
319
+ switch (status) {
320
+ case "paid":
321
+ return "success";
322
+ case "failed":
323
+ return "warning";
324
+ case "canceled":
325
+ case "pending":
326
+ case "in_transit":
327
+ default:
328
+ return "default";
329
+ }
330
+ }
308
331
  function getInvoiceStatusColor(status) {
309
332
  switch (status) {
310
333
  case "paid":
@@ -329,14 +352,26 @@ function getWebhookStatusColor(status) {
329
352
  }
330
353
  }
331
354
  function getCheckoutAmount(items, currency, trialing = false, upsell = true) {
355
+ if (items.find(x => (x.upsell_price || x.price).custom_unit_amount) && items.length > 1) {
356
+ throw new Error("Multiple items with custom unit amount are not supported");
357
+ }
332
358
  let renew = new _util.BN(0);
333
359
  const total = items.filter(x => {
334
360
  const price = upsell ? x.upsell_price || x.price : x.price;
335
361
  return price != null;
336
362
  }).reduce((acc, x) => {
363
+ if (x.custom_amount) {
364
+ return acc.add(new _util.BN(x.custom_amount));
365
+ }
337
366
  const price = upsell ? x.upsell_price || x.price : x.price;
367
+ const unitPrice = getPriceUintAmountByCurrency(price, currency);
368
+ if (price.custom_unit_amount) {
369
+ if (unitPrice) {
370
+ return acc.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
371
+ }
372
+ }
338
373
  if (price?.type === "recurring") {
339
- renew = renew.add(new _util.BN(getPriceUintAmountByCurrency(price, currency)).mul(new _util.BN(x.quantity)));
374
+ renew = renew.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
340
375
  if (trialing) {
341
376
  return acc;
342
377
  }
@@ -344,7 +379,7 @@ function getCheckoutAmount(items, currency, trialing = false, upsell = true) {
344
379
  return acc;
345
380
  }
346
381
  }
347
- return acc.add(new _util.BN(getPriceUintAmountByCurrency(price, currency)).mul(new _util.BN(x.quantity)));
382
+ return acc.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
348
383
  }, new _util.BN(0)).toString();
349
384
  return {
350
385
  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.211",
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.211",
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": "2fe03028e2284261a1a62260d82a2e79ec45ce4a"
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>
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';
@@ -39,6 +40,7 @@ export {
39
40
  ConfirmDialog,
40
41
  CheckoutForm,
41
42
  CheckoutTable,
43
+ CheckoutDonate,
42
44
  CurrencySelector,
43
45
  Payment,
44
46
  PaymentSummary,
@@ -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);
@@ -70,10 +70,12 @@ export default function PaymentForm({
70
70
  checkoutSession,
71
71
  paymentMethods,
72
72
  paymentIntent,
73
+ paymentLink,
73
74
  customer,
74
75
  onPaid,
75
76
  onError,
76
77
  mode,
78
+ action,
77
79
  }: PageData) {
78
80
  const theme = useTheme();
79
81
  const { t } = useLocaleContext();
@@ -140,9 +142,17 @@ export default function PaymentForm({
140
142
  }, [domSize, theme]);
141
143
 
142
144
  const payee = getStatementDescriptor(checkoutSession.line_items);
143
- const buttonText = session?.user
144
- ? t(`payment.checkout.${checkoutSession.mode}`)
145
- : t('payment.checkout.connect', { action: t(`payment.checkout.${checkoutSession.mode}`) });
145
+ let buttonText = '';
146
+ if (paymentLink?.donation_settings) {
147
+ if (action) {
148
+ buttonText = action;
149
+ } else {
150
+ buttonText = t('payment.checkout.donate');
151
+ }
152
+ } else {
153
+ buttonText = t(`payment.checkout.${checkoutSession.mode}`);
154
+ }
155
+ buttonText = session?.user ? buttonText : t('payment.checkout.connect', { action: buttonText });
146
156
 
147
157
  const method = paymentMethods.find((x) => x.id === paymentMethod) as TPaymentMethodExpanded;
148
158
 
@@ -348,7 +358,7 @@ export default function PaymentForm({
348
358
  <AddressForm mode={checkoutSession.billing_address_collection as string} stripe={method?.type === 'stripe'} />
349
359
  <Fade in>
350
360
  <Stack direction="column" alignItems="flex-start" className="cko-payment-methods">
351
- <Typography sx={{ mb: 2, color: 'text.primary', fontWeight: 600 }}>{t('payment.checkout.method')}</Typography>
361
+ <Typography sx={{ mb: 1, color: 'text.primary', fontWeight: 600 }}>{t('payment.checkout.method')}</Typography>
352
362
  <Stack direction="row" sx={{ width: '100%' }}>
353
363
  <Controller
354
364
  name="payment_currency"