@blocklet/payment-react 1.18.0 → 1.18.2
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.js +55 -10
- package/es/checkout/form.d.ts +2 -1
- package/es/checkout/form.js +32 -45
- package/es/components/payment-beneficiaries.d.ts +24 -0
- package/es/components/payment-beneficiaries.js +70 -0
- package/es/index.d.ts +2 -1
- package/es/index.js +3 -1
- package/es/locales/en.js +13 -1
- package/es/locales/zh.js +13 -1
- package/es/payment/donation-form.d.ts +24 -0
- package/es/payment/donation-form.js +604 -0
- package/es/payment/error.d.ts +1 -1
- package/es/payment/error.js +11 -1
- package/es/payment/form/index.d.ts +9 -3
- package/es/payment/form/index.js +60 -12
- package/es/payment/product-donation.js +101 -56
- package/es/payment/skeleton/donation.d.ts +1 -0
- package/es/payment/skeleton/donation.js +30 -0
- package/es/theme/index.js +13 -0
- package/es/types/index.d.ts +2 -0
- package/lib/checkout/donate.js +85 -10
- package/lib/checkout/form.d.ts +2 -1
- package/lib/checkout/form.js +39 -49
- package/lib/components/payment-beneficiaries.d.ts +24 -0
- package/lib/components/payment-beneficiaries.js +113 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +8 -0
- package/lib/locales/en.js +13 -1
- package/lib/locales/zh.js +13 -1
- package/lib/payment/donation-form.d.ts +24 -0
- package/lib/payment/donation-form.js +645 -0
- package/lib/payment/error.d.ts +1 -1
- package/lib/payment/error.js +2 -2
- package/lib/payment/form/index.d.ts +9 -3
- package/lib/payment/form/index.js +60 -8
- package/lib/payment/product-donation.js +143 -72
- package/lib/payment/skeleton/donation.d.ts +1 -0
- package/lib/payment/skeleton/donation.js +66 -0
- package/lib/theme/index.js +13 -0
- package/lib/types/index.d.ts +2 -0
- package/package.json +3 -3
- package/src/checkout/donate.tsx +64 -11
- package/src/checkout/form.tsx +17 -31
- package/src/components/payment-beneficiaries.tsx +97 -0
- package/src/index.ts +2 -0
- package/src/locales/en.tsx +12 -0
- package/src/locales/zh.tsx +12 -0
- package/src/payment/donation-form.tsx +647 -0
- package/src/payment/error.tsx +13 -4
- package/src/payment/form/index.tsx +66 -11
- package/src/payment/product-donation.tsx +94 -39
- package/src/payment/skeleton/donation.tsx +35 -0
- package/src/theme/index.tsx +13 -0
- package/src/types/index.ts +2 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/indent */
|
|
1
2
|
import 'react-international-phone/style.css';
|
|
2
3
|
|
|
3
4
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
@@ -10,8 +11,7 @@ import type {
|
|
|
10
11
|
TPaymentIntent,
|
|
11
12
|
TPaymentMethodExpanded,
|
|
12
13
|
} from '@blocklet/payment-types';
|
|
13
|
-
import {
|
|
14
|
-
import { Box, Divider, Fade, FormLabel, Stack, Typography } from '@mui/material';
|
|
14
|
+
import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Typography } from '@mui/material';
|
|
15
15
|
import { useMemoizedFn, useSetState } from 'ahooks';
|
|
16
16
|
import pWaitFor from 'p-wait-for';
|
|
17
17
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
@@ -42,7 +42,7 @@ import StripeCheckout from './stripe';
|
|
|
42
42
|
import { useMobile } from '../../hooks/mobile';
|
|
43
43
|
import { validatePhoneNumber } from '../../libs/phone-validator';
|
|
44
44
|
|
|
45
|
-
const waitForCheckoutComplete = async (sessionId: string) => {
|
|
45
|
+
export const waitForCheckoutComplete = async (sessionId: string) => {
|
|
46
46
|
let result: CheckoutContext;
|
|
47
47
|
|
|
48
48
|
await pWaitFor(
|
|
@@ -71,14 +71,19 @@ const waitForCheckoutComplete = async (sessionId: string) => {
|
|
|
71
71
|
return result;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
const hasDidWallet = (user: any) => {
|
|
74
|
+
export const hasDidWallet = (user: any) => {
|
|
75
75
|
const connected = user?.connectedAccounts || user?.extraConfigs?.connectedAccounts || [];
|
|
76
76
|
return connected.some((x: any) => x.provider === 'wallet');
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
type PageData = CheckoutContext &
|
|
79
|
+
type PageData = CheckoutContext &
|
|
80
|
+
CheckoutCallbacks & {
|
|
81
|
+
onlyShowBtn?: boolean;
|
|
82
|
+
};
|
|
80
83
|
|
|
81
|
-
PaymentForm.defaultProps = {
|
|
84
|
+
PaymentForm.defaultProps = {
|
|
85
|
+
onlyShowBtn: false,
|
|
86
|
+
};
|
|
82
87
|
|
|
83
88
|
// FIXME: https://stripe.com/docs/elements/address-element
|
|
84
89
|
// TODO: https://country-regions.github.io/react-country-region-selector/
|
|
@@ -96,6 +101,7 @@ export default function PaymentForm({
|
|
|
96
101
|
// mode,
|
|
97
102
|
action,
|
|
98
103
|
currencyId,
|
|
104
|
+
onlyShowBtn,
|
|
99
105
|
}: PageData) {
|
|
100
106
|
// const theme = useTheme();
|
|
101
107
|
const { t } = useLocaleContext();
|
|
@@ -398,6 +404,47 @@ export default function PaymentForm({
|
|
|
398
404
|
setState({ stripePaying: false });
|
|
399
405
|
};
|
|
400
406
|
|
|
407
|
+
if (onlyShowBtn) {
|
|
408
|
+
return (
|
|
409
|
+
<>
|
|
410
|
+
<Box className="cko-payment-submit-btn">
|
|
411
|
+
<Button
|
|
412
|
+
variant="contained"
|
|
413
|
+
color="primary"
|
|
414
|
+
size="large"
|
|
415
|
+
className="cko-submit-button"
|
|
416
|
+
onClick={() => {
|
|
417
|
+
if (state.submitting || state.paying) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
onAction();
|
|
421
|
+
}}
|
|
422
|
+
fullWidth
|
|
423
|
+
disabled={state.stripePaying || !quantityInventoryStatus || !payable}>
|
|
424
|
+
{(state.submitting || state.paying) && (
|
|
425
|
+
<CircularProgress size={16} sx={{ mr: 0.5, color: 'var(--foregrounds-fg-on-color, #fff)' }} />
|
|
426
|
+
)}
|
|
427
|
+
{state.submitting || state.paying ? t('payment.checkout.processing') : buttonText}
|
|
428
|
+
</Button>
|
|
429
|
+
</Box>
|
|
430
|
+
{state.customerLimited && (
|
|
431
|
+
<ConfirmDialog
|
|
432
|
+
onConfirm={() =>
|
|
433
|
+
window.open(
|
|
434
|
+
joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
|
|
435
|
+
'_self'
|
|
436
|
+
)
|
|
437
|
+
}
|
|
438
|
+
onCancel={() => setState({ customerLimited: false })}
|
|
439
|
+
confirm={t('payment.customer.pastDue.alert.confirm')}
|
|
440
|
+
title={t('payment.customer.pastDue.alert.title')}
|
|
441
|
+
message={t('payment.customer.pastDue.alert.description')}
|
|
442
|
+
color="primary"
|
|
443
|
+
/>
|
|
444
|
+
)}
|
|
445
|
+
</>
|
|
446
|
+
);
|
|
447
|
+
}
|
|
401
448
|
return (
|
|
402
449
|
<>
|
|
403
450
|
<Fade in>
|
|
@@ -498,20 +545,28 @@ export default function PaymentForm({
|
|
|
498
545
|
</Stack>
|
|
499
546
|
</Fade>
|
|
500
547
|
<Divider sx={{ mt: 2.5, mb: 2.5 }} />
|
|
548
|
+
|
|
501
549
|
<Fade in>
|
|
502
550
|
<Stack className="cko-payment-submit">
|
|
503
551
|
<Box className="cko-payment-submit-btn">
|
|
504
|
-
<
|
|
552
|
+
<Button
|
|
505
553
|
variant="contained"
|
|
506
554
|
color="primary"
|
|
507
555
|
size="large"
|
|
508
556
|
className="cko-submit-button"
|
|
509
|
-
onClick={
|
|
557
|
+
onClick={() => {
|
|
558
|
+
if (state.submitting || state.paying) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
onAction();
|
|
562
|
+
}}
|
|
510
563
|
fullWidth
|
|
511
|
-
disabled={state.
|
|
512
|
-
|
|
564
|
+
disabled={state.stripePaying || !quantityInventoryStatus || !payable}>
|
|
565
|
+
{(state.submitting || state.paying) && (
|
|
566
|
+
<CircularProgress size={16} sx={{ mr: 0.5, color: 'var(--foregrounds-fg-on-color, #fff)' }} />
|
|
567
|
+
)}
|
|
513
568
|
{state.submitting || state.paying ? t('payment.checkout.processing') : buttonText}
|
|
514
|
-
</
|
|
569
|
+
</Button>
|
|
515
570
|
</Box>
|
|
516
571
|
|
|
517
572
|
{['subscription', 'setup'].includes(checkoutSession.mode) && (
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
|
|
3
|
-
import { Box, Card, CardActionArea,
|
|
3
|
+
import { Avatar, Box, Card, CardActionArea, Grid, Stack, TextField, Typography } from '@mui/material';
|
|
4
4
|
import { useSetState } from 'ahooks';
|
|
5
|
-
import { useEffect } from 'react';
|
|
5
|
+
import { useEffect, useRef } from 'react';
|
|
6
6
|
|
|
7
|
-
import Switch from '../components/switch-button';
|
|
8
7
|
import { formatAmountPrecisionLimit } from '../libs/util';
|
|
9
8
|
import { usePaymentContext } from '../contexts/payment';
|
|
10
9
|
import { usePreventWheel } from '../hooks/scroll';
|
|
@@ -23,13 +22,17 @@ export default function ProductDonation({
|
|
|
23
22
|
const { t, locale } = useLocaleContext();
|
|
24
23
|
const { setPayable } = usePaymentContext();
|
|
25
24
|
usePreventWheel();
|
|
26
|
-
const
|
|
25
|
+
const presets = settings?.amount?.presets || [];
|
|
26
|
+
const preset = settings?.amount?.preset || presets?.[0] || '0';
|
|
27
|
+
const supportPreset = presets.length > 0;
|
|
28
|
+
const supportCustom = !!settings?.amount?.custom;
|
|
27
29
|
const [state, setState] = useSetState({
|
|
28
30
|
selected: preset,
|
|
29
31
|
input: '',
|
|
30
|
-
custom:
|
|
32
|
+
custom: !supportPreset,
|
|
31
33
|
error: '',
|
|
32
34
|
});
|
|
35
|
+
const customInputRef = useRef<HTMLInputElement>(null);
|
|
33
36
|
|
|
34
37
|
// Set default amount
|
|
35
38
|
useEffect(() => {
|
|
@@ -42,7 +45,16 @@ export default function ProductDonation({
|
|
|
42
45
|
}
|
|
43
46
|
}, [settings.amount.preset, settings.amount.presets]); // eslint-disable-line
|
|
44
47
|
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (state.custom) {
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
customInputRef.current?.focus();
|
|
52
|
+
}, 0);
|
|
53
|
+
}
|
|
54
|
+
}, [state.custom]);
|
|
55
|
+
|
|
45
56
|
const handleSelect = (amount: string) => {
|
|
57
|
+
setPayable(true);
|
|
46
58
|
setState({ selected: amount, custom: false, error: '' });
|
|
47
59
|
onChange({ priceId: item.price_id, amount });
|
|
48
60
|
};
|
|
@@ -69,71 +81,114 @@ export default function ProductDonation({
|
|
|
69
81
|
onChange({ priceId: item.price_id, amount: value });
|
|
70
82
|
};
|
|
71
83
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
setPayable(true);
|
|
77
|
-
handleSelect(preset);
|
|
84
|
+
const handleCustomSelect = () => {
|
|
85
|
+
setState({ custom: true, error: '' });
|
|
86
|
+
if (!state.input) {
|
|
87
|
+
setPayable(false);
|
|
78
88
|
}
|
|
79
89
|
};
|
|
80
90
|
|
|
81
91
|
return (
|
|
82
92
|
<Box display="flex" flexDirection="column" alignItems="flex-start" gap={1.5}>
|
|
83
|
-
{
|
|
84
|
-
<
|
|
85
|
-
control={<Switch checked={state.custom} sx={{ marginRight: 0.4 }} onChange={handleToggle} />}
|
|
86
|
-
label={state.custom ? t('payment.checkout.donation.select') : t('payment.checkout.donation.custom')}
|
|
87
|
-
sx={{ marginRight: 2, marginLeft: 0.5, color: 'text.lighter' }}
|
|
88
|
-
/>
|
|
89
|
-
)}
|
|
90
|
-
{!state.custom && (
|
|
91
|
-
<Box display="flex" flexWrap="wrap" alignItems="center" gap={1.5}>
|
|
93
|
+
{supportPreset && (
|
|
94
|
+
<Grid container spacing={2}>
|
|
92
95
|
{settings.amount.presets &&
|
|
93
96
|
settings.amount.presets.length > 0 &&
|
|
94
97
|
settings.amount.presets.map((amount) => (
|
|
98
|
+
<Grid item xs={6} sm={3} key={amount}>
|
|
99
|
+
<Card
|
|
100
|
+
key={amount}
|
|
101
|
+
variant="outlined"
|
|
102
|
+
sx={{
|
|
103
|
+
minWidth: 115,
|
|
104
|
+
textAlign: 'center',
|
|
105
|
+
transition: 'all 0.3s',
|
|
106
|
+
cursor: 'pointer',
|
|
107
|
+
'&:hover': {
|
|
108
|
+
transform: 'translateY(-4px)',
|
|
109
|
+
boxShadow: 3,
|
|
110
|
+
},
|
|
111
|
+
height: '42px',
|
|
112
|
+
...(state.selected === amount && !state.custom
|
|
113
|
+
? { borderColor: 'primary.main', borderWidth: 1 }
|
|
114
|
+
: {}),
|
|
115
|
+
}}>
|
|
116
|
+
<CardActionArea onClick={() => handleSelect(amount)}>
|
|
117
|
+
<Stack
|
|
118
|
+
direction="row"
|
|
119
|
+
sx={{ py: 1.5, px: 1.5 }}
|
|
120
|
+
spacing={0.5}
|
|
121
|
+
alignItems="center"
|
|
122
|
+
justifyContent="center">
|
|
123
|
+
<Avatar src={currency?.logo} sx={{ width: 16, height: 16, mr: 0.5 }} alt={currency?.symbol} />
|
|
124
|
+
<Typography
|
|
125
|
+
component="strong"
|
|
126
|
+
lineHeight={1}
|
|
127
|
+
variant="h3"
|
|
128
|
+
sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 400 }}>
|
|
129
|
+
{amount}
|
|
130
|
+
</Typography>
|
|
131
|
+
<Typography lineHeight={1} fontSize={14} color="text.secondary">
|
|
132
|
+
{currency?.symbol}
|
|
133
|
+
</Typography>
|
|
134
|
+
</Stack>
|
|
135
|
+
</CardActionArea>
|
|
136
|
+
</Card>
|
|
137
|
+
</Grid>
|
|
138
|
+
))}
|
|
139
|
+
{supportCustom && (
|
|
140
|
+
<Grid item xs={6} sm={3} key="custom">
|
|
95
141
|
<Card
|
|
96
|
-
key=
|
|
142
|
+
key="custom"
|
|
97
143
|
variant="outlined"
|
|
98
144
|
sx={{
|
|
99
|
-
minWidth: 115,
|
|
100
145
|
textAlign: 'center',
|
|
101
|
-
|
|
146
|
+
transition: 'all 0.3s',
|
|
147
|
+
cursor: 'pointer',
|
|
148
|
+
'&:hover': {
|
|
149
|
+
transform: 'translateY(-4px)',
|
|
150
|
+
boxShadow: 3,
|
|
151
|
+
},
|
|
152
|
+
height: '42px',
|
|
153
|
+
...(state.custom ? { borderColor: 'primary.main', borderWidth: 1 } : {}),
|
|
102
154
|
}}>
|
|
103
|
-
<CardActionArea onClick={() =>
|
|
155
|
+
<CardActionArea onClick={() => handleCustomSelect()}>
|
|
104
156
|
<Stack
|
|
105
157
|
direction="row"
|
|
106
|
-
sx={{ py: 1, px:
|
|
158
|
+
sx={{ py: 1.5, px: 1.5 }}
|
|
107
159
|
spacing={0.5}
|
|
108
|
-
alignItems="
|
|
160
|
+
alignItems="center"
|
|
109
161
|
justifyContent="center">
|
|
110
|
-
<Typography
|
|
111
|
-
|
|
112
|
-
lineHeight={1}
|
|
113
|
-
variant="h3"
|
|
114
|
-
sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 400 }}>
|
|
115
|
-
{amount}
|
|
162
|
+
<Typography variant="h3" lineHeight={1} sx={{ fontWeight: 400 }}>
|
|
163
|
+
{t('common.custom')}
|
|
116
164
|
</Typography>
|
|
117
|
-
<Typography component="small" lineHeight={1} fontSize={12}>
|
|
118
|
-
ABT
|
|
119
|
-
</Typography>{' '}
|
|
120
165
|
</Stack>
|
|
121
166
|
</CardActionArea>
|
|
122
167
|
</Card>
|
|
123
|
-
|
|
124
|
-
|
|
168
|
+
</Grid>
|
|
169
|
+
)}
|
|
170
|
+
</Grid>
|
|
125
171
|
)}
|
|
126
172
|
{state.custom && (
|
|
127
173
|
<TextField
|
|
128
|
-
label={preset !== '0' ? null : t('payment.checkout.donation.custom')}
|
|
129
174
|
type="number"
|
|
130
175
|
value={state.input}
|
|
131
176
|
onChange={handleInput}
|
|
132
|
-
inputProps={{ min: settings.amount.minimum, max: settings.amount.maximum }}
|
|
133
177
|
margin="none"
|
|
134
178
|
fullWidth
|
|
135
179
|
error={!!state.error}
|
|
136
180
|
helperText={state.error}
|
|
181
|
+
inputRef={customInputRef}
|
|
182
|
+
// eslint-disable-next-line react/jsx-no-duplicate-props
|
|
183
|
+
InputProps={{
|
|
184
|
+
endAdornment: (
|
|
185
|
+
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ ml: 1 }}>
|
|
186
|
+
<Avatar src={currency?.logo} sx={{ width: 16, height: 16 }} alt={currency?.symbol} />
|
|
187
|
+
<Typography>{currency?.symbol}</Typography>
|
|
188
|
+
</Stack>
|
|
189
|
+
),
|
|
190
|
+
autoComplete: 'off',
|
|
191
|
+
}}
|
|
137
192
|
sx={{
|
|
138
193
|
mt: preset !== '0' ? 0 : 1,
|
|
139
194
|
}}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Box, Divider, Fade, Skeleton, Stack } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
export default function DonationSkeleton() {
|
|
4
|
+
return (
|
|
5
|
+
<Fade in>
|
|
6
|
+
<Stack direction="column">
|
|
7
|
+
<Skeleton variant="text" sx={{ fontSize: '2rem', width: '40%' }} />
|
|
8
|
+
<Skeleton sx={{ mt: 2 }} variant="rounded" height={80} />
|
|
9
|
+
<Divider
|
|
10
|
+
sx={{
|
|
11
|
+
mt: {
|
|
12
|
+
xs: '16px',
|
|
13
|
+
md: '16px',
|
|
14
|
+
},
|
|
15
|
+
mb: {
|
|
16
|
+
xs: '16px',
|
|
17
|
+
md: '16px',
|
|
18
|
+
},
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
<Stack direction="row" justifyContent="space-between" spacing={2}>
|
|
22
|
+
<Skeleton variant="text" sx={{ fontSize: '1.5rem', width: '40%' }} />
|
|
23
|
+
<Box display="flex" alignItems="center" gap={2}>
|
|
24
|
+
<Box>
|
|
25
|
+
<Skeleton height={60} width={80} />
|
|
26
|
+
</Box>
|
|
27
|
+
<Box>
|
|
28
|
+
<Skeleton height={60} width={120} />
|
|
29
|
+
</Box>
|
|
30
|
+
</Box>
|
|
31
|
+
</Stack>
|
|
32
|
+
</Stack>
|
|
33
|
+
</Fade>
|
|
34
|
+
);
|
|
35
|
+
}
|
package/src/theme/index.tsx
CHANGED
|
@@ -48,6 +48,9 @@ export function PaymentThemeProvider({
|
|
|
48
48
|
minHeight: '1.65em',
|
|
49
49
|
lineHeight: '1.65em',
|
|
50
50
|
},
|
|
51
|
+
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
|
52
|
+
borderWidth: '1px',
|
|
53
|
+
},
|
|
51
54
|
},
|
|
52
55
|
},
|
|
53
56
|
},
|
|
@@ -121,6 +124,9 @@ export function PaymentThemeProvider({
|
|
|
121
124
|
},
|
|
122
125
|
MuiPopover: {
|
|
123
126
|
styleOverrides: {
|
|
127
|
+
root: {
|
|
128
|
+
zIndex: 1200,
|
|
129
|
+
},
|
|
124
130
|
paper: ({ theme }) => ({
|
|
125
131
|
border: `1px solid ${theme.palette.divider}`,
|
|
126
132
|
boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
|
|
@@ -241,6 +247,13 @@ export function PaymentThemeProvider({
|
|
|
241
247
|
},
|
|
242
248
|
},
|
|
243
249
|
},
|
|
250
|
+
MuiDialog: {
|
|
251
|
+
styleOverrides: {
|
|
252
|
+
root: {
|
|
253
|
+
zIndex: 1200,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
244
257
|
},
|
|
245
258
|
};
|
|
246
259
|
|
package/src/types/index.ts
CHANGED
|
@@ -46,6 +46,8 @@ export type CheckoutProps = Partial<CheckoutCallbacks> & {
|
|
|
46
46
|
action?: string;
|
|
47
47
|
mode?: LiteralUnion<'standalone' | 'inline' | 'popup' | 'inline-minimal' | 'popup-minimal', string>;
|
|
48
48
|
theme?: 'default' | 'inherit' | PaymentThemeOptions;
|
|
49
|
+
formType?: 'donation' | 'payment';
|
|
50
|
+
formRender?: Record<string, any>;
|
|
49
51
|
};
|
|
50
52
|
|
|
51
53
|
export type CheckoutCallbacks = {
|