@blocklet/payment-react 1.18.29 → 1.18.31
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 +51 -23
- package/es/components/country-select.js +1 -0
- package/es/components/over-due-invoice-payment.js +44 -5
- package/es/history/invoice/list.js +3 -1
- package/es/libs/util.d.ts +2 -0
- package/es/libs/util.js +25 -2
- package/es/locales/en.js +2 -1
- package/es/locales/zh.js +2 -1
- package/es/payment/form/currency.d.ts +1 -1
- package/es/payment/form/currency.js +3 -3
- package/es/payment/form/index.d.ts +1 -1
- package/es/payment/form/index.js +22 -36
- package/es/payment/form/stripe/form.js +4 -2
- package/es/payment/index.js +10 -1
- package/es/payment/product-donation.js +4 -3
- package/es/payment/success.d.ts +3 -1
- package/es/payment/success.js +78 -6
- package/lib/checkout/donate.js +19 -11
- package/lib/components/country-select.js +1 -0
- package/lib/components/over-due-invoice-payment.js +42 -3
- package/lib/history/invoice/list.js +1 -0
- package/lib/libs/util.d.ts +2 -0
- package/lib/libs/util.js +27 -2
- package/lib/locales/en.js +2 -1
- package/lib/locales/zh.js +2 -1
- package/lib/payment/form/currency.d.ts +1 -1
- package/lib/payment/form/currency.js +3 -3
- package/lib/payment/form/index.d.ts +1 -1
- package/lib/payment/form/index.js +21 -35
- package/lib/payment/form/stripe/form.js +4 -2
- package/lib/payment/index.js +10 -1
- package/lib/payment/product-donation.js +4 -3
- package/lib/payment/success.d.ts +3 -1
- package/lib/payment/success.js +68 -15
- package/package.json +8 -8
- package/src/checkout/donate.tsx +23 -5
- package/src/components/country-select.tsx +1 -0
- package/src/components/over-due-invoice-payment.tsx +47 -4
- package/src/history/invoice/list.tsx +2 -0
- package/src/libs/util.ts +28 -2
- package/src/locales/en.tsx +1 -0
- package/src/locales/zh.tsx +1 -0
- package/src/payment/form/currency.tsx +4 -4
- package/src/payment/form/index.tsx +23 -47
- package/src/payment/form/stripe/form.tsx +4 -2
- package/src/payment/index.tsx +12 -1
- package/src/payment/product-donation.tsx +4 -3
- package/src/payment/success.tsx +73 -11
- package/src/payment/summary.tsx +1 -0
package/lib/payment/success.js
CHANGED
|
@@ -9,6 +9,7 @@ var _context = require("@arcblock/ux/lib/Locale/context");
|
|
|
9
9
|
var _material = require("@mui/material");
|
|
10
10
|
var _system = require("@mui/system");
|
|
11
11
|
var _ufo = require("ufo");
|
|
12
|
+
var _ux = require("@arcblock/ux");
|
|
12
13
|
var _payment = require("../contexts/payment");
|
|
13
14
|
function PaymentSuccess({
|
|
14
15
|
mode,
|
|
@@ -16,7 +17,8 @@ function PaymentSuccess({
|
|
|
16
17
|
action,
|
|
17
18
|
payee,
|
|
18
19
|
invoiceId,
|
|
19
|
-
subscriptionId
|
|
20
|
+
subscriptionId,
|
|
21
|
+
subscriptions
|
|
20
22
|
}) {
|
|
21
23
|
const {
|
|
22
24
|
t
|
|
@@ -25,19 +27,69 @@ function PaymentSuccess({
|
|
|
25
27
|
prefix
|
|
26
28
|
} = (0, _payment.usePaymentContext)();
|
|
27
29
|
let next = null;
|
|
28
|
-
if (["subscription", "setup"].includes(action)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
if (["subscription", "setup"].includes(action)) {
|
|
31
|
+
if (subscriptions && subscriptions.length > 1) {
|
|
32
|
+
next = /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Paper, {
|
|
33
|
+
elevation: 0,
|
|
34
|
+
sx: {
|
|
35
|
+
p: 3,
|
|
36
|
+
backgroundColor: "grey.50",
|
|
37
|
+
borderRadius: 2,
|
|
38
|
+
width: "100%",
|
|
39
|
+
mt: 2,
|
|
40
|
+
display: "flex",
|
|
41
|
+
flexDirection: "column",
|
|
42
|
+
gap: 2
|
|
43
|
+
},
|
|
44
|
+
children: subscriptions.map(subscription => /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
|
|
45
|
+
sx: {
|
|
46
|
+
display: "flex",
|
|
47
|
+
alignItems: "center",
|
|
48
|
+
justifyContent: "space-between"
|
|
49
|
+
},
|
|
50
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
51
|
+
variant: "body2",
|
|
52
|
+
sx: {
|
|
53
|
+
color: "text.secondary",
|
|
54
|
+
fontWeight: 500
|
|
55
|
+
},
|
|
56
|
+
children: subscription.description
|
|
57
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
58
|
+
sx: {
|
|
59
|
+
flex: 1,
|
|
60
|
+
borderBottom: "1px dashed",
|
|
61
|
+
borderColor: "grey.300",
|
|
62
|
+
mx: 2
|
|
63
|
+
}
|
|
64
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_ux.Button, {
|
|
65
|
+
variant: "text",
|
|
66
|
+
color: "primary",
|
|
67
|
+
size: "small",
|
|
68
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
|
|
69
|
+
href: (0, _ufo.joinURL)(prefix, `/customer/subscription/${subscription.id}`),
|
|
70
|
+
sx: {
|
|
71
|
+
color: "text.secondary"
|
|
72
|
+
},
|
|
73
|
+
children: t("payment.checkout.next.view")
|
|
74
|
+
})
|
|
75
|
+
})]
|
|
76
|
+
}, subscription.id))
|
|
77
|
+
});
|
|
78
|
+
} else if (subscriptionId) {
|
|
79
|
+
next = /* @__PURE__ */(0, _jsxRuntime.jsx)(_ux.Button, {
|
|
80
|
+
variant: "outlined",
|
|
81
|
+
color: "primary",
|
|
82
|
+
sx: {
|
|
83
|
+
mt: 2
|
|
84
|
+
},
|
|
85
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
|
|
86
|
+
href: (0, _ufo.joinURL)(prefix, `/customer/subscription/${subscriptionId}`),
|
|
87
|
+
children: t("payment.checkout.next.subscription", {
|
|
88
|
+
payee
|
|
89
|
+
})
|
|
38
90
|
})
|
|
39
|
-
})
|
|
40
|
-
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
41
93
|
} else if (invoiceId) {
|
|
42
94
|
next = /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
43
95
|
textAlign: "center",
|
|
@@ -59,7 +111,7 @@ function PaymentSuccess({
|
|
|
59
111
|
alignItems: "center",
|
|
60
112
|
justifyContent: mode === "standalone" ? "center" : "flex-start",
|
|
61
113
|
sx: {
|
|
62
|
-
height: mode === "standalone" ?
|
|
114
|
+
height: mode === "standalone" ? "fit-content" : 300
|
|
63
115
|
},
|
|
64
116
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(Div, {
|
|
65
117
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)("div", {
|
|
@@ -95,7 +147,8 @@ function PaymentSuccess({
|
|
|
95
147
|
}
|
|
96
148
|
PaymentSuccess.defaultProps = {
|
|
97
149
|
invoiceId: "",
|
|
98
|
-
subscriptionId: ""
|
|
150
|
+
subscriptionId: "",
|
|
151
|
+
subscriptions: []
|
|
99
152
|
};
|
|
100
153
|
const Div = (0, _system.styled)("div")`
|
|
101
154
|
width: 80px;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.31",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -54,15 +54,15 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@arcblock/did-connect": "^2.
|
|
58
|
-
"@arcblock/ux": "^2.
|
|
59
|
-
"@arcblock/ws": "^1.
|
|
60
|
-
"@blocklet/ui-react": "^2.
|
|
57
|
+
"@arcblock/did-connect": "^2.13.5",
|
|
58
|
+
"@arcblock/ux": "^2.13.5",
|
|
59
|
+
"@arcblock/ws": "^1.20.1",
|
|
60
|
+
"@blocklet/ui-react": "^2.13.5",
|
|
61
61
|
"@mui/icons-material": "^5.16.6",
|
|
62
62
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
63
63
|
"@mui/material": "^5.16.6",
|
|
64
64
|
"@mui/system": "^5.16.6",
|
|
65
|
-
"@ocap/util": "^1.
|
|
65
|
+
"@ocap/util": "^1.20.1",
|
|
66
66
|
"@stripe/react-stripe-js": "^2.7.3",
|
|
67
67
|
"@stripe/stripe-js": "^2.4.0",
|
|
68
68
|
"@vitejs/plugin-legacy": "^5.4.1",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"@babel/core": "^7.25.2",
|
|
94
94
|
"@babel/preset-env": "^7.25.2",
|
|
95
95
|
"@babel/preset-react": "^7.24.7",
|
|
96
|
-
"@blocklet/payment-types": "1.18.
|
|
96
|
+
"@blocklet/payment-types": "1.18.31",
|
|
97
97
|
"@storybook/addon-essentials": "^7.6.20",
|
|
98
98
|
"@storybook/addon-interactions": "^7.6.20",
|
|
99
99
|
"@storybook/addon-links": "^7.6.20",
|
|
@@ -124,5 +124,5 @@
|
|
|
124
124
|
"vite-plugin-babel": "^1.2.0",
|
|
125
125
|
"vite-plugin-node-polyfills": "^0.21.0"
|
|
126
126
|
},
|
|
127
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "c9b1eff248ecd07bc1f606df039464dafa786914"
|
|
128
128
|
}
|
package/src/checkout/donate.tsx
CHANGED
|
@@ -368,7 +368,17 @@ function SupporterSimple({ supporters = [], totalAmount = '0', currency, method
|
|
|
368
368
|
})
|
|
369
369
|
)}
|
|
370
370
|
</Typography>
|
|
371
|
-
<AvatarGroup
|
|
371
|
+
<AvatarGroup
|
|
372
|
+
total={customersNum}
|
|
373
|
+
max={10}
|
|
374
|
+
spacing={4}
|
|
375
|
+
sx={{
|
|
376
|
+
'& .MuiAvatar-root': {
|
|
377
|
+
width: 24,
|
|
378
|
+
height: 24,
|
|
379
|
+
fontSize: '0.6rem',
|
|
380
|
+
},
|
|
381
|
+
}}>
|
|
372
382
|
{customers.map((x) => (
|
|
373
383
|
<Avatar
|
|
374
384
|
key={x.id}
|
|
@@ -376,7 +386,6 @@ function SupporterSimple({ supporters = [], totalAmount = '0', currency, method
|
|
|
376
386
|
alt={x.customer?.metadata?.anonymous ? '' : x.customer?.name}
|
|
377
387
|
src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 48)}
|
|
378
388
|
variant="circular"
|
|
379
|
-
sx={{ width: 24, height: 24 }}
|
|
380
389
|
/>
|
|
381
390
|
))}
|
|
382
391
|
</AvatarGroup>
|
|
@@ -708,7 +717,17 @@ function CheckoutDonateInner({
|
|
|
708
717
|
toolbar={
|
|
709
718
|
isMobile ? null : (
|
|
710
719
|
<Box display="flex" alignItems="center" gap={1} sx={{ color: 'text.secondary' }}>
|
|
711
|
-
<AvatarGroup
|
|
720
|
+
<AvatarGroup
|
|
721
|
+
total={customers?.length}
|
|
722
|
+
max={5}
|
|
723
|
+
spacing={4}
|
|
724
|
+
sx={{
|
|
725
|
+
'& .MuiAvatar-root': {
|
|
726
|
+
width: 18,
|
|
727
|
+
height: 18,
|
|
728
|
+
fontSize: '0.6rem',
|
|
729
|
+
},
|
|
730
|
+
}}>
|
|
712
731
|
{customers.map((x: any) => (
|
|
713
732
|
<Avatar
|
|
714
733
|
key={x.id}
|
|
@@ -716,10 +735,9 @@ function CheckoutDonateInner({
|
|
|
716
735
|
src={getCustomerAvatar(
|
|
717
736
|
x.customer?.did,
|
|
718
737
|
x?.updated_at ? new Date(x.updated_at).toISOString() : '',
|
|
719
|
-
|
|
738
|
+
24
|
|
720
739
|
)}
|
|
721
740
|
variant="circular"
|
|
722
|
-
sx={{ width: 18, height: 18 }}
|
|
723
741
|
/>
|
|
724
742
|
))}
|
|
725
743
|
</AvatarGroup>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/indent */
|
|
2
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Button, Typography, Stack, Alert, SxProps } from '@mui/material';
|
|
4
4
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
5
5
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
@@ -13,11 +13,12 @@ import type {
|
|
|
13
13
|
TInvoiceExpanded,
|
|
14
14
|
} from '@blocklet/payment-types';
|
|
15
15
|
import { useRequest } from 'ahooks';
|
|
16
|
+
import pWaitFor from 'p-wait-for';
|
|
16
17
|
import { Dialog } from '@arcblock/ux';
|
|
17
18
|
import { CheckCircle as CheckCircleIcon } from '@mui/icons-material';
|
|
18
19
|
import debounce from 'lodash/debounce';
|
|
19
20
|
import { usePaymentContext } from '../contexts/payment';
|
|
20
|
-
import { formatAmount, formatError, getPrefix } from '../libs/util';
|
|
21
|
+
import { formatAmount, formatError, getPrefix, isCrossOrigin } from '../libs/util';
|
|
21
22
|
import { useSubscription } from '../hooks/subscription';
|
|
22
23
|
import api from '../libs/api';
|
|
23
24
|
import LoadingButton from './loading-button';
|
|
@@ -113,6 +114,7 @@ function OverdueInvoicePayment({
|
|
|
113
114
|
const sourceType = subscriptionId ? 'subscription' : 'customer';
|
|
114
115
|
const effectiveCustomerId = customerId || session?.user?.did;
|
|
115
116
|
const sourceId = subscriptionId || effectiveCustomerId;
|
|
117
|
+
const customerIdRef = useRef(effectiveCustomerId);
|
|
116
118
|
const {
|
|
117
119
|
data = {
|
|
118
120
|
summary: {},
|
|
@@ -123,6 +125,11 @@ function OverdueInvoicePayment({
|
|
|
123
125
|
runAsync: refresh,
|
|
124
126
|
} = useRequest(() => fetchOverdueInvoices({ subscriptionId, customerId: effectiveCustomerId, authToken }), {
|
|
125
127
|
ready: !!subscriptionId || !!effectiveCustomerId,
|
|
128
|
+
onSuccess: (res) => {
|
|
129
|
+
if (res.customer?.id && res.customer?.id !== customerIdRef.current) {
|
|
130
|
+
customerIdRef.current = res.customer?.id;
|
|
131
|
+
}
|
|
132
|
+
},
|
|
126
133
|
});
|
|
127
134
|
|
|
128
135
|
const detailUrl = useMemo(() => {
|
|
@@ -163,16 +170,50 @@ function OverdueInvoicePayment({
|
|
|
163
170
|
}
|
|
164
171
|
);
|
|
165
172
|
|
|
173
|
+
const isCrossOriginRequest = isCrossOrigin();
|
|
174
|
+
|
|
166
175
|
const subscription = useSubscription('events');
|
|
176
|
+
const waitForInvoiceAllPaid = async () => {
|
|
177
|
+
let isPaid = false;
|
|
178
|
+
await pWaitFor(
|
|
179
|
+
async () => {
|
|
180
|
+
const res = await refresh();
|
|
181
|
+
isPaid = res.invoices?.length === 0;
|
|
182
|
+
return isPaid;
|
|
183
|
+
},
|
|
184
|
+
{ interval: 2000, timeout: 3 * 60 * 1000 }
|
|
185
|
+
);
|
|
186
|
+
return isPaid;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const handleConnected = async () => {
|
|
190
|
+
if (isCrossOriginRequest) {
|
|
191
|
+
try {
|
|
192
|
+
const paid = await waitForInvoiceAllPaid();
|
|
193
|
+
if (successToast) {
|
|
194
|
+
Toast.close();
|
|
195
|
+
Toast.success(t('payment.customer.invoice.paySuccess'));
|
|
196
|
+
}
|
|
197
|
+
if (paid) {
|
|
198
|
+
setDialogOpen(false);
|
|
199
|
+
onPaid(sourceId as string, selectCurrencyId, sourceType as 'subscription' | 'customer');
|
|
200
|
+
}
|
|
201
|
+
} catch (err) {
|
|
202
|
+
console.error('Check payment status failed:', err);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
167
207
|
useEffect(() => {
|
|
168
|
-
if (subscription) {
|
|
208
|
+
if (subscription && !isCrossOriginRequest) {
|
|
169
209
|
subscription.on('invoice.paid', ({ response }: { response: TInvoiceExpanded }) => {
|
|
170
210
|
const relevantId = subscriptionId || response.customer_id;
|
|
171
211
|
const uniqueKey = `${relevantId}-${response.currency_id}`;
|
|
172
212
|
|
|
173
213
|
if (
|
|
174
214
|
(subscriptionId && response.subscription_id === subscriptionId) ||
|
|
175
|
-
(effectiveCustomerId &&
|
|
215
|
+
(effectiveCustomerId && effectiveCustomerId === response.customer_id) ||
|
|
216
|
+
(customerIdRef.current && customerIdRef.current === response.customer_id)
|
|
176
217
|
) {
|
|
177
218
|
if (!processedCurrencies[uniqueKey]) {
|
|
178
219
|
setProcessedCurrencies((prev) => ({ ...prev, [uniqueKey]: 1 }));
|
|
@@ -214,9 +255,11 @@ function OverdueInvoicePayment({
|
|
|
214
255
|
saveConnect: false,
|
|
215
256
|
action: 'collect-batch',
|
|
216
257
|
prefix: joinURL(getPrefix(), '/api/did'),
|
|
258
|
+
useSocket: !isCrossOriginRequest,
|
|
217
259
|
extraParams,
|
|
218
260
|
onSuccess: () => {
|
|
219
261
|
connect.close();
|
|
262
|
+
handleConnected();
|
|
220
263
|
setPayLoading(false);
|
|
221
264
|
setPaymentStatus((prev) => ({
|
|
222
265
|
...prev,
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
getInvoiceDescriptionAndReason,
|
|
29
29
|
getInvoiceStatusColor,
|
|
30
30
|
getTxLink,
|
|
31
|
+
isCrossOrigin,
|
|
31
32
|
} from '../../libs/util';
|
|
32
33
|
import Table from '../../components/table';
|
|
33
34
|
import { createLink, handleNavigation, LinkInfo } from '../../libs/navigation';
|
|
@@ -617,6 +618,7 @@ export default function CustomerInvoiceList(props: Props) {
|
|
|
617
618
|
connect.open({
|
|
618
619
|
action: 'collect',
|
|
619
620
|
saveConnect: false,
|
|
621
|
+
useSocket: isCrossOrigin() === false,
|
|
620
622
|
messages: {
|
|
621
623
|
scan: '',
|
|
622
624
|
title: t(`payment.customer.invoice.${action || 'pay'}`),
|
package/src/libs/util.ts
CHANGED
|
@@ -61,6 +61,17 @@ export const getPrefix = (): string => {
|
|
|
61
61
|
return joinURL(baseUrl, prefix);
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
+
export function isCrossOrigin() {
|
|
65
|
+
try {
|
|
66
|
+
const prefix = getPrefix();
|
|
67
|
+
const prefixOrigin = new URL(prefix).origin;
|
|
68
|
+
const currentOrigin = window.location.origin;
|
|
69
|
+
return prefixOrigin !== currentOrigin;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
64
75
|
export function formatToDate(date: Date | string | number, locale = 'en', format = 'YYYY-MM-DD HH:mm:ss') {
|
|
65
76
|
if (!date) {
|
|
66
77
|
return '-';
|
|
@@ -586,6 +597,19 @@ export function formatPriceDisplay(
|
|
|
586
597
|
return [amount, then].filter(Boolean).join(' ');
|
|
587
598
|
}
|
|
588
599
|
|
|
600
|
+
export function hasMultipleRecurringIntervals(items: TLineItemExpanded[]): boolean {
|
|
601
|
+
const intervals = new Set<string>();
|
|
602
|
+
for (const item of items) {
|
|
603
|
+
if (item.price?.recurring?.interval && item.price?.type === 'recurring') {
|
|
604
|
+
intervals.add(`${item.price.recurring.interval}-${item.price.recurring.interval_count}`);
|
|
605
|
+
if (intervals.size > 1) {
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
|
|
589
613
|
export function getFreeTrialTime(
|
|
590
614
|
{ trialInDays, trialEnd }: { trialInDays: number; trialEnd: number },
|
|
591
615
|
locale: string = 'en'
|
|
@@ -674,8 +698,10 @@ export function formatCheckoutHeadlines(
|
|
|
674
698
|
locale
|
|
675
699
|
);
|
|
676
700
|
const hasMetered = items.some((x) => x.price.type === 'recurring' && x.price.recurring?.usage_type === 'metered');
|
|
701
|
+
const differentRecurring = hasMultipleRecurringIntervals(items);
|
|
677
702
|
// all recurring
|
|
678
703
|
if (items.every((x) => x.price.type === 'recurring')) {
|
|
704
|
+
// check if there has different recurring price
|
|
679
705
|
const subscription = [
|
|
680
706
|
hasMetered ? t('payment.checkout.least', locale) : '',
|
|
681
707
|
fromUnitToToken(
|
|
@@ -738,7 +764,7 @@ export function formatCheckoutHeadlines(
|
|
|
738
764
|
action: t('payment.checkout.sub1', locale, { name }),
|
|
739
765
|
amount,
|
|
740
766
|
then: hasMetered ? t('payment.checkout.meteredThen', locale, { recurring }) : recurring,
|
|
741
|
-
showThen: hasMetered,
|
|
767
|
+
showThen: hasMetered && !differentRecurring,
|
|
742
768
|
actualAmount,
|
|
743
769
|
};
|
|
744
770
|
return {
|
|
@@ -769,7 +795,7 @@ export function formatCheckoutHeadlines(
|
|
|
769
795
|
hasMetered && Number(subscription) === 0,
|
|
770
796
|
locale
|
|
771
797
|
),
|
|
772
|
-
showThen:
|
|
798
|
+
showThen: !differentRecurring,
|
|
773
799
|
actualAmount,
|
|
774
800
|
};
|
|
775
801
|
|
package/src/locales/en.tsx
CHANGED
package/src/locales/zh.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { Avatar, Card, Radio, Stack, Typography } from '@mui/material';
|
|
|
3
3
|
import { styled } from '@mui/system';
|
|
4
4
|
|
|
5
5
|
type Props = {
|
|
6
|
-
value:
|
|
6
|
+
value: string;
|
|
7
7
|
currencies: TPaymentCurrency[];
|
|
8
8
|
onChange: Function;
|
|
9
9
|
};
|
|
@@ -18,13 +18,13 @@ export default function CurrencySelector({ value, currencies, onChange }: Props)
|
|
|
18
18
|
gap: 12,
|
|
19
19
|
gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
|
|
20
20
|
}}>
|
|
21
|
-
{currencies.map((x
|
|
22
|
-
const selected =
|
|
21
|
+
{currencies.map((x) => {
|
|
22
|
+
const selected = x.id === value;
|
|
23
23
|
return (
|
|
24
24
|
<Card
|
|
25
25
|
key={x.id}
|
|
26
26
|
variant="outlined"
|
|
27
|
-
onClick={() => onChange(
|
|
27
|
+
onClick={() => onChange(x.id, (x as any).method?.id)}
|
|
28
28
|
className={selected ? 'cko-payment-card' : 'cko-payment-card-unselect'}>
|
|
29
29
|
<Stack direction="row" alignItems="center" sx={{ position: 'relative' }}>
|
|
30
30
|
<Avatar src={x.logo} alt={x.name} sx={{ width: 40, height: 40, marginRight: '12px' }} />
|
|
@@ -4,17 +4,11 @@ import 'react-international-phone/style.css';
|
|
|
4
4
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
5
5
|
// import { useTheme } from '@arcblock/ux/lib/Theme';
|
|
6
6
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
7
|
-
import type {
|
|
8
|
-
TCheckoutSession,
|
|
9
|
-
TCustomer,
|
|
10
|
-
TInvoice,
|
|
11
|
-
TPaymentIntent,
|
|
12
|
-
TPaymentMethodExpanded,
|
|
13
|
-
} from '@blocklet/payment-types';
|
|
7
|
+
import type { TCheckoutSession, TCustomer, TPaymentIntent, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
14
8
|
import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Typography } from '@mui/material';
|
|
15
9
|
import { useMemoizedFn, useSetState } from 'ahooks';
|
|
16
10
|
import pWaitFor from 'p-wait-for';
|
|
17
|
-
import { useEffect, useMemo, useRef
|
|
11
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
18
12
|
import { Controller, useFormContext, useWatch } from 'react-hook-form';
|
|
19
13
|
import { joinURL } from 'ufo';
|
|
20
14
|
import { dispatch } from 'use-bus';
|
|
@@ -30,8 +24,8 @@ import {
|
|
|
30
24
|
formatError,
|
|
31
25
|
formatQuantityInventory,
|
|
32
26
|
getPrefix,
|
|
33
|
-
getQueryParams,
|
|
34
27
|
getStatementDescriptor,
|
|
28
|
+
isCrossOrigin,
|
|
35
29
|
} from '../../libs/util';
|
|
36
30
|
import type { CheckoutCallbacks, CheckoutContext } from '../../types';
|
|
37
31
|
import AddressForm from './address';
|
|
@@ -161,7 +155,6 @@ export default function PaymentForm({
|
|
|
161
155
|
onError,
|
|
162
156
|
// mode,
|
|
163
157
|
action,
|
|
164
|
-
currencyId,
|
|
165
158
|
onlyShowBtn,
|
|
166
159
|
isDonation = false,
|
|
167
160
|
}: PageData) {
|
|
@@ -214,37 +207,15 @@ export default function PaymentForm({
|
|
|
214
207
|
|
|
215
208
|
const currencies = flattenPaymentMethods(paymentMethods);
|
|
216
209
|
|
|
217
|
-
const [paymentCurrencyIndex, setPaymentCurrencyIndex] = useState(() => {
|
|
218
|
-
const query = getQueryParams(window.location.href);
|
|
219
|
-
const queryCurrencyId = query.currencyId || currencyId;
|
|
220
|
-
const index = currencies.findIndex((x) => x.id === queryCurrencyId);
|
|
221
|
-
return index >= 0 ? index : 0;
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const handleCurrencyChange = (index: number) => {
|
|
225
|
-
setPaymentCurrencyIndex(index);
|
|
226
|
-
const selectedCurrencyId = currencies[index]?.id;
|
|
227
|
-
if (selectedCurrencyId) {
|
|
228
|
-
saveCurrencyPreference(selectedCurrencyId, session?.user?.did);
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
|
|
232
210
|
const onCheckoutComplete = useMemoizedFn(async ({ response }: { response: TCheckoutSession }) => {
|
|
233
211
|
if (response.id === checkoutSession.id && state.paid === false) {
|
|
234
212
|
await handleConnected();
|
|
235
213
|
}
|
|
236
214
|
});
|
|
237
215
|
|
|
238
|
-
const onInvoicePaid = useMemoizedFn(async ({ response }: { response: TInvoice }) => {
|
|
239
|
-
if (response.customer_id === customer?.id && state.customerLimited) {
|
|
240
|
-
await onAction();
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
|
|
244
216
|
useEffect(() => {
|
|
245
217
|
if (subscription) {
|
|
246
218
|
subscription.on('checkout.session.completed', onCheckoutComplete);
|
|
247
|
-
subscription.on('invoice.paid', onInvoicePaid);
|
|
248
219
|
}
|
|
249
220
|
}, [subscription]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
250
221
|
|
|
@@ -316,11 +287,6 @@ export default function PaymentForm({
|
|
|
316
287
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
317
288
|
}, [session?.user, checkoutSession.phone_number_collection?.enabled]);
|
|
318
289
|
|
|
319
|
-
useEffect(() => {
|
|
320
|
-
setValue('payment_method', (currencies[paymentCurrencyIndex] as any)?.method?.id);
|
|
321
|
-
setValue('payment_currency', currencies[paymentCurrencyIndex]?.id);
|
|
322
|
-
}, [paymentCurrencyIndex, currencies, setValue]);
|
|
323
|
-
|
|
324
290
|
const paymentMethod = useWatch({ control, name: 'payment_method' });
|
|
325
291
|
|
|
326
292
|
// const domSize = useSize(document.body);
|
|
@@ -426,6 +392,7 @@ export default function PaymentForm({
|
|
|
426
392
|
action: checkoutSession.mode,
|
|
427
393
|
prefix: joinURL(getPrefix(), '/api/did'),
|
|
428
394
|
saveConnect: false,
|
|
395
|
+
useSocket: isCrossOrigin() === false,
|
|
429
396
|
extraParams: { checkoutSessionId: checkoutSession.id, sessionUserDid: session?.user?.did },
|
|
430
397
|
onSuccess: async () => {
|
|
431
398
|
connect.close();
|
|
@@ -440,6 +407,11 @@ export default function PaymentForm({
|
|
|
440
407
|
setState({ submitting: false, paying: false });
|
|
441
408
|
onError(err);
|
|
442
409
|
},
|
|
410
|
+
messages: {
|
|
411
|
+
title: 'DID Connect',
|
|
412
|
+
scan: 'Use following methods to complete this payment',
|
|
413
|
+
confirm: 'Confirm',
|
|
414
|
+
},
|
|
443
415
|
} as any);
|
|
444
416
|
}
|
|
445
417
|
}
|
|
@@ -488,14 +460,14 @@ export default function PaymentForm({
|
|
|
488
460
|
}
|
|
489
461
|
if (hasDidWallet(session.user)) {
|
|
490
462
|
handleSubmit(onFormSubmit, onFormError)();
|
|
491
|
-
|
|
492
|
-
session.bindWallet(() => {
|
|
493
|
-
// timeout required because https://github.com/ArcBlock/ux/issues/1241
|
|
494
|
-
setTimeout(() => {
|
|
495
|
-
handleSubmit(onFormSubmit, onFormError)();
|
|
496
|
-
}, 2000);
|
|
497
|
-
});
|
|
463
|
+
return;
|
|
498
464
|
}
|
|
465
|
+
session.bindWallet(() => {
|
|
466
|
+
// timeout required because https://github.com/ArcBlock/ux/issues/1241
|
|
467
|
+
setTimeout(() => {
|
|
468
|
+
handleSubmit(onFormSubmit, onFormError)();
|
|
469
|
+
}, 2000);
|
|
470
|
+
});
|
|
499
471
|
} else {
|
|
500
472
|
if (isDonationMode) {
|
|
501
473
|
handleSubmit(onFormSubmit, onFormError)();
|
|
@@ -620,11 +592,15 @@ export default function PaymentForm({
|
|
|
620
592
|
<Controller
|
|
621
593
|
name="payment_currency"
|
|
622
594
|
control={control}
|
|
623
|
-
render={() => (
|
|
595
|
+
render={({ field }) => (
|
|
624
596
|
<CurrencySelector
|
|
625
|
-
value={
|
|
597
|
+
value={field.value}
|
|
626
598
|
currencies={currencies}
|
|
627
|
-
onChange={
|
|
599
|
+
onChange={(id: string, methodId: string) => {
|
|
600
|
+
field.onChange(id);
|
|
601
|
+
setValue('payment_method', methodId);
|
|
602
|
+
saveCurrencyPreference(id, session?.user?.did);
|
|
603
|
+
}}
|
|
628
604
|
/>
|
|
629
605
|
)}
|
|
630
606
|
/>
|
|
@@ -178,10 +178,12 @@ function StripeCheckoutForm({
|
|
|
178
178
|
|
|
179
179
|
return (
|
|
180
180
|
<Content onSubmit={handleSubmit}>
|
|
181
|
-
{(!state.paymentMethod ||
|
|
181
|
+
{(!state.paymentMethod || ['link', 'card'].includes(state.paymentMethod)) && (
|
|
182
182
|
<LinkAuthenticationElement
|
|
183
183
|
options={{
|
|
184
|
-
|
|
184
|
+
defaultValues: {
|
|
185
|
+
email: customer.email,
|
|
186
|
+
},
|
|
185
187
|
}}
|
|
186
188
|
/>
|
|
187
189
|
)}
|
package/src/payment/index.tsx
CHANGED
|
@@ -142,6 +142,16 @@ function PaymentInner({
|
|
|
142
142
|
},
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
if (defaultCurrencyId) {
|
|
147
|
+
methods.setValue('payment_currency', defaultCurrencyId);
|
|
148
|
+
}
|
|
149
|
+
if (defaultMethodId) {
|
|
150
|
+
methods.setValue('payment_method', defaultMethodId);
|
|
151
|
+
}
|
|
152
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
153
|
+
}, [defaultCurrencyId, defaultMethodId]);
|
|
154
|
+
|
|
145
155
|
useEffect(() => {
|
|
146
156
|
if (!isMobileSafari()) {
|
|
147
157
|
return () => {};
|
|
@@ -258,7 +268,7 @@ function PaymentInner({
|
|
|
258
268
|
// @ts-ignore
|
|
259
269
|
state.checkoutSession.subscription_data?.min_stake_amount || 0
|
|
260
270
|
)}
|
|
261
|
-
showStaking={method.type === 'arcblock'}
|
|
271
|
+
showStaking={method.type === 'arcblock' && !state.checkoutSession.subscription_data?.no_stake}
|
|
262
272
|
currency={currency}
|
|
263
273
|
onUpsell={onUpsell}
|
|
264
274
|
onDownsell={onDownsell}
|
|
@@ -290,6 +300,7 @@ function PaymentInner({
|
|
|
290
300
|
action={state.checkoutSession.mode}
|
|
291
301
|
invoiceId={state.checkoutSession.invoice_id}
|
|
292
302
|
subscriptionId={state.checkoutSession.subscription_id}
|
|
303
|
+
subscriptions={state.checkoutSession.subscriptions}
|
|
293
304
|
message={
|
|
294
305
|
paymentLink?.after_completion?.hosted_confirmation?.custom_message ||
|
|
295
306
|
t(
|
|
@@ -108,9 +108,10 @@ export default function ProductDonation({
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// Get min and max values for random amount
|
|
111
|
-
const minPreset = hasPresets ? sortedPresets[
|
|
112
|
-
|
|
113
|
-
const
|
|
111
|
+
const minPreset = hasPresets ? sortedPresets[sortedPresets.length - 1] : 1;
|
|
112
|
+
let maxPreset = hasPresets ? sortedPresets[sortedPresets.length - 1] * 5 : 100;
|
|
113
|
+
const systemMax = settings.amount.maximum ? parseFloat(settings.amount.maximum) : Infinity;
|
|
114
|
+
maxPreset = Math.min(maxPreset, systemMax);
|
|
114
115
|
|
|
115
116
|
// Detect precision from existing presets
|
|
116
117
|
const detectPrecision = () => {
|