@blocklet/payment-react 1.18.25 → 1.18.27

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 (59) hide show
  1. package/es/checkout/donate.js +11 -1
  2. package/es/components/country-select.js +243 -21
  3. package/es/components/over-due-invoice-payment.d.ts +3 -1
  4. package/es/components/over-due-invoice-payment.js +6 -4
  5. package/es/contexts/payment.d.ts +2 -1
  6. package/es/contexts/payment.js +8 -1
  7. package/es/index.d.ts +1 -0
  8. package/es/index.js +1 -0
  9. package/es/libs/api.js +4 -0
  10. package/es/libs/currency.d.ts +3 -0
  11. package/es/libs/currency.js +22 -0
  12. package/es/libs/phone-validator.js +2 -0
  13. package/es/libs/validator.d.ts +1 -0
  14. package/es/libs/validator.js +70 -0
  15. package/es/payment/form/address.js +17 -3
  16. package/es/payment/form/index.js +10 -1
  17. package/es/payment/form/phone.js +12 -1
  18. package/es/payment/form/stripe/form.js +14 -5
  19. package/es/payment/index.js +33 -11
  20. package/es/payment/product-donation.js +110 -12
  21. package/es/types/shims.d.ts +2 -0
  22. package/lib/checkout/donate.js +11 -1
  23. package/lib/components/country-select.js +243 -39
  24. package/lib/components/over-due-invoice-payment.d.ts +3 -1
  25. package/lib/components/over-due-invoice-payment.js +7 -4
  26. package/lib/contexts/payment.d.ts +2 -1
  27. package/lib/contexts/payment.js +9 -1
  28. package/lib/index.d.ts +1 -0
  29. package/lib/index.js +12 -0
  30. package/lib/libs/api.js +4 -0
  31. package/lib/libs/currency.d.ts +3 -0
  32. package/lib/libs/currency.js +31 -0
  33. package/lib/libs/phone-validator.js +1 -0
  34. package/lib/libs/validator.d.ts +1 -0
  35. package/lib/libs/validator.js +20 -0
  36. package/lib/payment/form/address.js +15 -2
  37. package/lib/payment/form/index.js +12 -1
  38. package/lib/payment/form/phone.js +13 -1
  39. package/lib/payment/form/stripe/form.js +21 -5
  40. package/lib/payment/index.js +34 -10
  41. package/lib/payment/product-donation.js +106 -15
  42. package/lib/types/shims.d.ts +2 -0
  43. package/package.json +8 -8
  44. package/src/checkout/donate.tsx +11 -1
  45. package/src/components/country-select.tsx +265 -20
  46. package/src/components/over-due-invoice-payment.tsx +6 -2
  47. package/src/contexts/payment.tsx +11 -1
  48. package/src/index.ts +1 -0
  49. package/src/libs/api.ts +4 -1
  50. package/src/libs/currency.ts +25 -0
  51. package/src/libs/phone-validator.ts +1 -0
  52. package/src/libs/validator.ts +70 -0
  53. package/src/payment/form/address.tsx +17 -4
  54. package/src/payment/form/index.tsx +11 -1
  55. package/src/payment/form/phone.tsx +15 -1
  56. package/src/payment/form/stripe/form.tsx +20 -9
  57. package/src/payment/index.tsx +45 -14
  58. package/src/payment/product-donation.tsx +129 -10
  59. package/src/types/shims.d.ts +2 -0
@@ -48,7 +48,8 @@ function StripeCheckoutForm({
48
48
  confirming: false,
49
49
  loaded: false,
50
50
  showBillingForm: false,
51
- isTransitioning: false
51
+ isTransitioning: false,
52
+ paymentMethod: "card"
52
53
  });
53
54
  const handlePaymentMethodChange = event => {
54
55
  const method = event.value?.type;
@@ -61,12 +62,14 @@ function StripeCheckoutForm({
61
62
  setTimeout(() => {
62
63
  setState({
63
64
  isTransitioning: false,
65
+ paymentMethod: method,
64
66
  showBillingForm: true
65
67
  });
66
68
  }, 300);
67
69
  } else {
68
70
  setState({
69
71
  showBillingForm: false,
72
+ paymentMethod: method,
70
73
  isTransitioning: false
71
74
  });
72
75
  }
@@ -111,17 +114,23 @@ function StripeCheckoutForm({
111
114
  }
112
115
  try {
113
116
  setState({
114
- confirming: true
117
+ confirming: true,
118
+ message: ""
115
119
  });
116
120
  const method = intentType === "payment_intent" ? "confirmPayment" : "confirmSetup";
117
121
  const {
118
122
  error: submitError
119
123
  } = await elements.submit();
120
124
  if (submitError) {
125
+ setState({
126
+ confirming: false
127
+ });
121
128
  return;
122
129
  }
123
130
  const {
124
- error
131
+ error,
132
+ paymentIntent,
133
+ setupIntent
125
134
  } = await stripe[method]({
126
135
  elements,
127
136
  redirect: "if_required",
@@ -147,6 +156,13 @@ function StripeCheckoutForm({
147
156
  } : {})
148
157
  }
149
158
  });
159
+ const intent = paymentIntent || setupIntent;
160
+ if (intent?.status === "canceled" || intent?.status === "requires_payment_method") {
161
+ setState({
162
+ confirming: false
163
+ });
164
+ return;
165
+ }
150
166
  setState({
151
167
  confirming: false
152
168
  });
@@ -167,13 +183,13 @@ function StripeCheckoutForm({
167
183
  message: err.message
168
184
  });
169
185
  }
170
- }, [customer, intentType, stripe]
186
+ }, [customer, intentType, stripe, state.showBillingForm, returnUrl]
171
187
  // eslint-disable-line
172
188
  );
173
189
 
174
190
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(Content, {
175
191
  onSubmit: handleSubmit,
176
- children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(LinkAuthenticationElement, {
192
+ children: [(!state.paymentMethod || state.paymentMethod === "card") && /* @__PURE__ */(0, _jsxRuntime.jsx)(LinkAuthenticationElement, {
177
193
  options: {
178
194
  defaultEmail: customer.email
179
195
  }
@@ -22,13 +22,16 @@ var _api = _interopRequireDefault(require("../libs/api"));
22
22
  var _util2 = require("../libs/util");
23
23
  var _error = _interopRequireDefault(require("./error"));
24
24
  var _footer = _interopRequireDefault(require("./footer"));
25
- var _form = _interopRequireDefault(require("./form"));
25
+ var _form = _interopRequireWildcard(require("./form"));
26
26
  var _overview = _interopRequireDefault(require("./skeleton/overview"));
27
27
  var _payment2 = _interopRequireDefault(require("./skeleton/payment"));
28
28
  var _success = _interopRequireDefault(require("./success"));
29
29
  var _summary = _interopRequireDefault(require("./summary"));
30
30
  var _mobile = require("../hooks/mobile");
31
31
  var _phoneValidator = require("../libs/phone-validator");
32
+ var _currency = require("../libs/currency");
33
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
34
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
32
35
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
36
  PaymentInner.defaultProps = {
34
37
  completed: false,
@@ -62,7 +65,36 @@ function PaymentInner({
62
65
  checkoutSession
63
66
  });
64
67
  const query = (0, _util2.getQueryParams)(window.location.href);
65
- const defaultCurrencyId = query.currencyId || state.checkoutSession.currency_id || state.checkoutSession.line_items[0]?.price.currency_id;
68
+ const availableCurrencyIds = (0, _react.useMemo)(() => {
69
+ const currencyIds = /* @__PURE__ */new Set();
70
+ paymentMethods.forEach(method2 => {
71
+ method2.payment_currencies.forEach(currency2 => {
72
+ if (currency2.active) {
73
+ currencyIds.add(currency2.id);
74
+ }
75
+ });
76
+ });
77
+ return Array.from(currencyIds);
78
+ }, [paymentMethods]);
79
+ const defaultCurrencyId = (0, _react.useMemo)(() => {
80
+ if (query.currencyId && availableCurrencyIds.includes(query.currencyId)) {
81
+ return query.currencyId;
82
+ }
83
+ if (session?.user && !(0, _form.hasDidWallet)(session.user)) {
84
+ const stripeCurrencyId = paymentMethods.find(m => m.type === "stripe")?.payment_currencies.find(c => c.active)?.id;
85
+ if (stripeCurrencyId) {
86
+ return stripeCurrencyId;
87
+ }
88
+ }
89
+ const savedPreference = (0, _currency.getCurrencyPreference)(session?.user?.did, availableCurrencyIds);
90
+ if (savedPreference) {
91
+ return savedPreference;
92
+ }
93
+ if (state.checkoutSession.currency_id && availableCurrencyIds.includes(state.checkoutSession.currency_id)) {
94
+ return state.checkoutSession.currency_id;
95
+ }
96
+ return availableCurrencyIds?.[0];
97
+ }, [query.currencyId, availableCurrencyIds, session?.user, state.checkoutSession.currency_id, paymentMethods]);
66
98
  const defaultMethodId = paymentMethods.find(m => m.payment_currencies.some(c => c.id === defaultCurrencyId))?.id;
67
99
  const hideSummaryCard = mode.endsWith("-minimal") || !showCheckoutSummary;
68
100
  const methods = (0, _reactHookForm.useForm)({
@@ -102,14 +134,6 @@ function PaymentInner({
102
134
  document.body.removeEventListener("focusout", focusoutHandler);
103
135
  };
104
136
  }, []);
105
- (0, _react.useEffect)(() => {
106
- if (!methods || query.currencyId) {
107
- return;
108
- }
109
- if (state.checkoutSession.currency_id !== defaultCurrencyId) {
110
- methods.setValue("payment_currency", state.checkoutSession.currency_id);
111
- }
112
- }, [state.checkoutSession, defaultCurrencyId, query.currencyId]);
113
137
  const currencyId = (0, _reactHookForm.useWatch)({
114
138
  control: methods.control,
115
139
  name: "payment_currency",
@@ -7,12 +7,14 @@ module.exports = ProductDonation;
7
7
  var _jsxRuntime = require("react/jsx-runtime");
8
8
  var _context = require("@arcblock/ux/lib/Locale/context");
9
9
  var _material = require("@mui/material");
10
+ var _AutoAwesome = _interopRequireDefault(require("@mui/icons-material/AutoAwesome"));
10
11
  var _ahooks = require("ahooks");
11
12
  var _react = require("react");
12
13
  var _util = require("../libs/util");
13
14
  var _payment = require("../contexts/payment");
14
15
  var _scroll = require("../hooks/scroll");
15
16
  var _keyboard = require("../hooks/keyboard");
17
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
18
  const DONATION_PRESET_KEY_BASE = "payment-donation-preset";
17
19
  const DONATION_CUSTOM_AMOUNT_KEY_BASE = "payment-donation-custom-amount";
18
20
  const formatAmount = amount => {
@@ -74,7 +76,8 @@ function ProductDonation({
74
76
  selected: defaultPreset === "custom" ? "" : defaultPreset,
75
77
  input: defaultCustomAmount,
76
78
  custom: !supportPreset || defaultPreset === "custom",
77
- error: ""
79
+ error: "",
80
+ animating: false
78
81
  });
79
82
  const customInputRef = (0, _react.useRef)(null);
80
83
  const containerRef = (0, _react.useRef)(null);
@@ -95,21 +98,73 @@ function ProductDonation({
95
98
  setState({
96
99
  custom: true,
97
100
  selected: "",
98
- error: ""
101
+ animating: true
99
102
  });
100
- const savedCustomAmount = getSavedCustomAmount();
101
- if (savedCustomAmount) {
102
- setState({
103
- input: savedCustomAmount
103
+ const hasPresets = presets.length > 0;
104
+ let sortedPresets = [];
105
+ if (hasPresets) {
106
+ sortedPresets = [...presets].map(p => parseFloat(p)).sort((a, b) => a - b);
107
+ }
108
+ const minPreset = hasPresets ? sortedPresets[0] : 1;
109
+ const middleIndex = Math.floor(sortedPresets.length / 2);
110
+ const maxPreset = hasPresets ? sortedPresets[middleIndex] : 10;
111
+ const detectPrecision = () => {
112
+ let maxPrecision = 2;
113
+ if (!hasPresets) return 0;
114
+ const allIntegers = presets.every(preset => {
115
+ const num = parseFloat(preset);
116
+ return num === Math.floor(num);
104
117
  });
105
- onChange({
106
- priceId: item.price_id,
107
- amount: savedCustomAmount
118
+ if (allIntegers) return 0;
119
+ presets.forEach(preset => {
120
+ const decimalPart = preset.toString().split(".")[1];
121
+ if (decimalPart) {
122
+ maxPrecision = Math.max(maxPrecision, decimalPart.length);
123
+ }
108
124
  });
109
- setPayable(true);
110
- } else if (!state.input) {
111
- setPayable(false);
125
+ return maxPrecision;
126
+ };
127
+ const precision = detectPrecision();
128
+ let randomAmount;
129
+ if (precision === 0) {
130
+ randomAmount = (Math.round(Math.random() * (maxPreset - minPreset) + minPreset) || 1).toString();
131
+ } else {
132
+ randomAmount = (Math.random() * (maxPreset - minPreset) + minPreset).toFixed(precision);
112
133
  }
134
+ const startValue = state.input ? parseFloat(state.input) : 0;
135
+ const targetValue = parseFloat(randomAmount);
136
+ const difference = targetValue - startValue;
137
+ const startTime = Date.now();
138
+ const duration = 800;
139
+ const updateCounter = () => {
140
+ const currentTime = Date.now();
141
+ const elapsed = currentTime - startTime;
142
+ if (elapsed < duration) {
143
+ const progress = elapsed / duration;
144
+ const intermediateValue = startValue + difference * progress;
145
+ const currentValue = precision === 0 ? Math.floor(intermediateValue).toString() : intermediateValue.toFixed(precision);
146
+ setState({
147
+ input: currentValue
148
+ });
149
+ requestAnimationFrame(updateCounter);
150
+ } else {
151
+ setState({
152
+ input: randomAmount,
153
+ animating: false,
154
+ error: ""
155
+ });
156
+ onChange({
157
+ priceId: item.price_id,
158
+ amount: formatAmount(randomAmount)
159
+ });
160
+ setPayable(true);
161
+ localStorage.setItem(getUserStorageKey(DONATION_CUSTOM_AMOUNT_KEY_BASE), formatAmount(randomAmount));
162
+ setTimeout(() => {
163
+ customInputRef.current?.focus();
164
+ }, 200);
165
+ }
166
+ };
167
+ requestAnimationFrame(updateCounter);
113
168
  localStorage.setItem(getUserStorageKey(DONATION_PRESET_KEY_BASE), "custom");
114
169
  };
115
170
  const handleTabSelect = selectedItem => {
@@ -345,7 +400,24 @@ function ProductDonation({
345
400
  sx: {
346
401
  ml: 1
347
402
  },
348
- children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Avatar, {
403
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
404
+ size: "small",
405
+ onClick: handleCustomSelect,
406
+ disabled: state.animating,
407
+ sx: {
408
+ mr: 0.5,
409
+ opacity: state.animating ? 0.5 : 1,
410
+ transition: "all 0.2s ease",
411
+ "&:hover": {
412
+ transform: "scale(1.2)",
413
+ transition: "transform 0.3s ease"
414
+ }
415
+ },
416
+ "aria-label": t("common.random"),
417
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_AutoAwesome.default, {
418
+ fontSize: "small"
419
+ })
420
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Avatar, {
349
421
  src: currency?.logo,
350
422
  sx: {
351
423
  width: 16,
@@ -356,10 +428,29 @@ function ProductDonation({
356
428
  children: currency?.symbol
357
429
  })]
358
430
  }),
359
- autoComplete: "off"
431
+ autoComplete: "off",
432
+ sx: {
433
+ "& input": {
434
+ transition: "all 0.25s ease"
435
+ }
436
+ }
360
437
  },
361
438
  sx: {
362
- mt: defaultPreset !== "0" ? 0 : 1
439
+ mt: defaultPreset !== "0" ? 0 : 1,
440
+ "& .MuiInputBase-root": {
441
+ transition: "all 0.3s ease"
442
+ },
443
+ "& input[type=number]": {
444
+ MozAppearance: "textfield"
445
+ },
446
+ "& input[type=number]::-webkit-outer-spin-button": {
447
+ WebkitAppearance: "none",
448
+ margin: 0
449
+ },
450
+ "& input[type=number]::-webkit-inner-spin-button": {
451
+ WebkitAppearance: "none",
452
+ margin: 0
453
+ }
363
454
  }
364
455
  })]
365
456
  });
@@ -16,3 +16,5 @@ declare module 'pretty-ms-i18n';
16
16
  declare var blocklet: import('@blocklet/sdk').WindowBlocklet;
17
17
 
18
18
  declare var __PAYMENT_KIT_BASE_URL: string;
19
+
20
+ declare var __PAYMENT_KIT_AUTH_TOKEN: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.18.25",
3
+ "version": "1.18.27",
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.52",
58
- "@arcblock/ux": "^2.12.52",
59
- "@arcblock/ws": "^1.19.15",
60
- "@blocklet/ui-react": "^2.12.52",
57
+ "@arcblock/did-connect": "^2.12.60",
58
+ "@arcblock/ux": "^2.12.60",
59
+ "@arcblock/ws": "^1.19.19",
60
+ "@blocklet/ui-react": "^2.12.60",
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.15",
65
+ "@ocap/util": "^1.19.19",
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.25",
96
+ "@blocklet/payment-types": "1.18.27",
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": "1665ec667d621a3e607650e486cb0967371b9771"
127
+ "gitHead": "2bbcff1991daf5de147813c598e13d755da0c989"
128
128
  }
@@ -149,6 +149,7 @@ export function DonateDetails({ supporters = [], currency, method }: DonateHisto
149
149
  const { locale } = useLocaleContext();
150
150
  return (
151
151
  <Stack
152
+ className="cko-donate-details"
152
153
  sx={{
153
154
  width: '100%',
154
155
  minWidth: '256px',
@@ -308,9 +309,18 @@ function SupporterAvatar({
308
309
  onClose={() => setOpen(false)}
309
310
  sx={{
310
311
  '.MuiDialogContent-root': {
311
- width: '450px',
312
+ width: {
313
+ xs: '100%',
314
+ md: '450px',
315
+ },
312
316
  padding: '8px',
313
317
  },
318
+ '.cko-donate-details': {
319
+ maxHeight: {
320
+ xs: '100%',
321
+ md: '300px',
322
+ },
323
+ },
314
324
  }}
315
325
  title={`${customersNum} supporter${customersNum > 1 ? 's' : ''}`}>
316
326
  <DonateDetails supporters={supporters} currency={currency} method={method} totalAmount={totalAmount} />