@blocklet/payment-react 1.18.0 → 1.18.1
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 +40 -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 +603 -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 +39 -4
- package/es/payment/product-donation.js +98 -57
- package/es/payment/skeleton/donation.d.ts +1 -0
- package/es/payment/skeleton/donation.js +30 -0
- package/es/theme/index.js +3 -0
- package/es/types/index.d.ts +2 -0
- package/lib/checkout/donate.js +76 -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 +644 -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 +35 -2
- package/lib/payment/product-donation.js +140 -73
- package/lib/payment/skeleton/donation.d.ts +1 -0
- package/lib/payment/skeleton/donation.js +66 -0
- package/lib/theme/index.js +3 -0
- package/lib/types/index.d.ts +2 -0
- package/package.json +3 -3
- package/src/checkout/donate.tsx +54 -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 +646 -0
- package/src/payment/error.tsx +13 -4
- package/src/payment/form/index.tsx +46 -4
- package/src/payment/product-donation.tsx +91 -40
- package/src/payment/skeleton/donation.tsx +35 -0
- package/src/theme/index.tsx +3 -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';
|
|
@@ -42,7 +43,7 @@ import StripeCheckout from './stripe';
|
|
|
42
43
|
import { useMobile } from '../../hooks/mobile';
|
|
43
44
|
import { validatePhoneNumber } from '../../libs/phone-validator';
|
|
44
45
|
|
|
45
|
-
const waitForCheckoutComplete = async (sessionId: string) => {
|
|
46
|
+
export const waitForCheckoutComplete = async (sessionId: string) => {
|
|
46
47
|
let result: CheckoutContext;
|
|
47
48
|
|
|
48
49
|
await pWaitFor(
|
|
@@ -71,14 +72,19 @@ const waitForCheckoutComplete = async (sessionId: string) => {
|
|
|
71
72
|
return result;
|
|
72
73
|
};
|
|
73
74
|
|
|
74
|
-
const hasDidWallet = (user: any) => {
|
|
75
|
+
export const hasDidWallet = (user: any) => {
|
|
75
76
|
const connected = user?.connectedAccounts || user?.extraConfigs?.connectedAccounts || [];
|
|
76
77
|
return connected.some((x: any) => x.provider === 'wallet');
|
|
77
78
|
};
|
|
78
79
|
|
|
79
|
-
type PageData = CheckoutContext &
|
|
80
|
+
type PageData = CheckoutContext &
|
|
81
|
+
CheckoutCallbacks & {
|
|
82
|
+
onlyShowBtn?: boolean;
|
|
83
|
+
};
|
|
80
84
|
|
|
81
|
-
PaymentForm.defaultProps = {
|
|
85
|
+
PaymentForm.defaultProps = {
|
|
86
|
+
onlyShowBtn: false,
|
|
87
|
+
};
|
|
82
88
|
|
|
83
89
|
// FIXME: https://stripe.com/docs/elements/address-element
|
|
84
90
|
// TODO: https://country-regions.github.io/react-country-region-selector/
|
|
@@ -96,6 +102,7 @@ export default function PaymentForm({
|
|
|
96
102
|
// mode,
|
|
97
103
|
action,
|
|
98
104
|
currencyId,
|
|
105
|
+
onlyShowBtn,
|
|
99
106
|
}: PageData) {
|
|
100
107
|
// const theme = useTheme();
|
|
101
108
|
const { t } = useLocaleContext();
|
|
@@ -398,6 +405,40 @@ export default function PaymentForm({
|
|
|
398
405
|
setState({ stripePaying: false });
|
|
399
406
|
};
|
|
400
407
|
|
|
408
|
+
if (onlyShowBtn) {
|
|
409
|
+
return (
|
|
410
|
+
<>
|
|
411
|
+
<Box className="cko-payment-submit-btn">
|
|
412
|
+
<LoadingButton
|
|
413
|
+
variant="contained"
|
|
414
|
+
color="primary"
|
|
415
|
+
size="large"
|
|
416
|
+
className="cko-submit-button"
|
|
417
|
+
onClick={onAction}
|
|
418
|
+
fullWidth
|
|
419
|
+
disabled={state.submitting || state.paying || state.stripePaying || !quantityInventoryStatus || !payable}
|
|
420
|
+
loading={state.submitting || state.paying}>
|
|
421
|
+
{state.submitting || state.paying ? t('payment.checkout.processing') : buttonText}
|
|
422
|
+
</LoadingButton>
|
|
423
|
+
</Box>
|
|
424
|
+
{state.customerLimited && (
|
|
425
|
+
<ConfirmDialog
|
|
426
|
+
onConfirm={() =>
|
|
427
|
+
window.open(
|
|
428
|
+
joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
|
|
429
|
+
'_self'
|
|
430
|
+
)
|
|
431
|
+
}
|
|
432
|
+
onCancel={() => setState({ customerLimited: false })}
|
|
433
|
+
confirm={t('payment.customer.pastDue.alert.confirm')}
|
|
434
|
+
title={t('payment.customer.pastDue.alert.title')}
|
|
435
|
+
message={t('payment.customer.pastDue.alert.description')}
|
|
436
|
+
color="primary"
|
|
437
|
+
/>
|
|
438
|
+
)}
|
|
439
|
+
</>
|
|
440
|
+
);
|
|
441
|
+
}
|
|
401
442
|
return (
|
|
402
443
|
<>
|
|
403
444
|
<Fade in>
|
|
@@ -498,6 +539,7 @@ export default function PaymentForm({
|
|
|
498
539
|
</Stack>
|
|
499
540
|
</Fade>
|
|
500
541
|
<Divider sx={{ mt: 2.5, mb: 2.5 }} />
|
|
542
|
+
|
|
501
543
|
<Fade in>
|
|
502
544
|
<Stack className="cko-payment-submit">
|
|
503
545
|
<Box className="cko-payment-submit-btn">
|
|
@@ -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,6 +45,14 @@ 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) => {
|
|
46
57
|
setState({ selected: amount, custom: false, error: '' });
|
|
47
58
|
onChange({ priceId: item.price_id, amount });
|
|
@@ -69,71 +80,111 @@ export default function ProductDonation({
|
|
|
69
80
|
onChange({ priceId: item.price_id, amount: value });
|
|
70
81
|
};
|
|
71
82
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
setState({ custom: true, input: state.selected, error: '' });
|
|
75
|
-
} else {
|
|
76
|
-
setPayable(true);
|
|
77
|
-
handleSelect(preset);
|
|
78
|
-
}
|
|
83
|
+
const handleCustomSelect = () => {
|
|
84
|
+
setState({ custom: true, error: '' });
|
|
79
85
|
};
|
|
80
86
|
|
|
81
87
|
return (
|
|
82
88
|
<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}>
|
|
89
|
+
{supportPreset && (
|
|
90
|
+
<Grid container spacing={2}>
|
|
92
91
|
{settings.amount.presets &&
|
|
93
92
|
settings.amount.presets.length > 0 &&
|
|
94
93
|
settings.amount.presets.map((amount) => (
|
|
94
|
+
<Grid item xs={6} sm={3} key={amount}>
|
|
95
|
+
<Card
|
|
96
|
+
key={amount}
|
|
97
|
+
variant="outlined"
|
|
98
|
+
sx={{
|
|
99
|
+
minWidth: 115,
|
|
100
|
+
textAlign: 'center',
|
|
101
|
+
transition: 'all 0.3s',
|
|
102
|
+
cursor: 'pointer',
|
|
103
|
+
'&:hover': {
|
|
104
|
+
transform: 'translateY(-4px)',
|
|
105
|
+
boxShadow: 3,
|
|
106
|
+
},
|
|
107
|
+
height: '42px',
|
|
108
|
+
...(state.selected === amount && !state.custom
|
|
109
|
+
? { borderColor: 'primary.main', borderWidth: 1 }
|
|
110
|
+
: {}),
|
|
111
|
+
}}>
|
|
112
|
+
<CardActionArea onClick={() => handleSelect(amount)}>
|
|
113
|
+
<Stack
|
|
114
|
+
direction="row"
|
|
115
|
+
sx={{ py: 1.5, px: 1.5 }}
|
|
116
|
+
spacing={0.5}
|
|
117
|
+
alignItems="center"
|
|
118
|
+
justifyContent="center">
|
|
119
|
+
<Avatar src={currency?.logo} sx={{ width: 16, height: 16, mr: 0.5 }} alt={currency?.symbol} />
|
|
120
|
+
<Typography
|
|
121
|
+
component="strong"
|
|
122
|
+
lineHeight={1}
|
|
123
|
+
variant="h3"
|
|
124
|
+
sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 400 }}>
|
|
125
|
+
{amount}
|
|
126
|
+
</Typography>
|
|
127
|
+
<Typography lineHeight={1} fontSize={14} color="text.secondary">
|
|
128
|
+
{currency?.symbol}
|
|
129
|
+
</Typography>
|
|
130
|
+
</Stack>
|
|
131
|
+
</CardActionArea>
|
|
132
|
+
</Card>
|
|
133
|
+
</Grid>
|
|
134
|
+
))}
|
|
135
|
+
{supportCustom && (
|
|
136
|
+
<Grid item xs={6} sm={3} key="custom">
|
|
95
137
|
<Card
|
|
96
|
-
key=
|
|
138
|
+
key="custom"
|
|
97
139
|
variant="outlined"
|
|
98
140
|
sx={{
|
|
99
|
-
minWidth: 115,
|
|
100
141
|
textAlign: 'center',
|
|
101
|
-
|
|
142
|
+
transition: 'all 0.3s',
|
|
143
|
+
cursor: 'pointer',
|
|
144
|
+
'&:hover': {
|
|
145
|
+
transform: 'translateY(-4px)',
|
|
146
|
+
boxShadow: 3,
|
|
147
|
+
},
|
|
148
|
+
height: '42px',
|
|
149
|
+
...(state.custom ? { borderColor: 'primary.main', borderWidth: 1 } : {}),
|
|
102
150
|
}}>
|
|
103
|
-
<CardActionArea onClick={() =>
|
|
151
|
+
<CardActionArea onClick={() => handleCustomSelect()}>
|
|
104
152
|
<Stack
|
|
105
153
|
direction="row"
|
|
106
|
-
sx={{ py: 1, px:
|
|
154
|
+
sx={{ py: 1.5, px: 1.5 }}
|
|
107
155
|
spacing={0.5}
|
|
108
|
-
alignItems="
|
|
156
|
+
alignItems="center"
|
|
109
157
|
justifyContent="center">
|
|
110
|
-
<Typography
|
|
111
|
-
|
|
112
|
-
lineHeight={1}
|
|
113
|
-
variant="h3"
|
|
114
|
-
sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 400 }}>
|
|
115
|
-
{amount}
|
|
158
|
+
<Typography variant="h3" lineHeight={1} sx={{ fontWeight: 400 }}>
|
|
159
|
+
{t('common.custom')}
|
|
116
160
|
</Typography>
|
|
117
|
-
<Typography component="small" lineHeight={1} fontSize={12}>
|
|
118
|
-
ABT
|
|
119
|
-
</Typography>{' '}
|
|
120
161
|
</Stack>
|
|
121
162
|
</CardActionArea>
|
|
122
163
|
</Card>
|
|
123
|
-
|
|
124
|
-
|
|
164
|
+
</Grid>
|
|
165
|
+
)}
|
|
166
|
+
</Grid>
|
|
125
167
|
)}
|
|
126
168
|
{state.custom && (
|
|
127
169
|
<TextField
|
|
128
|
-
label={preset !== '0' ? null : t('payment.checkout.donation.custom')}
|
|
129
170
|
type="number"
|
|
130
171
|
value={state.input}
|
|
131
172
|
onChange={handleInput}
|
|
132
|
-
inputProps={{ min: settings.amount.minimum, max: settings.amount.maximum }}
|
|
133
173
|
margin="none"
|
|
134
174
|
fullWidth
|
|
135
175
|
error={!!state.error}
|
|
136
176
|
helperText={state.error}
|
|
177
|
+
inputRef={customInputRef}
|
|
178
|
+
// eslint-disable-next-line react/jsx-no-duplicate-props
|
|
179
|
+
InputProps={{
|
|
180
|
+
endAdornment: (
|
|
181
|
+
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ ml: 1 }}>
|
|
182
|
+
<Avatar src={currency?.logo} sx={{ width: 16, height: 16 }} alt={currency?.symbol} />
|
|
183
|
+
<Typography>{currency?.symbol}</Typography>
|
|
184
|
+
</Stack>
|
|
185
|
+
),
|
|
186
|
+
autoComplete: 'off',
|
|
187
|
+
}}
|
|
137
188
|
sx={{
|
|
138
189
|
mt: preset !== '0' ? 0 : 1,
|
|
139
190
|
}}
|
|
@@ -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
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 = {
|