@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.
Files changed (49) hide show
  1. package/es/checkout/donate.js +51 -23
  2. package/es/components/country-select.js +1 -0
  3. package/es/components/over-due-invoice-payment.js +44 -5
  4. package/es/history/invoice/list.js +3 -1
  5. package/es/libs/util.d.ts +2 -0
  6. package/es/libs/util.js +25 -2
  7. package/es/locales/en.js +2 -1
  8. package/es/locales/zh.js +2 -1
  9. package/es/payment/form/currency.d.ts +1 -1
  10. package/es/payment/form/currency.js +3 -3
  11. package/es/payment/form/index.d.ts +1 -1
  12. package/es/payment/form/index.js +22 -36
  13. package/es/payment/form/stripe/form.js +4 -2
  14. package/es/payment/index.js +10 -1
  15. package/es/payment/product-donation.js +4 -3
  16. package/es/payment/success.d.ts +3 -1
  17. package/es/payment/success.js +78 -6
  18. package/lib/checkout/donate.js +19 -11
  19. package/lib/components/country-select.js +1 -0
  20. package/lib/components/over-due-invoice-payment.js +42 -3
  21. package/lib/history/invoice/list.js +1 -0
  22. package/lib/libs/util.d.ts +2 -0
  23. package/lib/libs/util.js +27 -2
  24. package/lib/locales/en.js +2 -1
  25. package/lib/locales/zh.js +2 -1
  26. package/lib/payment/form/currency.d.ts +1 -1
  27. package/lib/payment/form/currency.js +3 -3
  28. package/lib/payment/form/index.d.ts +1 -1
  29. package/lib/payment/form/index.js +21 -35
  30. package/lib/payment/form/stripe/form.js +4 -2
  31. package/lib/payment/index.js +10 -1
  32. package/lib/payment/product-donation.js +4 -3
  33. package/lib/payment/success.d.ts +3 -1
  34. package/lib/payment/success.js +68 -15
  35. package/package.json +8 -8
  36. package/src/checkout/donate.tsx +23 -5
  37. package/src/components/country-select.tsx +1 -0
  38. package/src/components/over-due-invoice-payment.tsx +47 -4
  39. package/src/history/invoice/list.tsx +2 -0
  40. package/src/libs/util.ts +28 -2
  41. package/src/locales/en.tsx +1 -0
  42. package/src/locales/zh.tsx +1 -0
  43. package/src/payment/form/currency.tsx +4 -4
  44. package/src/payment/form/index.tsx +23 -47
  45. package/src/payment/form/stripe/form.tsx +4 -2
  46. package/src/payment/index.tsx +12 -1
  47. package/src/payment/product-donation.tsx +4 -3
  48. package/src/payment/success.tsx +73 -11
  49. package/src/payment/summary.tsx +1 -0
@@ -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) && subscriptionId) {
29
- next = /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
30
- textAlign: "center",
31
- sx: {
32
- mt: 2
33
- },
34
- children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
35
- href: (0, _ufo.joinURL)(prefix, `/customer/subscription/${subscriptionId}`),
36
- children: t("payment.checkout.next.subscription", {
37
- payee
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" ? 360 : 300
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.29",
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.12.70",
58
- "@arcblock/ux": "^2.12.70",
59
- "@arcblock/ws": "^1.19.19",
60
- "@blocklet/ui-react": "^2.12.70",
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.19.19",
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.29",
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": "bb8d03a1da62822cbc2ae57d7c5f2912aaebc0da"
127
+ "gitHead": "c9b1eff248ecd07bc1f606df039464dafa786914"
128
128
  }
@@ -368,7 +368,17 @@ function SupporterSimple({ supporters = [], totalAmount = '0', currency, method
368
368
  })
369
369
  )}
370
370
  </Typography>
371
- <AvatarGroup total={customersNum} max={10}>
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 total={customers?.length} max={5}>
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
- 18
738
+ 24
720
739
  )}
721
740
  variant="circular"
722
- sx={{ width: 18, height: 18 }}
723
741
  />
724
742
  ))}
725
743
  </AvatarGroup>
@@ -230,6 +230,7 @@ const CountrySelect = forwardRef<HTMLDivElement, CountrySelectProps>(({ value, o
230
230
  }}
231
231
  sx={{
232
232
  width: '100%',
233
+ minWidth: '60px',
233
234
  fieldset: {
234
235
  display: 'none',
235
236
  },
@@ -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 && [data.customer?.id, effectiveCustomerId].includes(response.customer_id))
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: true,
798
+ showThen: !differentRecurring,
773
799
  actualAmount,
774
800
  };
775
801
 
@@ -118,6 +118,7 @@ export default flat({
118
118
  next: {
119
119
  subscription: 'View subscription',
120
120
  invoice: 'View invoice',
121
+ view: 'View',
121
122
  },
122
123
  paymentRequired: 'Payment Required',
123
124
  staking: {
@@ -118,6 +118,7 @@ export default flat({
118
118
  next: {
119
119
  subscription: '查看订阅',
120
120
  invoice: '查看账单',
121
+ view: '查看',
121
122
  },
122
123
  paymentRequired: '支付金额',
123
124
  staking: {
@@ -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: number;
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, i) => {
22
- const selected = i === value;
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(i)}
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, useState } from 'react';
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
- } else {
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={paymentCurrencyIndex}
597
+ value={field.value}
626
598
  currencies={currencies}
627
- onChange={handleCurrencyChange}
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 || state.paymentMethod === 'card') && (
181
+ {(!state.paymentMethod || ['link', 'card'].includes(state.paymentMethod)) && (
182
182
  <LinkAuthenticationElement
183
183
  options={{
184
- defaultEmail: customer.email,
184
+ defaultValues: {
185
+ email: customer.email,
186
+ },
185
187
  }}
186
188
  />
187
189
  )}
@@ -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[0] : 1;
112
- const middleIndex = Math.floor(sortedPresets.length / 2);
113
- const maxPreset = hasPresets ? sortedPresets[middleIndex] : 10;
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 = () => {