@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.
- 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/index.d.ts +2 -1
- package/es/index.js +2 -0
- 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 +1 -0
- package/es/util.js +44 -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/index.d.ts +2 -1
- package/lib/index.js +8 -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 +1 -0
- package/lib/util.js +39 -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/index.ts +2 -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 +50 -3
package/src/payment/index.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable import/no-extraneous-dependencies */
|
|
1
|
+
/* eslint-disable no-nested-ternary */
|
|
3
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
3
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
5
4
|
import type {
|
|
@@ -12,10 +11,11 @@ import type {
|
|
|
12
11
|
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
13
12
|
import { Box, Fade, Stack } from '@mui/material';
|
|
14
13
|
import { styled } from '@mui/system';
|
|
14
|
+
import { fromTokenToUnit } from '@ocap/util';
|
|
15
15
|
import { useSetState } from 'ahooks';
|
|
16
16
|
import { useEffect, useState } from 'react';
|
|
17
17
|
import { FormProvider, useForm, useWatch } from 'react-hook-form';
|
|
18
|
-
import { LiteralUnion } from 'type-fest';
|
|
18
|
+
import type { LiteralUnion } from 'type-fest';
|
|
19
19
|
|
|
20
20
|
import api from '../api';
|
|
21
21
|
import { usePaymentContext } from '../contexts/payment';
|
|
@@ -50,6 +50,7 @@ export default function Payment({
|
|
|
50
50
|
onError,
|
|
51
51
|
onChange,
|
|
52
52
|
goBack,
|
|
53
|
+
action,
|
|
53
54
|
}: Props) {
|
|
54
55
|
const { t } = useLocaleContext();
|
|
55
56
|
const { refresh, livemode, setLivemode } = usePaymentContext();
|
|
@@ -74,7 +75,7 @@ export default function Payment({
|
|
|
74
75
|
}, [checkoutSession, livemode, setLivemode, refresh]);
|
|
75
76
|
|
|
76
77
|
if (error) {
|
|
77
|
-
return <PaymentError title="Oops" description={formatError(error)} />;
|
|
78
|
+
return <PaymentError mode={mode} title="Oops" description={formatError(error)} />;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
if (!checkoutSession || !delay) {
|
|
@@ -87,7 +88,7 @@ export default function Payment({
|
|
|
87
88
|
<Stack className="cko-payment">
|
|
88
89
|
<PaymentSkeleton />
|
|
89
90
|
</Stack>
|
|
90
|
-
<CheckoutFooter className="cko-footer" />
|
|
91
|
+
{mode === 'standalone' && <CheckoutFooter className="cko-footer" />}
|
|
91
92
|
</Stack>
|
|
92
93
|
</Root>
|
|
93
94
|
);
|
|
@@ -96,12 +97,11 @@ export default function Payment({
|
|
|
96
97
|
// expired session
|
|
97
98
|
if (checkoutSession.expires_at <= Math.round(Date.now() / 1000)) {
|
|
98
99
|
return (
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
</Center>
|
|
100
|
+
<PaymentError
|
|
101
|
+
mode={mode}
|
|
102
|
+
title={t('payment.checkout.expired.title')}
|
|
103
|
+
description={t('payment.checkout.expired.description')}
|
|
104
|
+
/>
|
|
105
105
|
);
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -109,6 +109,7 @@ export default function Payment({
|
|
|
109
109
|
if (checkoutSession.status === 'complete') {
|
|
110
110
|
return (
|
|
111
111
|
<PaymentError
|
|
112
|
+
mode={mode}
|
|
112
113
|
title={t('payment.checkout.complete.title')}
|
|
113
114
|
description={t('payment.checkout.complete.description')}
|
|
114
115
|
/>
|
|
@@ -128,6 +129,7 @@ export default function Payment({
|
|
|
128
129
|
onChange={onChange}
|
|
129
130
|
goBack={goBack}
|
|
130
131
|
mode={mode}
|
|
132
|
+
action={action}
|
|
131
133
|
/>
|
|
132
134
|
);
|
|
133
135
|
}
|
|
@@ -150,6 +152,7 @@ export function PaymentInner({
|
|
|
150
152
|
onError,
|
|
151
153
|
onChange,
|
|
152
154
|
goBack,
|
|
155
|
+
action,
|
|
153
156
|
}: MainProps) {
|
|
154
157
|
const { t } = useLocaleContext();
|
|
155
158
|
const { settings, session } = usePaymentContext();
|
|
@@ -232,6 +235,19 @@ export function PaymentInner({
|
|
|
232
235
|
}
|
|
233
236
|
};
|
|
234
237
|
|
|
238
|
+
const onChangeAmount = async ({ priceId, amount }: { priceId: string; amount: string }) => {
|
|
239
|
+
try {
|
|
240
|
+
const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/amount`, {
|
|
241
|
+
priceId,
|
|
242
|
+
amount: fromTokenToUnit(amount, currency.decimal).toString(),
|
|
243
|
+
});
|
|
244
|
+
setState({ checkoutSession: data });
|
|
245
|
+
} catch (err) {
|
|
246
|
+
console.error(err);
|
|
247
|
+
Toast.error(formatError(err));
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
235
251
|
const handlePaid = (result: any) => {
|
|
236
252
|
setState({ checkoutSession: result.checkoutSession });
|
|
237
253
|
onPaid(result);
|
|
@@ -247,7 +263,7 @@ export function PaymentInner({
|
|
|
247
263
|
fontSize="medium"
|
|
248
264
|
/>
|
|
249
265
|
)}
|
|
250
|
-
<Stack className="cko-container" sx={{ gap: { sm: mode === 'standalone' ? 0 : 8 } }}>
|
|
266
|
+
<Stack className="cko-container" sx={{ gap: { sm: mode === 'standalone' ? 0 : mode === 'inline' ? 4 : 8 } }}>
|
|
251
267
|
<Fade in>
|
|
252
268
|
<Stack className="cko-overview" direction="column">
|
|
253
269
|
{mode === 'standalone' ? <PaymentHeader checkoutSession={state.checkoutSession} /> : null}
|
|
@@ -261,21 +277,29 @@ export function PaymentInner({
|
|
|
261
277
|
onDownsell={onDownsell}
|
|
262
278
|
onApplyCrossSell={onApplyCrossSell}
|
|
263
279
|
onCancelCrossSell={onCancelCrossSell}
|
|
280
|
+
onChangeAmount={onChangeAmount}
|
|
264
281
|
checkoutSessionId={state.checkoutSession.id}
|
|
265
282
|
crossSellBehavior={state.checkoutSession.cross_sell_behavior}
|
|
283
|
+
donationSettings={paymentLink?.donation_settings}
|
|
284
|
+
action={action}
|
|
266
285
|
/>
|
|
267
286
|
</Stack>
|
|
268
287
|
</Fade>
|
|
269
|
-
<Stack className="cko-payment" direction="column" spacing={4}>
|
|
288
|
+
<Stack className="cko-payment" direction="column" spacing={{ xs: 2, sm: 4 }}>
|
|
270
289
|
{completed && (
|
|
271
290
|
<PaymentSuccess
|
|
291
|
+
mode={mode}
|
|
272
292
|
payee={getStatementDescriptor(state.checkoutSession.line_items)}
|
|
273
293
|
action={state.checkoutSession.mode}
|
|
274
294
|
invoiceId={state.checkoutSession.invoice_id}
|
|
275
295
|
subscriptionId={state.checkoutSession.subscription_id}
|
|
276
296
|
message={
|
|
277
297
|
paymentLink?.after_completion?.hosted_confirmation?.custom_message ||
|
|
278
|
-
t(
|
|
298
|
+
t(
|
|
299
|
+
`payment.checkout.completed.${
|
|
300
|
+
paymentLink?.donation_settings ? 'donate' : state.checkoutSession.mode
|
|
301
|
+
}`
|
|
302
|
+
)
|
|
279
303
|
}
|
|
280
304
|
/>
|
|
281
305
|
)}
|
|
@@ -284,10 +308,12 @@ export function PaymentInner({
|
|
|
284
308
|
checkoutSession={state.checkoutSession}
|
|
285
309
|
paymentMethods={paymentMethods as TPaymentMethodExpanded[]}
|
|
286
310
|
paymentIntent={paymentIntent}
|
|
311
|
+
paymentLink={paymentLink}
|
|
287
312
|
customer={customer}
|
|
288
313
|
onPaid={handlePaid}
|
|
289
314
|
onError={onError}
|
|
290
315
|
mode={mode}
|
|
316
|
+
action={action}
|
|
291
317
|
/>
|
|
292
318
|
)}
|
|
293
319
|
</Stack>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
+
import type { DonationSettings, TLineItemExpanded } from '@blocklet/payment-types';
|
|
3
|
+
import { Box, Card, CardActionArea, FormControlLabel, Stack, TextField, Typography } from '@mui/material';
|
|
4
|
+
import { useSetState } from 'ahooks';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
import Switch from '../components/switch-button';
|
|
8
|
+
|
|
9
|
+
export default function ProductDonation({
|
|
10
|
+
item,
|
|
11
|
+
settings,
|
|
12
|
+
onChange,
|
|
13
|
+
}: {
|
|
14
|
+
item: TLineItemExpanded;
|
|
15
|
+
settings: DonationSettings;
|
|
16
|
+
onChange: Function;
|
|
17
|
+
}) {
|
|
18
|
+
const { t } = useLocaleContext();
|
|
19
|
+
const preset = settings.amount.preset || settings.amount.presets?.[0] || '0';
|
|
20
|
+
const [state, setState] = useSetState({
|
|
21
|
+
selected: preset,
|
|
22
|
+
input: '',
|
|
23
|
+
custom: settings.amount.presets?.length === 0,
|
|
24
|
+
error: '',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Set default amount
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (settings.amount.preset) {
|
|
30
|
+
setState({ selected: settings.amount.preset, custom: false });
|
|
31
|
+
} else if (settings.amount.presets && settings.amount.presets.length > 0) {
|
|
32
|
+
setState({ selected: settings.amount.presets[0], custom: false });
|
|
33
|
+
}
|
|
34
|
+
}, [settings.amount.preset, settings.amount.presets, setState]);
|
|
35
|
+
|
|
36
|
+
const handleSelect = (amount: string) => {
|
|
37
|
+
setState({ selected: amount, custom: false, error: '' });
|
|
38
|
+
onChange({ priceId: item.price_id, amount });
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handleInput = (event: any) => {
|
|
42
|
+
const { value } = event.target;
|
|
43
|
+
const min = parseFloat(settings.amount.minimum || '0');
|
|
44
|
+
const max = settings.amount.maximum ? parseFloat(settings.amount.maximum) : Infinity;
|
|
45
|
+
|
|
46
|
+
if (value < min || value > max) {
|
|
47
|
+
setState({ input: value, error: t('payment.checkout.donation.between', { min, max }) });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setState({ error: '', input: value });
|
|
52
|
+
onChange({ priceId: item.price_id, amount: value });
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleToggle = (event: any) => {
|
|
56
|
+
if (event.target.checked) {
|
|
57
|
+
setState({ custom: true, input: state.selected, error: '' });
|
|
58
|
+
} else {
|
|
59
|
+
setState({ custom: false, input: '', error: '' });
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Box display="flex" flexDirection="column" alignItems="flex-start" gap={1.5}>
|
|
65
|
+
{settings.amount.custom && preset !== '0' && (
|
|
66
|
+
<FormControlLabel
|
|
67
|
+
control={<Switch checked={state.custom} sx={{ marginRight: 0.4 }} onChange={handleToggle} />}
|
|
68
|
+
label={state.custom ? t('payment.checkout.donation.select') : t('payment.checkout.donation.custom')}
|
|
69
|
+
sx={{ marginRight: 2, marginLeft: 0.5, color: 'text.secondary' }}
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
{!state.custom && (
|
|
73
|
+
<Box display="flex" flexWrap="wrap" alignItems="center" gap={1.5}>
|
|
74
|
+
{settings.amount.presets &&
|
|
75
|
+
settings.amount.presets.length > 0 &&
|
|
76
|
+
settings.amount.presets.map((amount) => (
|
|
77
|
+
<Card
|
|
78
|
+
key={amount}
|
|
79
|
+
variant="outlined"
|
|
80
|
+
sx={{
|
|
81
|
+
minWidth: 120,
|
|
82
|
+
textAlign: 'center',
|
|
83
|
+
...(state.selected === amount && !state.custom ? { borderColor: 'primary.main' } : {}),
|
|
84
|
+
}}>
|
|
85
|
+
<CardActionArea onClick={() => handleSelect(amount)}>
|
|
86
|
+
<Stack direction="row" sx={{ py: 1 }} spacing={0.5} alignItems="flex-end" justifyContent="center">
|
|
87
|
+
<Typography
|
|
88
|
+
component="strong"
|
|
89
|
+
lineHeight={1}
|
|
90
|
+
variant="h5"
|
|
91
|
+
sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 400 }}>
|
|
92
|
+
{amount}
|
|
93
|
+
</Typography>
|
|
94
|
+
<Typography component="small" lineHeight={1} fontSize={12}>
|
|
95
|
+
ABT
|
|
96
|
+
</Typography>{' '}
|
|
97
|
+
</Stack>
|
|
98
|
+
</CardActionArea>
|
|
99
|
+
</Card>
|
|
100
|
+
))}
|
|
101
|
+
</Box>
|
|
102
|
+
)}
|
|
103
|
+
{state.custom && (
|
|
104
|
+
<TextField
|
|
105
|
+
label={preset !== '0' ? null : t('payment.checkout.donation.custom')}
|
|
106
|
+
type="number"
|
|
107
|
+
value={state.input}
|
|
108
|
+
onChange={handleInput}
|
|
109
|
+
inputProps={{ min: settings.amount.minimum, max: settings.amount.maximum }}
|
|
110
|
+
margin="none"
|
|
111
|
+
fullWidth
|
|
112
|
+
error={!!state.error}
|
|
113
|
+
helperText={state.error}
|
|
114
|
+
/>
|
|
115
|
+
)}
|
|
116
|
+
</Box>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
@@ -8,13 +8,13 @@ export default function OverviewSkeleton() {
|
|
|
8
8
|
<Skeleton variant="circular" width={32} height={32} />
|
|
9
9
|
<Skeleton variant="text" sx={{ fontSize: '2rem', width: '40%' }} />
|
|
10
10
|
</Stack>
|
|
11
|
-
<Typography mt={
|
|
11
|
+
<Typography mt={2} component="div" variant="h4">
|
|
12
12
|
<Skeleton />
|
|
13
13
|
</Typography>
|
|
14
14
|
<Typography component="div" variant="h2">
|
|
15
15
|
<Skeleton />
|
|
16
16
|
</Typography>
|
|
17
|
-
<Skeleton sx={{ mt:
|
|
17
|
+
<Skeleton sx={{ mt: 2 }} variant="rounded" width={200} height={200} />
|
|
18
18
|
</Stack>
|
|
19
19
|
</Fade>
|
|
20
20
|
);
|
|
@@ -3,7 +3,7 @@ import { Box, Fade, Skeleton, Stack, Typography } from '@mui/material';
|
|
|
3
3
|
export default function PaymentSkeleton() {
|
|
4
4
|
return (
|
|
5
5
|
<Fade in>
|
|
6
|
-
<Stack direction="column" spacing={
|
|
6
|
+
<Stack direction="column" spacing={2}>
|
|
7
7
|
<Skeleton variant="text" sx={{ fontSize: '2rem', width: '40%' }} />
|
|
8
8
|
<Box>
|
|
9
9
|
<Typography component="div" variant="h4">
|
|
@@ -25,9 +25,6 @@ export default function PaymentSkeleton() {
|
|
|
25
25
|
<Typography component="div" variant="h4">
|
|
26
26
|
<Skeleton />
|
|
27
27
|
</Typography>
|
|
28
|
-
<Typography component="div" variant="h1">
|
|
29
|
-
<Skeleton />
|
|
30
|
-
</Typography>
|
|
31
28
|
</Box>
|
|
32
29
|
</Stack>
|
|
33
30
|
</Fade>
|
package/src/payment/success.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { joinURL } from 'ufo';
|
|
|
6
6
|
import { usePaymentContext } from '../contexts/payment';
|
|
7
7
|
|
|
8
8
|
type Props = {
|
|
9
|
+
mode: string;
|
|
9
10
|
message: string;
|
|
10
11
|
action: string;
|
|
11
12
|
payee: string;
|
|
@@ -13,7 +14,7 @@ type Props = {
|
|
|
13
14
|
subscriptionId?: string;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
export default function PaymentSuccess({ message, action, payee, invoiceId, subscriptionId }: Props) {
|
|
17
|
+
export default function PaymentSuccess({ mode, message, action, payee, invoiceId, subscriptionId }: Props) {
|
|
17
18
|
const { t } = useLocaleContext();
|
|
18
19
|
const { prefix } = usePaymentContext();
|
|
19
20
|
let next: any = null;
|
|
@@ -37,7 +38,11 @@ export default function PaymentSuccess({ message, action, payee, invoiceId, subs
|
|
|
37
38
|
|
|
38
39
|
return (
|
|
39
40
|
<Grow in>
|
|
40
|
-
<Stack
|
|
41
|
+
<Stack
|
|
42
|
+
direction="column"
|
|
43
|
+
alignItems="center"
|
|
44
|
+
justifyContent={mode === 'standalone' ? 'center' : 'flex-start'}
|
|
45
|
+
sx={{ height: mode === 'standalone' ? 360 : 300 }}>
|
|
41
46
|
<Div>
|
|
42
47
|
<div className="check-icon">
|
|
43
48
|
<span className="icon-line line-tip" />
|
package/src/payment/summary.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
-
import type { TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
|
|
2
|
+
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
|
|
3
3
|
import { InfoOutlined } from '@mui/icons-material';
|
|
4
4
|
import { LoadingButton } from '@mui/lab';
|
|
5
5
|
import { Fade, Grow, Stack, Tooltip, Typography, keyframes } from '@mui/material';
|
|
@@ -12,6 +12,7 @@ import api from '../api';
|
|
|
12
12
|
import Status from '../components/status';
|
|
13
13
|
import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from '../util';
|
|
14
14
|
import PaymentAmount from './amount';
|
|
15
|
+
import ProductDonation from './product-donation';
|
|
15
16
|
import ProductItem from './product-item';
|
|
16
17
|
|
|
17
18
|
const shake = keyframes`
|
|
@@ -40,10 +41,13 @@ type Props = {
|
|
|
40
41
|
showStaking?: boolean;
|
|
41
42
|
onUpsell?: Function;
|
|
42
43
|
onDownsell?: Function;
|
|
44
|
+
onChangeAmount?: Function;
|
|
43
45
|
onApplyCrossSell?: Function;
|
|
44
46
|
onCancelCrossSell?: Function;
|
|
45
47
|
checkoutSessionId?: string;
|
|
46
48
|
crossSellBehavior?: string;
|
|
49
|
+
donationSettings?: DonationSettings; // only include backend part
|
|
50
|
+
action?: string;
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
async function fetchCrossSell(id: string) {
|
|
@@ -91,9 +95,12 @@ PaymentSummary.defaultProps = {
|
|
|
91
95
|
onDownsell: noop,
|
|
92
96
|
onApplyCrossSell: noop,
|
|
93
97
|
onCancelCrossSell: noop,
|
|
98
|
+
onChangeAmount: noop,
|
|
94
99
|
checkoutSessionId: '',
|
|
95
100
|
crossSellBehavior: '',
|
|
96
101
|
showStaking: false,
|
|
102
|
+
donationSettings: null,
|
|
103
|
+
action: '',
|
|
97
104
|
};
|
|
98
105
|
|
|
99
106
|
export default function PaymentSummary({
|
|
@@ -105,9 +112,12 @@ export default function PaymentSummary({
|
|
|
105
112
|
onDownsell,
|
|
106
113
|
onApplyCrossSell,
|
|
107
114
|
onCancelCrossSell,
|
|
115
|
+
onChangeAmount,
|
|
108
116
|
checkoutSessionId,
|
|
109
117
|
crossSellBehavior,
|
|
110
118
|
showStaking,
|
|
119
|
+
donationSettings,
|
|
120
|
+
action,
|
|
111
121
|
...rest
|
|
112
122
|
}: Props) {
|
|
113
123
|
const { t, locale } = useLocaleContext();
|
|
@@ -166,38 +176,47 @@ export default function PaymentSummary({
|
|
|
166
176
|
return (
|
|
167
177
|
<Fade in>
|
|
168
178
|
<Stack className="cko-product" direction="column" {...rest}>
|
|
169
|
-
<Stack className="cko-product-summary" direction="column" alignItems="flex-start" sx={{ mb:
|
|
179
|
+
<Stack className="cko-product-summary" direction="column" alignItems="flex-start" sx={{ mb: { xs: 0, sm: 3 } }}>
|
|
170
180
|
<Typography sx={{ fontWeight: 500, fontSize: '1.15rem', color: 'text.secondary' }}>
|
|
171
|
-
{headlines.action}
|
|
181
|
+
{action || headlines.action}
|
|
172
182
|
</Typography>
|
|
173
183
|
<PaymentAmount amount={headlines.amount} />
|
|
174
184
|
{headlines.then && (
|
|
175
185
|
<Typography sx={{ fontSize: '0.9rem', color: 'text.secondary' }}>{headlines.then}</Typography>
|
|
176
186
|
)}
|
|
177
187
|
</Stack>
|
|
178
|
-
<Stack spacing={2}>
|
|
179
|
-
{items.map((x: TLineItemExpanded) =>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
188
|
+
<Stack spacing={{ xs: 1, sm: 2 }}>
|
|
189
|
+
{items.map((x: TLineItemExpanded) =>
|
|
190
|
+
x.price.custom_unit_amount && onChangeAmount && donationSettings ? (
|
|
191
|
+
<ProductDonation
|
|
192
|
+
key={`${x.price_id}-${currency.id}`}
|
|
193
|
+
item={x}
|
|
194
|
+
settings={donationSettings}
|
|
195
|
+
onChange={onChangeAmount}
|
|
196
|
+
/>
|
|
197
|
+
) : (
|
|
198
|
+
<ProductItem
|
|
199
|
+
key={`${x.price_id}-${currency.id}`}
|
|
200
|
+
item={x}
|
|
201
|
+
items={items}
|
|
202
|
+
trialInDays={trialInDays}
|
|
203
|
+
currency={currency}
|
|
204
|
+
onUpsell={handleUpsell}
|
|
205
|
+
onDownsell={handleDownsell}>
|
|
206
|
+
{x.cross_sell && (
|
|
207
|
+
<LoadingButton
|
|
208
|
+
size="small"
|
|
209
|
+
loadingPosition="end"
|
|
210
|
+
color="error"
|
|
211
|
+
variant="text"
|
|
212
|
+
loading={state.loading}
|
|
213
|
+
onClick={handleCancelCrossSell}>
|
|
214
|
+
{t('payment.checkout.cross_sell.remove')}
|
|
215
|
+
</LoadingButton>
|
|
216
|
+
)}
|
|
217
|
+
</ProductItem>
|
|
218
|
+
)
|
|
219
|
+
)}
|
|
201
220
|
</Stack>
|
|
202
221
|
{data && items.some((x) => x.price_id === data.id) === false && (
|
|
203
222
|
<Grow in>
|
|
@@ -210,7 +229,7 @@ export default function PaymentSummary({
|
|
|
210
229
|
borderRadius: 1,
|
|
211
230
|
padding: 1,
|
|
212
231
|
animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : 'none',
|
|
213
|
-
mt:
|
|
232
|
+
mt: { xs: 1, sm: 2 },
|
|
214
233
|
}}>
|
|
215
234
|
<ProductItem
|
|
216
235
|
item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
|
|
@@ -249,7 +268,7 @@ export default function PaymentSummary({
|
|
|
249
268
|
border: '1px solid #eee',
|
|
250
269
|
borderRadius: 1,
|
|
251
270
|
padding: 1,
|
|
252
|
-
mt:
|
|
271
|
+
mt: { xs: 1, sm: 2 },
|
|
253
272
|
}}>
|
|
254
273
|
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
255
274
|
<Typography>{t('payment.checkout.staking.title')}</Typography>
|
package/src/types/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type CheckoutContext = {
|
|
|
15
15
|
paymentIntent?: TPaymentIntent;
|
|
16
16
|
customer?: TCustomer;
|
|
17
17
|
mode: LiteralUnion<'standalone' | 'inline' | 'popup', string>;
|
|
18
|
+
action?: string;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
export type CheckoutFormData = {
|
|
@@ -36,6 +37,7 @@ export type CheckoutFormData = {
|
|
|
36
37
|
export type CheckoutProps = Partial<CheckoutCallbacks> & {
|
|
37
38
|
id: string;
|
|
38
39
|
extraParams?: Record<string, any>;
|
|
40
|
+
action?: string;
|
|
39
41
|
mode?: LiteralUnion<'standalone' | 'inline' | 'popup' | 'inline-minimal' | 'popup-minimal', string>;
|
|
40
42
|
};
|
|
41
43
|
|
package/src/util.ts
CHANGED
|
@@ -125,6 +125,10 @@ export const formatPrice = (
|
|
|
125
125
|
bn: boolean = true,
|
|
126
126
|
locale: string = 'en'
|
|
127
127
|
) => {
|
|
128
|
+
if (price.custom_unit_amount) {
|
|
129
|
+
return `Custom (${currency.symbol})`;
|
|
130
|
+
}
|
|
131
|
+
|
|
128
132
|
const unit = getPriceUintAmountByCurrency(price, currency);
|
|
129
133
|
const amount = bn
|
|
130
134
|
? fromUnitToToken(new BN(unit).mul(new BN(quantity)), currency.decimal).toString()
|
|
@@ -219,10 +223,16 @@ export function getPriceUintAmountByCurrency(price: TPrice, currency: TPaymentCu
|
|
|
219
223
|
const options = getPriceCurrencyOptions(price);
|
|
220
224
|
const option = options.find((x) => x.currency_id === currency.id);
|
|
221
225
|
if (option) {
|
|
226
|
+
if (option.custom_unit_amount) {
|
|
227
|
+
return option.custom_unit_amount.preset || option.custom_unit_amount.presets[0];
|
|
228
|
+
}
|
|
222
229
|
return option.unit_amount;
|
|
223
230
|
}
|
|
224
231
|
|
|
225
232
|
if (price.currency_id === currency.id) {
|
|
233
|
+
if (price.custom_unit_amount) {
|
|
234
|
+
return price.custom_unit_amount.preset || price.custom_unit_amount.presets[0];
|
|
235
|
+
}
|
|
226
236
|
return price.unit_amount;
|
|
227
237
|
}
|
|
228
238
|
|
|
@@ -235,7 +245,14 @@ export function getPriceCurrencyOptions(price: TPrice): PriceCurrency[] {
|
|
|
235
245
|
return price.currency_options;
|
|
236
246
|
}
|
|
237
247
|
|
|
238
|
-
return [
|
|
248
|
+
return [
|
|
249
|
+
{
|
|
250
|
+
currency_id: price.currency_id,
|
|
251
|
+
unit_amount: price.unit_amount,
|
|
252
|
+
custom_unit_amount: price.custom_unit_amount || null,
|
|
253
|
+
tiers: null,
|
|
254
|
+
},
|
|
255
|
+
];
|
|
239
256
|
}
|
|
240
257
|
|
|
241
258
|
export function formatLineItemPricing(
|
|
@@ -339,6 +356,20 @@ export function getRefundStatusColor(status: string) {
|
|
|
339
356
|
}
|
|
340
357
|
}
|
|
341
358
|
|
|
359
|
+
export function getPayoutStatusColor(status: string) {
|
|
360
|
+
switch (status) {
|
|
361
|
+
case 'paid':
|
|
362
|
+
return 'success';
|
|
363
|
+
case 'failed':
|
|
364
|
+
return 'warning';
|
|
365
|
+
case 'canceled':
|
|
366
|
+
case 'pending':
|
|
367
|
+
case 'in_transit':
|
|
368
|
+
default:
|
|
369
|
+
return 'default';
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
342
373
|
export function getInvoiceStatusColor(status: string) {
|
|
343
374
|
switch (status) {
|
|
344
375
|
case 'paid':
|
|
@@ -370,6 +401,10 @@ export function getCheckoutAmount(
|
|
|
370
401
|
trialing = false,
|
|
371
402
|
upsell = true
|
|
372
403
|
) {
|
|
404
|
+
if (items.find((x) => (x.upsell_price || x.price).custom_unit_amount) && items.length > 1) {
|
|
405
|
+
throw new Error('Multiple items with custom unit amount are not supported');
|
|
406
|
+
}
|
|
407
|
+
|
|
373
408
|
let renew = new BN(0);
|
|
374
409
|
const total = items
|
|
375
410
|
.filter((x) => {
|
|
@@ -377,9 +412,20 @@ export function getCheckoutAmount(
|
|
|
377
412
|
return price != null;
|
|
378
413
|
})
|
|
379
414
|
.reduce((acc, x) => {
|
|
415
|
+
if (x.custom_amount) {
|
|
416
|
+
return acc.add(new BN(x.custom_amount));
|
|
417
|
+
}
|
|
418
|
+
|
|
380
419
|
const price = upsell ? x.upsell_price || x.price : x.price;
|
|
420
|
+
const unitPrice = getPriceUintAmountByCurrency(price, currency);
|
|
421
|
+
if (price.custom_unit_amount) {
|
|
422
|
+
if (unitPrice) {
|
|
423
|
+
return acc.add(new BN(unitPrice).mul(new BN(x.quantity)));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
381
427
|
if (price?.type === 'recurring') {
|
|
382
|
-
renew = renew.add(new BN(
|
|
428
|
+
renew = renew.add(new BN(unitPrice).mul(new BN(x.quantity)));
|
|
383
429
|
|
|
384
430
|
if (trialing) {
|
|
385
431
|
return acc;
|
|
@@ -388,7 +434,8 @@ export function getCheckoutAmount(
|
|
|
388
434
|
return acc;
|
|
389
435
|
}
|
|
390
436
|
}
|
|
391
|
-
|
|
437
|
+
|
|
438
|
+
return acc.add(new BN(unitPrice).mul(new BN(x.quantity)));
|
|
392
439
|
}, new BN(0))
|
|
393
440
|
.toString();
|
|
394
441
|
|