@blocklet/payment-react 1.18.24 → 1.18.26

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 (67) 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/hooks/keyboard.js +3 -0
  8. package/es/index.d.ts +1 -0
  9. package/es/index.js +1 -0
  10. package/es/libs/api.js +4 -0
  11. package/es/libs/currency.d.ts +3 -0
  12. package/es/libs/currency.js +22 -0
  13. package/es/libs/phone-validator.js +2 -0
  14. package/es/libs/util.d.ts +2 -2
  15. package/es/libs/util.js +7 -4
  16. package/es/libs/validator.d.ts +1 -0
  17. package/es/libs/validator.js +70 -0
  18. package/es/payment/form/address.js +17 -3
  19. package/es/payment/form/index.js +10 -1
  20. package/es/payment/form/phone.js +12 -1
  21. package/es/payment/form/stripe/form.js +72 -15
  22. package/es/payment/index.js +33 -11
  23. package/es/payment/product-donation.js +110 -12
  24. package/es/types/shims.d.ts +2 -0
  25. package/lib/checkout/donate.js +11 -1
  26. package/lib/components/country-select.js +243 -39
  27. package/lib/components/over-due-invoice-payment.d.ts +3 -1
  28. package/lib/components/over-due-invoice-payment.js +7 -4
  29. package/lib/contexts/payment.d.ts +2 -1
  30. package/lib/contexts/payment.js +9 -1
  31. package/lib/hooks/keyboard.js +3 -0
  32. package/lib/index.d.ts +1 -0
  33. package/lib/index.js +12 -0
  34. package/lib/libs/api.js +4 -0
  35. package/lib/libs/currency.d.ts +3 -0
  36. package/lib/libs/currency.js +31 -0
  37. package/lib/libs/phone-validator.js +1 -0
  38. package/lib/libs/util.d.ts +2 -2
  39. package/lib/libs/util.js +7 -4
  40. package/lib/libs/validator.d.ts +1 -0
  41. package/lib/libs/validator.js +20 -0
  42. package/lib/payment/form/address.js +15 -2
  43. package/lib/payment/form/index.js +12 -1
  44. package/lib/payment/form/phone.js +13 -1
  45. package/lib/payment/form/stripe/form.js +98 -29
  46. package/lib/payment/index.js +34 -10
  47. package/lib/payment/product-donation.js +106 -15
  48. package/lib/types/shims.d.ts +2 -0
  49. package/package.json +8 -8
  50. package/src/checkout/donate.tsx +11 -1
  51. package/src/components/country-select.tsx +265 -20
  52. package/src/components/over-due-invoice-payment.tsx +6 -2
  53. package/src/contexts/payment.tsx +11 -1
  54. package/src/hooks/keyboard.ts +5 -3
  55. package/src/index.ts +1 -0
  56. package/src/libs/api.ts +4 -1
  57. package/src/libs/currency.ts +25 -0
  58. package/src/libs/phone-validator.ts +1 -0
  59. package/src/libs/util.ts +18 -4
  60. package/src/libs/validator.ts +70 -0
  61. package/src/payment/form/address.tsx +17 -4
  62. package/src/payment/form/index.tsx +11 -1
  63. package/src/payment/form/phone.tsx +15 -1
  64. package/src/payment/form/stripe/form.tsx +104 -32
  65. package/src/payment/index.tsx +45 -14
  66. package/src/payment/product-donation.tsx +129 -10
  67. package/src/types/shims.d.ts +2 -0
@@ -9,6 +9,7 @@ var _react = require("react");
9
9
  var _material = require("@mui/material");
10
10
  var _reactHookForm = require("react-hook-form");
11
11
  var _reactInternationalPhone = require("react-international-phone");
12
+ var _mobile = require("../hooks/mobile");
12
13
  const CountrySelect = (0, _react.forwardRef)(({
13
14
  value,
14
15
  onChange,
@@ -18,6 +19,102 @@ const CountrySelect = (0, _react.forwardRef)(({
18
19
  const {
19
20
  setValue
20
21
  } = (0, _reactHookForm.useFormContext)();
22
+ const [open, setOpen] = (0, _react.useState)(false);
23
+ const [searchText, setSearchText] = (0, _react.useState)("");
24
+ const inputRef = (0, _react.useRef)(null);
25
+ const menuRef = (0, _react.useRef)(null);
26
+ const listRef = (0, _react.useRef)(null);
27
+ const [focusedIndex, setFocusedIndex] = (0, _react.useState)(-1);
28
+ const itemHeightRef = (0, _react.useRef)(40);
29
+ const {
30
+ isMobile
31
+ } = (0, _mobile.useMobile)();
32
+ const measuredRef = (0, _react.useRef)(false);
33
+ (0, _react.useEffect)(() => {
34
+ if (!open) return () => {};
35
+ const handleResize = () => {
36
+ measuredRef.current = false;
37
+ };
38
+ window.addEventListener("resize", handleResize);
39
+ return () => {
40
+ window.removeEventListener("resize", handleResize);
41
+ };
42
+ }, [open]);
43
+ const scrollToTop = () => {
44
+ if (listRef.current) {
45
+ listRef.current.scrollTop = 0;
46
+ }
47
+ };
48
+ const measureItemHeight = () => {
49
+ if (!listRef.current || !open) return;
50
+ const items = listRef.current.querySelectorAll(".MuiMenuItem-root");
51
+ if (items.length > 0) {
52
+ const firstItem = items[0];
53
+ if (firstItem.offsetHeight > 0) {
54
+ itemHeightRef.current = firstItem.offsetHeight;
55
+ }
56
+ }
57
+ };
58
+ const controlScrollPosition = index => {
59
+ if (!listRef.current) return;
60
+ if (open && !measuredRef.current) {
61
+ measureItemHeight();
62
+ measuredRef.current = true;
63
+ }
64
+ const listHeight = listRef.current.clientHeight;
65
+ const targetPosition = index * itemHeightRef.current;
66
+ if (index < 2) {
67
+ listRef.current.scrollTop = 0;
68
+ } else if (index > filteredCountries.length - 3) {
69
+ listRef.current.scrollTop = listRef.current.scrollHeight - listHeight;
70
+ } else {
71
+ const scrollPosition = targetPosition - listHeight / 2 + itemHeightRef.current / 2;
72
+ listRef.current.scrollTop = Math.max(0, scrollPosition);
73
+ }
74
+ };
75
+ (0, _react.useEffect)(() => {
76
+ let timeout = null;
77
+ if (open) {
78
+ timeout = setTimeout(() => {
79
+ scrollToTop();
80
+ if (!isMobile && inputRef.current) {
81
+ inputRef.current.focus();
82
+ }
83
+ }, 100);
84
+ } else {
85
+ setSearchText("");
86
+ setFocusedIndex(-1);
87
+ }
88
+ return () => {
89
+ if (timeout) {
90
+ clearTimeout(timeout);
91
+ }
92
+ };
93
+ }, [open, isMobile]);
94
+ const filteredCountries = (0, _react.useMemo)(() => {
95
+ if (!searchText) return _reactInternationalPhone.defaultCountries;
96
+ return _reactInternationalPhone.defaultCountries.filter(c => {
97
+ const parsed = (0, _reactInternationalPhone.parseCountry)(c);
98
+ return parsed.name.toLowerCase().includes(searchText.toLowerCase()) || parsed.iso2.toLowerCase().includes(searchText.toLowerCase()) || `+${parsed.dialCode}`.includes(searchText);
99
+ });
100
+ }, [searchText]);
101
+ (0, _react.useEffect)(() => {
102
+ scrollToTop();
103
+ setFocusedIndex(-1);
104
+ }, [searchText]);
105
+ (0, _react.useEffect)(() => {
106
+ let timeout = null;
107
+ if (focusedIndex >= 0) {
108
+ timeout = setTimeout(() => {
109
+ controlScrollPosition(focusedIndex);
110
+ }, 10);
111
+ }
112
+ return () => {
113
+ if (timeout) {
114
+ clearTimeout(timeout);
115
+ }
116
+ };
117
+ }, [focusedIndex, filteredCountries.length]);
21
118
  const countryDetail = (0, _react.useMemo)(() => {
22
119
  const item = _reactInternationalPhone.defaultCountries.find(v => v[1] === value);
23
120
  return value && item ? (0, _reactInternationalPhone.parseCountry)(item) : {
@@ -28,11 +125,58 @@ const CountrySelect = (0, _react.forwardRef)(({
28
125
  onChange(e.target.value);
29
126
  setValue(name, e.target.value);
30
127
  };
31
- return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Select, {
128
+ const handleCountryClick = code => {
129
+ onChange(code);
130
+ setValue(name, code);
131
+ setOpen(false);
132
+ };
133
+ const handleSearchChange = e => {
134
+ e.stopPropagation();
135
+ setSearchText(e.target.value);
136
+ };
137
+ const handleKeyDown = e => {
138
+ e.stopPropagation();
139
+ if (e.key === "Escape") {
140
+ setOpen(false);
141
+ return;
142
+ }
143
+ const handleNavigation = direction => {
144
+ e.preventDefault();
145
+ setFocusedIndex(prev => {
146
+ if (direction === "next") {
147
+ if (prev === -1) return 0;
148
+ return prev >= filteredCountries.length - 1 ? 0 : prev + 1;
149
+ }
150
+ if (prev === -1) return filteredCountries.length - 1;
151
+ return prev <= 0 ? filteredCountries.length - 1 : prev - 1;
152
+ });
153
+ };
154
+ if (e.key === "Tab") {
155
+ handleNavigation(e.shiftKey ? "prev" : "next");
156
+ return;
157
+ }
158
+ if (e.key === "ArrowDown") {
159
+ handleNavigation("next");
160
+ return;
161
+ }
162
+ if (e.key === "ArrowUp") {
163
+ handleNavigation("prev");
164
+ return;
165
+ }
166
+ if (e.key === "Enter" && focusedIndex >= 0 && focusedIndex < filteredCountries.length) {
167
+ e.preventDefault();
168
+ const country = (0, _reactInternationalPhone.parseCountry)(filteredCountries[focusedIndex]);
169
+ handleCountryClick(country.iso2);
170
+ }
171
+ };
172
+ return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Select, {
32
173
  ref,
174
+ open,
175
+ onOpen: () => setOpen(true),
176
+ onClose: () => setOpen(false),
33
177
  MenuProps: {
34
178
  style: {
35
- height: "300px",
179
+ maxHeight: "300px",
36
180
  top: "10px"
37
181
  },
38
182
  anchorOrigin: {
@@ -42,6 +186,18 @@ const CountrySelect = (0, _react.forwardRef)(({
42
186
  transformOrigin: {
43
187
  vertical: "top",
44
188
  horizontal: "left"
189
+ },
190
+ PaperProps: {
191
+ ref: menuRef,
192
+ sx: {
193
+ display: "flex",
194
+ "& .MuiList-root": {
195
+ pt: 0,
196
+ display: "flex",
197
+ flexDirection: "column",
198
+ overflowY: "hidden"
199
+ }
200
+ }
45
201
  }
46
202
  },
47
203
  sx: {
@@ -68,43 +224,91 @@ const CountrySelect = (0, _react.forwardRef)(({
68
224
  },
69
225
  value,
70
226
  onChange: onCountryChange,
71
- renderValue: code => {
72
- return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
73
- display: "flex",
74
- alignItems: "center",
75
- flexWrap: "nowrap",
76
- gap: 0.5,
77
- sx: {
78
- cursor: "pointer"
79
- },
80
- children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_reactInternationalPhone.FlagEmoji, {
81
- iso2: code,
82
- style: {
83
- display: "flex"
84
- }
85
- }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
86
- children: countryDetail?.name
87
- })]
88
- });
89
- },
90
- children: _reactInternationalPhone.defaultCountries.map(c => {
91
- const parsed = (0, _reactInternationalPhone.parseCountry)(c);
92
- return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.MenuItem, {
93
- value: parsed.iso2,
94
- children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_reactInternationalPhone.FlagEmoji, {
95
- iso2: parsed.iso2,
96
- style: {
97
- marginRight: "8px"
98
- }
99
- }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
100
- marginRight: "8px",
101
- children: parsed.name
102
- }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
103
- color: "gray",
104
- children: ["+", parsed.dialCode]
105
- })]
106
- }, parsed.iso2);
107
- })
227
+ renderValue: code => /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
228
+ display: "flex",
229
+ alignItems: "center",
230
+ flexWrap: "nowrap",
231
+ gap: 0.5,
232
+ sx: {
233
+ cursor: "pointer"
234
+ },
235
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_reactInternationalPhone.FlagEmoji, {
236
+ iso2: code,
237
+ style: {
238
+ display: "flex"
239
+ }
240
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
241
+ children: countryDetail?.name
242
+ })]
243
+ }),
244
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
245
+ sx: {
246
+ position: "sticky",
247
+ top: 0,
248
+ zIndex: 1,
249
+ bgcolor: "background.paper",
250
+ p: 1
251
+ },
252
+ onClick: e => {
253
+ e.stopPropagation();
254
+ },
255
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.TextField, {
256
+ inputRef,
257
+ autoFocus: !isMobile,
258
+ fullWidth: true,
259
+ placeholder: "Search country...",
260
+ value: searchText,
261
+ onChange: handleSearchChange,
262
+ onKeyDown: handleKeyDown,
263
+ onClick: e => e.stopPropagation(),
264
+ size: "small",
265
+ variant: "outlined"
266
+ })
267
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
268
+ ref: listRef,
269
+ sx: {
270
+ flex: 1,
271
+ overflowY: "auto",
272
+ overflowX: "hidden",
273
+ maxHeight: "calc(300px - 65px)",
274
+ scrollBehavior: "smooth"
275
+ },
276
+ children: filteredCountries.length > 0 ? filteredCountries.map((c, index) => {
277
+ const parsed = (0, _reactInternationalPhone.parseCountry)(c);
278
+ const isFocused = index === focusedIndex;
279
+ return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.MenuItem, {
280
+ value: parsed.iso2,
281
+ selected: parsed.iso2 === value,
282
+ onClick: () => handleCountryClick(parsed.iso2),
283
+ sx: {
284
+ "&.Mui-selected": {
285
+ backgroundColor: "rgba(0, 0, 0, 0.04)"
286
+ },
287
+ "&:hover": {
288
+ backgroundColor: "var(--backgrounds-bg-highlight, #eff6ff)"
289
+ },
290
+ ...(isFocused ? {
291
+ backgroundColor: "var(--backgrounds-bg-highlight, #eff6ff)",
292
+ outline: "none"
293
+ } : {})
294
+ },
295
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_reactInternationalPhone.FlagEmoji, {
296
+ iso2: parsed.iso2,
297
+ style: {
298
+ marginRight: "8px"
299
+ }
300
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
301
+ children: parsed.name
302
+ })]
303
+ }, parsed.iso2);
304
+ }) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.MenuItem, {
305
+ disabled: true,
306
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
307
+ color: "text.secondary",
308
+ children: "No countries found"
309
+ })
310
+ })
311
+ })]
108
312
  });
109
313
  });
110
314
  CountrySelect.defaultProps = {
@@ -27,13 +27,14 @@ type Props = {
27
27
  subscriptionCount?: number;
28
28
  detailUrl: string;
29
29
  }) => React.ReactNode;
30
+ authToken?: string;
30
31
  };
31
32
  type SummaryItem = {
32
33
  amount: string;
33
34
  currency: PaymentCurrency;
34
35
  method: PaymentMethod;
35
36
  };
36
- declare function OverdueInvoicePayment({ subscriptionId, customerId, mode, dialogProps, children, onPaid, detailLinkOptions, successToast, alertMessage, }: Props): import("react").JSX.Element | null;
37
+ declare function OverdueInvoicePayment({ subscriptionId, customerId, mode, dialogProps, children, onPaid, detailLinkOptions, successToast, alertMessage, authToken, }: Props): import("react").JSX.Element | null;
37
38
  declare namespace OverdueInvoicePayment {
38
39
  var defaultProps: {
39
40
  mode: string;
@@ -49,6 +50,7 @@ declare namespace OverdueInvoicePayment {
49
50
  customerId: undefined;
50
51
  successToast: boolean;
51
52
  alertMessage: string;
53
+ authToken: undefined;
52
54
  };
53
55
  }
54
56
  export default OverdueInvoicePayment;
@@ -30,7 +30,7 @@ const fetchOverdueInvoices = async params => {
30
30
  } else {
31
31
  url = `/api/customers/${params.customerId}/overdue/invoices`;
32
32
  }
33
- const res = await _api.default.get(url);
33
+ const res = await _api.default.get(params.authToken ? (0, _ufo.joinURL)(url, `?authToken=${params.authToken}`) : url);
34
34
  return res.data;
35
35
  };
36
36
  function OverdueInvoicePayment({
@@ -44,7 +44,8 @@ function OverdueInvoicePayment({
44
44
  enabled: true
45
45
  },
46
46
  successToast = true,
47
- alertMessage = ""
47
+ alertMessage = "",
48
+ authToken
48
49
  }) {
49
50
  const {
50
51
  t
@@ -69,7 +70,8 @@ function OverdueInvoicePayment({
69
70
  runAsync: refresh
70
71
  } = (0, _ahooks.useRequest)(() => fetchOverdueInvoices({
71
72
  subscriptionId,
72
- customerId
73
+ customerId,
74
+ authToken
73
75
  }), {
74
76
  ready: !!subscriptionId || !!customerId
75
77
  });
@@ -450,6 +452,7 @@ OverdueInvoicePayment.defaultProps = {
450
452
  subscriptionId: void 0,
451
453
  customerId: void 0,
452
454
  successToast: true,
453
- alertMessage: ""
455
+ alertMessage: "",
456
+ authToken: void 0
454
457
  };
455
458
  module.exports = OverdueInvoicePayment;
@@ -25,10 +25,11 @@ export type PaymentContextProps = {
25
25
  connect: import('@arcblock/did-connect/lib/types').SessionContext['connectApi'];
26
26
  children: any;
27
27
  baseUrl?: string;
28
+ authToken?: string;
28
29
  };
29
30
  declare const PaymentContext: import("react").Context<PaymentContextType>;
30
31
  declare const Consumer: import("react").Consumer<PaymentContextType>;
31
- declare function PaymentProvider({ session, connect, children, baseUrl }: PaymentContextProps): import("react").JSX.Element | null;
32
+ declare function PaymentProvider({ session, connect, children, baseUrl, authToken }: PaymentContextProps): import("react").JSX.Element | null;
32
33
  declare namespace PaymentProvider {
33
34
  var defaultProps: {};
34
35
  }
@@ -57,10 +57,18 @@ function PaymentProvider({
57
57
  session,
58
58
  connect,
59
59
  children,
60
- baseUrl
60
+ baseUrl,
61
+ authToken
61
62
  }) {
62
63
  if (baseUrl) {
63
64
  window.__PAYMENT_KIT_BASE_URL = baseUrl;
65
+ } else {
66
+ window.__PAYMENT_KIT_BASE_URL = "";
67
+ }
68
+ if (authToken) {
69
+ window.__PAYMENT_KIT_AUTH_TOKEN = authToken;
70
+ } else {
71
+ window.__PAYMENT_KIT_AUTH_TOKEN = "";
64
72
  }
65
73
  const [livemode, setLivemode] = (0, _ahooks.useLocalStorageState)("livemode", {
66
74
  defaultValue: true
@@ -44,6 +44,9 @@ const useTabNavigation = (items, onSelect, options) => {
44
44
  return i;
45
45
  }
46
46
  }
47
+ if (includeCustom && navigableElements.length > 0) {
48
+ return navigableElements.length - 1;
49
+ }
47
50
  }
48
51
  return -1;
49
52
  }, [items, includeCustom, isCustomSelected, currentValue, valueType, compareValue, findNavigableElements]);
package/lib/index.d.ts CHANGED
@@ -43,5 +43,6 @@ export * from './hooks/mobile';
43
43
  export * from './hooks/table';
44
44
  export * from './hooks/scroll';
45
45
  export * from './hooks/keyboard';
46
+ export * from './libs/validator';
46
47
  export { translations, createTranslator } from './locales';
47
48
  export { createLazyComponent, api, dayjs, FormInput, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, PaymentBeneficiaries, LoadingButton, DonateDetails, };
package/lib/index.js CHANGED
@@ -430,6 +430,18 @@ Object.keys(_keyboard).forEach(function (key) {
430
430
  }
431
431
  });
432
432
  });
433
+ var _validator = require("./libs/validator");
434
+ Object.keys(_validator).forEach(function (key) {
435
+ if (key === "default" || key === "__esModule") return;
436
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
437
+ if (key in exports && exports[key] === _validator[key]) return;
438
+ Object.defineProperty(exports, key, {
439
+ enumerable: true,
440
+ get: function () {
441
+ return _validator[key];
442
+ }
443
+ });
444
+ });
433
445
  var _locales = require("./locales");
434
446
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
435
447
  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); }
package/lib/libs/api.js CHANGED
@@ -19,6 +19,10 @@ api.interceptors.request.use(config => {
19
19
  ...(config.params || {}),
20
20
  locale
21
21
  };
22
+ const authToken = window.__PAYMENT_KIT_AUTH_TOKEN;
23
+ if (authToken && typeof config.params.authToken === "undefined" && !query.has("authToken")) {
24
+ config.params.authToken = authToken;
25
+ }
22
26
  if (typeof config.params.livemode === "undefined" && query.has("livemode") === false) {
23
27
  const livemode = localStorage.getItem("livemode");
24
28
  config.params.livemode = (0, _isNull.default)(livemode) ? true : JSON.parse(livemode);
@@ -0,0 +1,3 @@
1
+ export declare const getUserStorageKey: (base: string, did?: string) => string;
2
+ export declare const saveCurrencyPreference: (currencyId: string, did?: string) => void;
3
+ export declare const getCurrencyPreference: (did?: string, availableCurrencyIds?: string[]) => string | null;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.saveCurrencyPreference = exports.getUserStorageKey = exports.getCurrencyPreference = void 0;
7
+ const CURRENCY_PREFERENCE_KEY_BASE = "payment-currency-preference";
8
+ const getUserStorageKey = (base, did) => {
9
+ return did ? `${base}:${did}` : base;
10
+ };
11
+ exports.getUserStorageKey = getUserStorageKey;
12
+ const saveCurrencyPreference = (currencyId, did) => {
13
+ try {
14
+ localStorage.setItem(getUserStorageKey(CURRENCY_PREFERENCE_KEY_BASE, did), currencyId);
15
+ } catch (e) {
16
+ console.warn("Failed to save currency preference", e);
17
+ }
18
+ };
19
+ exports.saveCurrencyPreference = saveCurrencyPreference;
20
+ const getCurrencyPreference = (did, availableCurrencyIds) => {
21
+ try {
22
+ const saved = localStorage.getItem(getUserStorageKey(CURRENCY_PREFERENCE_KEY_BASE, did));
23
+ if (saved && (!availableCurrencyIds || availableCurrencyIds.includes(saved))) {
24
+ return saved;
25
+ }
26
+ } catch (e) {
27
+ console.warn("Failed to access localStorage", e);
28
+ }
29
+ return null;
30
+ };
31
+ exports.getCurrencyPreference = getCurrencyPreference;
@@ -18,6 +18,7 @@ const getPhoneUtil = async () => {
18
18
  };
19
19
  exports.getPhoneUtil = getPhoneUtil;
20
20
  const validatePhoneNumber = async phoneNumber => {
21
+ if (!phoneNumber) return true;
21
22
  try {
22
23
  let util = null;
23
24
  try {
@@ -10,8 +10,8 @@ export declare function formatDateTime(date: Date | string | number, locale?: st
10
10
  export declare const formatLocale: (locale?: string) => string;
11
11
  export declare const formatPrettyMsLocale: (locale: string) => "zh_CN" | "en_US";
12
12
  export declare const formatError: (err: any) => any;
13
- export declare function formatBNStr(str?: string, decimals?: number, precision?: number, trim?: boolean): string;
14
- export declare function formatNumber(n: number | string, precision?: number, trim?: boolean): string;
13
+ export declare function formatBNStr(str?: string, decimals?: number, precision?: number, trim?: boolean, thousandSeparated?: boolean): string;
14
+ export declare function formatNumber(n: number | string, precision?: number, trim?: boolean, thousandSeparated?: boolean): string;
15
15
  export declare const formatPrice: (price: TPrice, currency: TPaymentCurrency, unit_label?: string, quantity?: number, bn?: boolean, locale?: string) => string;
16
16
  export declare const formatPriceAmount: (price: TPrice, currency: TPaymentCurrency, unit_label?: string, quantity?: number, bn?: boolean) => string;
17
17
  export declare function getStatementDescriptor(items: any[]): any;
package/lib/libs/util.js CHANGED
@@ -156,16 +156,19 @@ const formatError = err => {
156
156
  return err.message;
157
157
  };
158
158
  exports.formatError = formatError;
159
- function formatBNStr(str = "", decimals = 18, precision = 6, trim = true) {
160
- return formatNumber((0, _util.fromUnitToToken)(str, decimals), precision, trim);
159
+ function formatBNStr(str = "", decimals = 18, precision = 6, trim = true, thousandSeparated = true) {
160
+ if (!str) {
161
+ return "0";
162
+ }
163
+ return formatNumber((0, _util.fromUnitToToken)(str, decimals), precision, trim, thousandSeparated);
161
164
  }
162
- function formatNumber(n, precision = 6, trim = true) {
165
+ function formatNumber(n, precision = 6, trim = true, thousandSeparated = true) {
163
166
  if (!n || n === "0") {
164
167
  return "0";
165
168
  }
166
169
  const num = (0, _numbro.default)(n);
167
170
  const options = {
168
- thousandSeparated: true,
171
+ thousandSeparated,
169
172
  ...((precision || precision === 0) && {
170
173
  mantissa: precision
171
174
  })
@@ -0,0 +1 @@
1
+ export declare function validatePostalCode(postalCode: string, country?: string): boolean;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.validatePostalCode = validatePostalCode;
7
+ var _isPostalCode = _interopRequireDefault(require("validator/lib/isPostalCode"));
8
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ const POSTAL_CODE_SUPPORTED_COUNTRIES = ["AD", "AT", "AU", "BE", "BG", "BR", "CA", "CH", "CN", "CZ", "DE", "DK", "DZ", "EE", "ES", "FI", "FR", "GB", "GR", "HR", "HU", "ID", "IE", "IL", "IN", "IR", "IS", "IT", "JP", "KE", "KR", "LI", "LT", "LU", "LV", "MX", "MT", "NL", "NO", "NZ", "PL", "PR", "PT", "RO", "RU", "SA", "SE", "SI", "SK", "TN", "TW", "UA", "US", "ZA", "ZM"];
10
+ function validatePostalCode(postalCode, country) {
11
+ if (!postalCode) return true;
12
+ const countryUpper = country?.toUpperCase();
13
+ const isSupported = country && POSTAL_CODE_SUPPORTED_COUNTRIES.includes(countryUpper);
14
+ try {
15
+ return (0, _isPostalCode.default)(postalCode, isSupported ? countryUpper : "any");
16
+ } catch (error) {
17
+ console.error(error);
18
+ return false;
19
+ }
20
+ }
@@ -10,6 +10,7 @@ var _material = require("@mui/material");
10
10
  var _reactHookForm = require("react-hook-form");
11
11
  var _input = _interopRequireDefault(require("../../components/input"));
12
12
  var _countrySelect = _interopRequireDefault(require("../../components/country-select"));
13
+ var _validator = require("../../libs/validator");
13
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
15
  AddressForm.defaultProps = {
15
16
  sx: {}
@@ -25,6 +26,10 @@ function AddressForm({
25
26
  const {
26
27
  control
27
28
  } = (0, _reactHookForm.useFormContext)();
29
+ const country = (0, _reactHookForm.useWatch)({
30
+ control,
31
+ name: "billing_address.country"
32
+ });
28
33
  if (mode === "required") {
29
34
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Fade, {
30
35
  in: true,
@@ -74,7 +79,11 @@ function AddressForm({
74
79
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
75
80
  name: "billing_address.postal_code",
76
81
  rules: {
77
- required: t("payment.checkout.required")
82
+ required: t("payment.checkout.required"),
83
+ validate: x => {
84
+ const isValid = (0, _validator.validatePostalCode)(x, country);
85
+ return isValid ? true : t("payment.checkout.invalid");
86
+ }
78
87
  },
79
88
  errorPosition: "right",
80
89
  variant: "outlined",
@@ -126,7 +135,11 @@ function AddressForm({
126
135
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
127
136
  name: "billing_address.postal_code",
128
137
  rules: {
129
- required: t("payment.checkout.required")
138
+ required: t("payment.checkout.required"),
139
+ validate: x => {
140
+ const isValid = (0, _validator.validatePostalCode)(x, country);
141
+ return isValid ? true : t("payment.checkout.invalid");
142
+ }
130
143
  },
131
144
  errorPosition: "right",
132
145
  variant: "outlined",
@@ -31,6 +31,7 @@ var _mobile = require("../../hooks/mobile");
31
31
  var _phoneValidator = require("../../libs/phone-validator");
32
32
  var _loadingButton = _interopRequireDefault(require("../../components/loading-button"));
33
33
  var _overDueInvoicePayment = _interopRequireDefault(require("../../components/over-due-invoice-payment"));
34
+ var _currency2 = require("../../libs/currency");
34
35
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
35
36
  const waitForCheckoutComplete = async sessionId => {
36
37
  let result;
@@ -155,6 +156,13 @@ function PaymentForm({
155
156
  const index = currencies.findIndex(x => x.id === queryCurrencyId);
156
157
  return index >= 0 ? index : 0;
157
158
  });
159
+ const handleCurrencyChange = index => {
160
+ setPaymentCurrencyIndex(index);
161
+ const selectedCurrencyId = currencies[index]?.id;
162
+ if (selectedCurrencyId) {
163
+ (0, _currency2.saveCurrencyPreference)(selectedCurrencyId, session?.user?.did);
164
+ }
165
+ };
158
166
  const onCheckoutComplete = (0, _ahooks.useMemoizedFn)(async ({
159
167
  response
160
168
  }) => {
@@ -277,6 +285,9 @@ function PaymentForm({
277
285
  const showForm = !!session?.user;
278
286
  const skipBindWallet = method.type === "stripe";
279
287
  const handleConnected = async () => {
288
+ setState({
289
+ paying: true
290
+ });
280
291
  try {
281
292
  const result = await waitForCheckoutComplete(checkoutSession.id);
282
293
  if (state.paid === false) {
@@ -561,7 +572,7 @@ function PaymentForm({
561
572
  render: () => /* @__PURE__ */(0, _jsxRuntime.jsx)(_currency.default, {
562
573
  value: paymentCurrencyIndex,
563
574
  currencies,
564
- onChange: setPaymentCurrencyIndex
575
+ onChange: handleCurrencyChange
565
576
  })
566
577
  })
567
578
  }), state.stripePaying && state.stripeContext && /* @__PURE__ */(0, _jsxRuntime.jsx)(_stripe.default, {