@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
@@ -31,6 +31,7 @@ import { useMobile } from "../../hooks/mobile.js";
31
31
  import { formatPhone, validatePhoneNumber } from "../../libs/phone-validator.js";
32
32
  import LoadingButton from "../../components/loading-button.js";
33
33
  import OverdueInvoicePayment from "../../components/over-due-invoice-payment.js";
34
+ import { saveCurrencyPreference } from "../../libs/currency.js";
34
35
  export const waitForCheckoutComplete = async (sessionId) => {
35
36
  let result;
36
37
  await pWaitFor(
@@ -135,6 +136,13 @@ export default function PaymentForm({
135
136
  const index = currencies.findIndex((x) => x.id === queryCurrencyId);
136
137
  return index >= 0 ? index : 0;
137
138
  });
139
+ const handleCurrencyChange = (index) => {
140
+ setPaymentCurrencyIndex(index);
141
+ const selectedCurrencyId = currencies[index]?.id;
142
+ if (selectedCurrencyId) {
143
+ saveCurrencyPreference(selectedCurrencyId, session?.user?.did);
144
+ }
145
+ };
138
146
  const onCheckoutComplete = useMemoizedFn(async ({ response }) => {
139
147
  if (response.id === checkoutSession.id && state.paid === false) {
140
148
  await handleConnected();
@@ -248,6 +256,7 @@ export default function PaymentForm({
248
256
  const showForm = !!session?.user;
249
257
  const skipBindWallet = method.type === "stripe";
250
258
  const handleConnected = async () => {
259
+ setState({ paying: true });
251
260
  try {
252
261
  const result = await waitForCheckoutComplete(checkoutSession.id);
253
262
  if (state.paid === false) {
@@ -485,7 +494,7 @@ export default function PaymentForm({
485
494
  {
486
495
  value: paymentCurrencyIndex,
487
496
  currencies,
488
- onChange: setPaymentCurrencyIndex
497
+ onChange: handleCurrencyChange
489
498
  }
490
499
  )
491
500
  }
@@ -4,12 +4,14 @@ import omit from "lodash/omit";
4
4
  import { useEffect, useRef, useCallback } from "react";
5
5
  import { useFormContext, useWatch } from "react-hook-form";
6
6
  import { defaultCountries, usePhoneInput } from "react-international-phone";
7
+ import { useMount } from "ahooks";
7
8
  import FormInput from "../../components/input.js";
8
9
  import { isValidCountry } from "../../libs/util.js";
9
10
  import CountrySelect from "../../components/country-select.js";
11
+ import { getPhoneUtil } from "../../libs/phone-validator.js";
10
12
  export default function PhoneInput({ ...props }) {
11
13
  const countryFieldName = props.countryFieldName || "billing_address.country";
12
- const { control, getValues, setValue } = useFormContext();
14
+ const { control, getValues, setValue, trigger } = useFormContext();
13
15
  const values = getValues();
14
16
  const isUpdatingRef = useRef(false);
15
17
  const safeUpdate = useCallback((callback) => {
@@ -43,6 +45,11 @@ export default function PhoneInput({ ...props }) {
43
45
  setCountry(userCountry);
44
46
  });
45
47
  }, [userCountry, country, setCountry, safeUpdate]);
48
+ useMount(() => {
49
+ getPhoneUtil().catch((err) => {
50
+ console.error("Failed to preload phone validator:", err);
51
+ });
52
+ });
46
53
  const onCountryChange = useCallback(
47
54
  (v) => {
48
55
  safeUpdate(() => {
@@ -51,6 +58,9 @@ export default function PhoneInput({ ...props }) {
51
58
  },
52
59
  [setCountry, safeUpdate]
53
60
  );
61
+ const handleBlur = useCallback(() => {
62
+ trigger(props.name);
63
+ }, [props.name]);
54
64
  return (
55
65
  // @ts-ignore
56
66
  /* @__PURE__ */ jsx(
@@ -60,6 +70,7 @@ export default function PhoneInput({ ...props }) {
60
70
  onChange: handlePhoneValueChange,
61
71
  type: "tel",
62
72
  inputRef,
73
+ onBlur: handleBlur,
63
74
  InputProps: {
64
75
  startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", style: { marginRight: "2px", marginLeft: "-8px" }, children: /* @__PURE__ */ jsx(
65
76
  CountrySelect,
@@ -9,6 +9,13 @@ import { useEffect, useCallback } from "react";
9
9
  import { useMobile } from "../../../hooks/mobile.js";
10
10
  import LoadingButton from "../../../components/loading-button.js";
11
11
  const { Elements, PaymentElement, useElements, useStripe, loadStripe, LinkAuthenticationElement } = globalThis.__STRIPE_COMPONENTS__;
12
+ const PaymentElementContainer = styled("div")`
13
+ opacity: 0;
14
+ transition: opacity 300ms ease;
15
+ &.visible {
16
+ opacity: 1;
17
+ }
18
+ `;
12
19
  function StripeCheckoutForm({
13
20
  clientSecret,
14
21
  intentType,
@@ -23,8 +30,35 @@ function StripeCheckoutForm({
23
30
  const [state, setState] = useSetState({
24
31
  message: "",
25
32
  confirming: false,
26
- loaded: false
33
+ loaded: false,
34
+ showBillingForm: false,
35
+ isTransitioning: false,
36
+ paymentMethod: "card"
27
37
  });
38
+ const handlePaymentMethodChange = (event) => {
39
+ const method = event.value?.type;
40
+ const needsBillingInfo = method === "google_pay" || method === "apple_pay";
41
+ const shouldShowForm = needsBillingInfo && !isCompleteBillingAddress(customer.address);
42
+ if (shouldShowForm && !state.showBillingForm) {
43
+ setState({ isTransitioning: true });
44
+ setTimeout(() => {
45
+ setState({
46
+ isTransitioning: false,
47
+ paymentMethod: method,
48
+ showBillingForm: true
49
+ });
50
+ }, 300);
51
+ } else {
52
+ setState({
53
+ showBillingForm: false,
54
+ paymentMethod: method,
55
+ isTransitioning: false
56
+ });
57
+ }
58
+ };
59
+ const isCompleteBillingAddress = (address) => {
60
+ return address && address.line1 && address.city && address.state && address.postal_code && address.country;
61
+ };
28
62
  useEffect(() => {
29
63
  if (!stripe) {
30
64
  return;
@@ -55,23 +89,43 @@ function StripeCheckoutForm({
55
89
  return;
56
90
  }
57
91
  try {
58
- setState({ confirming: true });
92
+ setState({ confirming: true, message: "" });
59
93
  const method = intentType === "payment_intent" ? "confirmPayment" : "confirmSetup";
60
- const { error } = await stripe[method]({
94
+ const { error: submitError } = await elements.submit();
95
+ if (submitError) {
96
+ setState({ confirming: false });
97
+ return;
98
+ }
99
+ const { error, paymentIntent, setupIntent } = await stripe[method]({
61
100
  elements,
62
101
  redirect: "if_required",
63
102
  confirmParams: {
64
103
  return_url: returnUrl || window.location.href,
65
- payment_method_data: {
66
- billing_details: {
67
- name: customer.name,
68
- phone: customer.phone,
69
- email: customer.email,
70
- address: customer.address
104
+ ...!state.showBillingForm ? {
105
+ payment_method_data: {
106
+ billing_details: {
107
+ name: customer.name,
108
+ phone: customer.phone,
109
+ email: customer.email,
110
+ address: {
111
+ ...customer.address || {},
112
+ country: customer.address?.country || "us",
113
+ line1: customer.address?.line1 || "",
114
+ line2: customer.address?.line2 || "",
115
+ city: customer.address?.city || "",
116
+ state: customer.address?.state || "",
117
+ postal_code: customer.address?.postal_code || "00000"
118
+ }
119
+ }
71
120
  }
72
- }
121
+ } : {}
73
122
  }
74
123
  });
124
+ const intent = paymentIntent || setupIntent;
125
+ if (intent?.status === "canceled" || intent?.status === "requires_payment_method") {
126
+ setState({ confirming: false });
127
+ return;
128
+ }
75
129
  setState({ confirming: false });
76
130
  if (error) {
77
131
  if (error.type === "validation_error") {
@@ -86,11 +140,11 @@ function StripeCheckoutForm({
86
140
  setState({ confirming: false, message: err.message });
87
141
  }
88
142
  },
89
- [customer, intentType, stripe]
143
+ [customer, intentType, stripe, state.showBillingForm, returnUrl]
90
144
  // eslint-disable-line
91
145
  );
92
146
  return /* @__PURE__ */ jsxs(Content, { onSubmit: handleSubmit, children: [
93
- /* @__PURE__ */ jsx(
147
+ (!state.paymentMethod || state.paymentMethod === "card") && /* @__PURE__ */ jsx(
94
148
  LinkAuthenticationElement,
95
149
  {
96
150
  options: {
@@ -98,12 +152,14 @@ function StripeCheckoutForm({
98
152
  }
99
153
  }
100
154
  ),
101
- /* @__PURE__ */ jsx(
155
+ /* @__PURE__ */ jsx(PaymentElementContainer, { className: !state.isTransitioning ? "visible" : "", children: /* @__PURE__ */ jsx(
102
156
  PaymentElement,
103
157
  {
104
158
  options: {
105
159
  layout: "auto",
106
- fields: { billingDetails: "never" },
160
+ fields: {
161
+ billingDetails: state.showBillingForm ? "auto" : "never"
162
+ },
107
163
  readOnly: state.confirming,
108
164
  defaultValues: {
109
165
  billingDetails: {
@@ -114,9 +170,10 @@ function StripeCheckoutForm({
114
170
  }
115
171
  }
116
172
  },
173
+ onChange: handlePaymentMethodChange,
117
174
  onReady: () => setState({ loaded: true })
118
175
  }
119
- ),
176
+ ) }),
120
177
  (!stripe || !elements || !state.loaded) && /* @__PURE__ */ jsx(Center, { relative: "parent", children: /* @__PURE__ */ jsx(CircularProgress, {}) }),
121
178
  stripe && elements && state.loaded && /* @__PURE__ */ jsx(
122
179
  LoadingButton,
@@ -7,7 +7,7 @@ import { Box, Fade, Stack } from "@mui/material";
7
7
  import { styled } from "@mui/system";
8
8
  import { fromTokenToUnit } from "@ocap/util";
9
9
  import { useSetState } from "ahooks";
10
- import { useEffect, useState } from "react";
10
+ import { useEffect, useState, useMemo } from "react";
11
11
  import { FormProvider, useForm, useWatch } from "react-hook-form";
12
12
  import trim from "lodash/trim";
13
13
  import { usePaymentContext } from "../contexts/payment.js";
@@ -22,13 +22,14 @@ import {
22
22
  } from "../libs/util.js";
23
23
  import PaymentError from "./error.js";
24
24
  import CheckoutFooter from "./footer.js";
25
- import PaymentForm from "./form/index.js";
25
+ import PaymentForm, { hasDidWallet } from "./form/index.js";
26
26
  import OverviewSkeleton from "./skeleton/overview.js";
27
27
  import PaymentSkeleton from "./skeleton/payment.js";
28
28
  import PaymentSuccess from "./success.js";
29
29
  import PaymentSummary from "./summary.js";
30
30
  import { useMobile } from "../hooks/mobile.js";
31
31
  import { formatPhone } from "../libs/phone-validator.js";
32
+ import { getCurrencyPreference } from "../libs/currency.js";
32
33
  PaymentInner.defaultProps = {
33
34
  completed: false,
34
35
  showCheckoutSummary: true
@@ -52,7 +53,36 @@ function PaymentInner({
52
53
  const { isMobile } = useMobile();
53
54
  const [state, setState] = useSetState({ checkoutSession });
54
55
  const query = getQueryParams(window.location.href);
55
- const defaultCurrencyId = query.currencyId || state.checkoutSession.currency_id || state.checkoutSession.line_items[0]?.price.currency_id;
56
+ const availableCurrencyIds = useMemo(() => {
57
+ const currencyIds = /* @__PURE__ */ new Set();
58
+ paymentMethods.forEach((method2) => {
59
+ method2.payment_currencies.forEach((currency2) => {
60
+ if (currency2.active) {
61
+ currencyIds.add(currency2.id);
62
+ }
63
+ });
64
+ });
65
+ return Array.from(currencyIds);
66
+ }, [paymentMethods]);
67
+ const defaultCurrencyId = useMemo(() => {
68
+ if (query.currencyId && availableCurrencyIds.includes(query.currencyId)) {
69
+ return query.currencyId;
70
+ }
71
+ if (session?.user && !hasDidWallet(session.user)) {
72
+ const stripeCurrencyId = paymentMethods.find((m) => m.type === "stripe")?.payment_currencies.find((c) => c.active)?.id;
73
+ if (stripeCurrencyId) {
74
+ return stripeCurrencyId;
75
+ }
76
+ }
77
+ const savedPreference = getCurrencyPreference(session?.user?.did, availableCurrencyIds);
78
+ if (savedPreference) {
79
+ return savedPreference;
80
+ }
81
+ if (state.checkoutSession.currency_id && availableCurrencyIds.includes(state.checkoutSession.currency_id)) {
82
+ return state.checkoutSession.currency_id;
83
+ }
84
+ return availableCurrencyIds?.[0];
85
+ }, [query.currencyId, availableCurrencyIds, session?.user, state.checkoutSession.currency_id, paymentMethods]);
56
86
  const defaultMethodId = paymentMethods.find((m) => m.payment_currencies.some((c) => c.id === defaultCurrencyId))?.id;
57
87
  const hideSummaryCard = mode.endsWith("-minimal") || !showCheckoutSummary;
58
88
  const methods = useForm({
@@ -97,14 +127,6 @@ function PaymentInner({
97
127
  document.body.removeEventListener("focusout", focusoutHandler);
98
128
  };
99
129
  }, []);
100
- useEffect(() => {
101
- if (!methods || query.currencyId) {
102
- return;
103
- }
104
- if (state.checkoutSession.currency_id !== defaultCurrencyId) {
105
- methods.setValue("payment_currency", state.checkoutSession.currency_id);
106
- }
107
- }, [state.checkoutSession, defaultCurrencyId, query.currencyId]);
108
130
  const currencyId = useWatch({ control: methods.control, name: "payment_currency", defaultValue: defaultCurrencyId });
109
131
  const currency = findCurrency(paymentMethods, currencyId) || settings.baseCurrency;
110
132
  const method = paymentMethods.find((x) => x.id === currency.payment_method_id);
@@ -1,6 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
- import { Avatar, Box, Card, CardActionArea, Grid, Stack, TextField, Typography } from "@mui/material";
3
+ import { Avatar, Box, Card, CardActionArea, Grid, Stack, TextField, Typography, IconButton } from "@mui/material";
4
+ import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";
4
5
  import { useSetState } from "ahooks";
5
6
  import { useEffect, useRef } from "react";
6
7
  import { formatAmountPrecisionLimit } from "../libs/util.js";
@@ -62,7 +63,8 @@ export default function ProductDonation({
62
63
  selected: defaultPreset === "custom" ? "" : defaultPreset,
63
64
  input: defaultCustomAmount,
64
65
  custom: !supportPreset || defaultPreset === "custom",
65
- error: ""
66
+ error: "",
67
+ animating: false
66
68
  });
67
69
  const customInputRef = useRef(null);
68
70
  const containerRef = useRef(null);
@@ -73,15 +75,73 @@ export default function ProductDonation({
73
75
  localStorage.setItem(getUserStorageKey(DONATION_PRESET_KEY_BASE), formatAmount(amount));
74
76
  };
75
77
  const handleCustomSelect = () => {
76
- setState({ custom: true, selected: "", error: "" });
77
- const savedCustomAmount = getSavedCustomAmount();
78
- if (savedCustomAmount) {
79
- setState({ input: savedCustomAmount });
80
- onChange({ priceId: item.price_id, amount: savedCustomAmount });
81
- setPayable(true);
82
- } else if (!state.input) {
83
- setPayable(false);
78
+ setState({
79
+ custom: true,
80
+ selected: "",
81
+ animating: true
82
+ });
83
+ const hasPresets = presets.length > 0;
84
+ let sortedPresets = [];
85
+ if (hasPresets) {
86
+ sortedPresets = [...presets].map((p) => parseFloat(p)).sort((a, b) => a - b);
87
+ }
88
+ const minPreset = hasPresets ? sortedPresets[0] : 1;
89
+ const middleIndex = Math.floor(sortedPresets.length / 2);
90
+ const maxPreset = hasPresets ? sortedPresets[middleIndex] : 10;
91
+ const detectPrecision = () => {
92
+ let maxPrecision = 2;
93
+ if (!hasPresets)
94
+ return 0;
95
+ const allIntegers = presets.every((preset) => {
96
+ const num = parseFloat(preset);
97
+ return num === Math.floor(num);
98
+ });
99
+ if (allIntegers)
100
+ return 0;
101
+ presets.forEach((preset) => {
102
+ const decimalPart = preset.toString().split(".")[1];
103
+ if (decimalPart) {
104
+ maxPrecision = Math.max(maxPrecision, decimalPart.length);
105
+ }
106
+ });
107
+ return maxPrecision;
108
+ };
109
+ const precision = detectPrecision();
110
+ let randomAmount;
111
+ if (precision === 0) {
112
+ randomAmount = (Math.round(Math.random() * (maxPreset - minPreset) + minPreset) || 1).toString();
113
+ } else {
114
+ randomAmount = (Math.random() * (maxPreset - minPreset) + minPreset).toFixed(precision);
84
115
  }
116
+ const startValue = state.input ? parseFloat(state.input) : 0;
117
+ const targetValue = parseFloat(randomAmount);
118
+ const difference = targetValue - startValue;
119
+ const startTime = Date.now();
120
+ const duration = 800;
121
+ const updateCounter = () => {
122
+ const currentTime = Date.now();
123
+ const elapsed = currentTime - startTime;
124
+ if (elapsed < duration) {
125
+ const progress = elapsed / duration;
126
+ const intermediateValue = startValue + difference * progress;
127
+ const currentValue = precision === 0 ? Math.floor(intermediateValue).toString() : intermediateValue.toFixed(precision);
128
+ setState({ input: currentValue });
129
+ requestAnimationFrame(updateCounter);
130
+ } else {
131
+ setState({
132
+ input: randomAmount,
133
+ animating: false,
134
+ error: ""
135
+ });
136
+ onChange({ priceId: item.price_id, amount: formatAmount(randomAmount) });
137
+ setPayable(true);
138
+ localStorage.setItem(getUserStorageKey(DONATION_CUSTOM_AMOUNT_KEY_BASE), formatAmount(randomAmount));
139
+ setTimeout(() => {
140
+ customInputRef.current?.focus();
141
+ }, 200);
142
+ }
143
+ };
144
+ requestAnimationFrame(updateCounter);
85
145
  localStorage.setItem(getUserStorageKey(DONATION_PRESET_KEY_BASE), "custom");
86
146
  };
87
147
  const handleTabSelect = (selectedItem) => {
@@ -261,13 +321,51 @@ export default function ProductDonation({
261
321
  inputRef: customInputRef,
262
322
  InputProps: {
263
323
  endAdornment: /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", sx: { ml: 1 }, children: [
324
+ /* @__PURE__ */ jsx(
325
+ IconButton,
326
+ {
327
+ size: "small",
328
+ onClick: handleCustomSelect,
329
+ disabled: state.animating,
330
+ sx: {
331
+ mr: 0.5,
332
+ opacity: state.animating ? 0.5 : 1,
333
+ transition: "all 0.2s ease",
334
+ "&:hover": {
335
+ transform: "scale(1.2)",
336
+ transition: "transform 0.3s ease"
337
+ }
338
+ },
339
+ "aria-label": t("common.random"),
340
+ children: /* @__PURE__ */ jsx(AutoAwesomeIcon, { fontSize: "small" })
341
+ }
342
+ ),
264
343
  /* @__PURE__ */ jsx(Avatar, { src: currency?.logo, sx: { width: 16, height: 16 }, alt: currency?.symbol }),
265
344
  /* @__PURE__ */ jsx(Typography, { children: currency?.symbol })
266
345
  ] }),
267
- autoComplete: "off"
346
+ autoComplete: "off",
347
+ sx: {
348
+ "& input": {
349
+ transition: "all 0.25s ease"
350
+ }
351
+ }
268
352
  },
269
353
  sx: {
270
- mt: defaultPreset !== "0" ? 0 : 1
354
+ mt: defaultPreset !== "0" ? 0 : 1,
355
+ "& .MuiInputBase-root": {
356
+ transition: "all 0.3s ease"
357
+ },
358
+ "& input[type=number]": {
359
+ MozAppearance: "textfield"
360
+ },
361
+ "& input[type=number]::-webkit-outer-spin-button": {
362
+ WebkitAppearance: "none",
363
+ margin: 0
364
+ },
365
+ "& input[type=number]::-webkit-inner-spin-button": {
366
+ WebkitAppearance: "none",
367
+ margin: 0
368
+ }
271
369
  }
272
370
  }
273
371
  )
@@ -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;
@@ -63,6 +63,7 @@ function DonateDetails({
63
63
  locale
64
64
  } = (0, _context.useLocaleContext)();
65
65
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Stack, {
66
+ className: "cko-donate-details",
66
67
  sx: {
67
68
  width: "100%",
68
69
  minWidth: "256px",
@@ -227,8 +228,17 @@ function SupporterAvatar({
227
228
  onClose: () => setOpen(false),
228
229
  sx: {
229
230
  ".MuiDialogContent-root": {
230
- width: "450px",
231
+ width: {
232
+ xs: "100%",
233
+ md: "450px"
234
+ },
231
235
  padding: "8px"
236
+ },
237
+ ".cko-donate-details": {
238
+ maxHeight: {
239
+ xs: "100%",
240
+ md: "300px"
241
+ }
232
242
  }
233
243
  },
234
244
  title: `${customersNum} supporter${customersNum > 1 ? "s" : ""}`,