@blocklet/payment-react 1.13.113

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 (173) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +29 -0
  3. package/babel.config.es.js +8 -0
  4. package/build.config.ts +29 -0
  5. package/es/api.d.ts +2 -0
  6. package/es/api.js +18 -0
  7. package/es/checkout/index.d.ts +15 -0
  8. package/es/checkout/index.js +61 -0
  9. package/es/components/input.d.ts +23 -0
  10. package/es/components/input.js +44 -0
  11. package/es/components/livemode.d.ts +2 -0
  12. package/es/components/livemode.js +24 -0
  13. package/es/components/pricing-table.d.ts +18 -0
  14. package/es/components/pricing-table.js +175 -0
  15. package/es/components/status.d.ts +3 -0
  16. package/es/components/status.js +20 -0
  17. package/es/components/switch.d.ts +6 -0
  18. package/es/components/switch.js +42 -0
  19. package/es/contexts/payment.d.ts +29 -0
  20. package/es/contexts/payment.js +45 -0
  21. package/es/dayjs.d.ts +2 -0
  22. package/es/dayjs.js +14 -0
  23. package/es/index.d.ts +16 -0
  24. package/es/index.js +29 -0
  25. package/es/locales/en.d.ts +2 -0
  26. package/es/locales/en.js +213 -0
  27. package/es/locales/index.d.ts +10 -0
  28. package/es/locales/index.js +20 -0
  29. package/es/locales/zh.d.ts +2 -0
  30. package/es/locales/zh.js +213 -0
  31. package/es/payment/amount.d.ts +12 -0
  32. package/es/payment/amount.js +22 -0
  33. package/es/payment/error.d.ts +13 -0
  34. package/es/payment/error.js +12 -0
  35. package/es/payment/footer.d.ts +4 -0
  36. package/es/payment/footer.js +9 -0
  37. package/es/payment/form/addon.d.ts +2 -0
  38. package/es/payment/form/addon.js +14 -0
  39. package/es/payment/form/address.d.ts +7 -0
  40. package/es/payment/form/address.js +119 -0
  41. package/es/payment/form/index.d.ts +9 -0
  42. package/es/payment/form/index.js +337 -0
  43. package/es/payment/form/phone.d.ts +4 -0
  44. package/es/payment/form/phone.js +97 -0
  45. package/es/payment/form/stripe.d.ts +13 -0
  46. package/es/payment/form/stripe.js +158 -0
  47. package/es/payment/header.d.ts +7 -0
  48. package/es/payment/header.js +29 -0
  49. package/es/payment/index.d.ts +28 -0
  50. package/es/payment/index.js +327 -0
  51. package/es/payment/product-card.d.ts +21 -0
  52. package/es/payment/product-card.js +34 -0
  53. package/es/payment/product-item.d.ts +19 -0
  54. package/es/payment/product-item.js +107 -0
  55. package/es/payment/product-skeleton.d.ts +4 -0
  56. package/es/payment/product-skeleton.js +34 -0
  57. package/es/payment/skeleton/overview.d.ts +2 -0
  58. package/es/payment/skeleton/overview.js +13 -0
  59. package/es/payment/skeleton/payment.d.ts +2 -0
  60. package/es/payment/skeleton/payment.js +19 -0
  61. package/es/payment/success.d.ts +8 -0
  62. package/es/payment/success.js +164 -0
  63. package/es/payment/summary.d.ts +12 -0
  64. package/es/payment/summary.js +178 -0
  65. package/es/theme.d.ts +1 -0
  66. package/es/theme.js +17 -0
  67. package/es/types/index.d.ts +19 -0
  68. package/es/types/index.js +0 -0
  69. package/es/types/shims.d.ts +18 -0
  70. package/es/util.d.ts +52 -0
  71. package/es/util.js +390 -0
  72. package/lib/api.d.ts +2 -0
  73. package/lib/api.js +26 -0
  74. package/lib/checkout/index.d.ts +15 -0
  75. package/lib/checkout/index.js +83 -0
  76. package/lib/components/input.d.ts +23 -0
  77. package/lib/components/input.js +72 -0
  78. package/lib/components/livemode.d.ts +2 -0
  79. package/lib/components/livemode.js +29 -0
  80. package/lib/components/pricing-table.d.ts +18 -0
  81. package/lib/components/pricing-table.js +232 -0
  82. package/lib/components/status.d.ts +3 -0
  83. package/lib/components/status.js +23 -0
  84. package/lib/components/switch.d.ts +6 -0
  85. package/lib/components/switch.js +51 -0
  86. package/lib/contexts/payment.d.ts +29 -0
  87. package/lib/contexts/payment.js +73 -0
  88. package/lib/dayjs.d.ts +2 -0
  89. package/lib/dayjs.js +21 -0
  90. package/lib/index.d.ts +16 -0
  91. package/lib/index.js +143 -0
  92. package/lib/locales/en.d.ts +2 -0
  93. package/lib/locales/en.js +220 -0
  94. package/lib/locales/index.d.ts +10 -0
  95. package/lib/locales/index.js +33 -0
  96. package/lib/locales/zh.d.ts +2 -0
  97. package/lib/locales/zh.js +220 -0
  98. package/lib/payment/amount.d.ts +12 -0
  99. package/lib/payment/amount.js +28 -0
  100. package/lib/payment/error.d.ts +13 -0
  101. package/lib/payment/error.js +52 -0
  102. package/lib/payment/footer.d.ts +4 -0
  103. package/lib/payment/footer.js +25 -0
  104. package/lib/payment/form/addon.d.ts +2 -0
  105. package/lib/payment/form/addon.js +37 -0
  106. package/lib/payment/form/address.d.ts +7 -0
  107. package/lib/payment/form/address.js +152 -0
  108. package/lib/payment/form/index.d.ts +9 -0
  109. package/lib/payment/form/index.js +464 -0
  110. package/lib/payment/form/phone.d.ts +4 -0
  111. package/lib/payment/form/phone.js +133 -0
  112. package/lib/payment/form/stripe.d.ts +13 -0
  113. package/lib/payment/form/stripe.js +213 -0
  114. package/lib/payment/header.d.ts +7 -0
  115. package/lib/payment/header.js +58 -0
  116. package/lib/payment/index.d.ts +28 -0
  117. package/lib/payment/index.js +382 -0
  118. package/lib/payment/product-card.d.ts +21 -0
  119. package/lib/payment/product-card.js +81 -0
  120. package/lib/payment/product-item.d.ts +19 -0
  121. package/lib/payment/product-item.js +160 -0
  122. package/lib/payment/product-skeleton.d.ts +4 -0
  123. package/lib/payment/product-skeleton.js +71 -0
  124. package/lib/payment/skeleton/overview.d.ts +2 -0
  125. package/lib/payment/skeleton/overview.js +48 -0
  126. package/lib/payment/skeleton/payment.d.ts +2 -0
  127. package/lib/payment/skeleton/payment.js +54 -0
  128. package/lib/payment/success.d.ts +8 -0
  129. package/lib/payment/success.js +215 -0
  130. package/lib/payment/summary.d.ts +12 -0
  131. package/lib/payment/summary.js +225 -0
  132. package/lib/theme.d.ts +1 -0
  133. package/lib/theme.js +19 -0
  134. package/lib/types/index.d.ts +19 -0
  135. package/lib/types/index.js +1 -0
  136. package/lib/types/shims.d.ts +18 -0
  137. package/lib/util.d.ts +52 -0
  138. package/lib/util.js +487 -0
  139. package/package.json +104 -0
  140. package/src/api.ts +24 -0
  141. package/src/checkout/index.tsx +74 -0
  142. package/src/components/input.tsx +58 -0
  143. package/src/components/livemode.tsx +23 -0
  144. package/src/components/pricing-table.tsx +207 -0
  145. package/src/components/status.tsx +19 -0
  146. package/src/components/switch.tsx +48 -0
  147. package/src/contexts/payment.tsx +74 -0
  148. package/src/dayjs.ts +17 -0
  149. package/src/index.ts +32 -0
  150. package/src/locales/en.tsx +218 -0
  151. package/src/locales/index.tsx +30 -0
  152. package/src/locales/zh.tsx +214 -0
  153. package/src/payment/amount.tsx +24 -0
  154. package/src/payment/error.tsx +29 -0
  155. package/src/payment/footer.tsx +12 -0
  156. package/src/payment/form/addon.tsx +24 -0
  157. package/src/payment/form/address.tsx +119 -0
  158. package/src/payment/form/index.tsx +401 -0
  159. package/src/payment/form/phone.tsx +103 -0
  160. package/src/payment/form/stripe.tsx +195 -0
  161. package/src/payment/header.tsx +40 -0
  162. package/src/payment/index.tsx +367 -0
  163. package/src/payment/product-card.tsx +55 -0
  164. package/src/payment/product-item.tsx +121 -0
  165. package/src/payment/product-skeleton.tsx +39 -0
  166. package/src/payment/skeleton/overview.tsx +21 -0
  167. package/src/payment/skeleton/payment.tsx +35 -0
  168. package/src/payment/success.tsx +186 -0
  169. package/src/payment/summary.tsx +198 -0
  170. package/src/theme.ts +18 -0
  171. package/src/types/index.ts +29 -0
  172. package/src/types/shims.d.ts +18 -0
  173. package/src/util.ts +543 -0
@@ -0,0 +1,119 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { Fade, Stack, Typography } from "@mui/material";
4
+ import { Controller, useFormContext } from "react-hook-form";
5
+ import { CountrySelector } from "react-international-phone";
6
+ import FormInput from "../../components/input.js";
7
+ export default function AddressForm({ mode, stripe }) {
8
+ const { t } = useLocaleContext();
9
+ const { control, setValue } = useFormContext();
10
+ if (mode === "required") {
11
+ return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-payment-address cko-payment-form", children: [
12
+ /* @__PURE__ */ jsx(Typography, { sx: { mb: 1, color: "text.primary", fontWeight: 600 }, children: t(`payment.checkout.billing.${mode}`) }),
13
+ /* @__PURE__ */ jsxs(Stack, { direction: "column", className: "cko-payment-form", spacing: 0, children: [
14
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0, children: [
15
+ /* @__PURE__ */ jsx(
16
+ Controller,
17
+ {
18
+ name: "billing_address.country",
19
+ control,
20
+ render: ({ field }) => /* @__PURE__ */ jsx(
21
+ CountrySelector,
22
+ {
23
+ selectedCountry: field.value,
24
+ onSelect: ({ iso2 }) => setValue(field.name, iso2),
25
+ buttonStyle: {
26
+ width: "64px",
27
+ height: "40px",
28
+ border: "1px solid #ccc",
29
+ marginLeft: -1,
30
+ marginTop: -1
31
+ }
32
+ }
33
+ )
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsx(
37
+ FormInput,
38
+ {
39
+ name: "billing_address.postal_code",
40
+ rules: { required: t("payment.checkout.required") },
41
+ errorPosition: "right",
42
+ variant: "outlined",
43
+ placeholder: t("payment.checkout.billing.postal_code")
44
+ }
45
+ )
46
+ ] }),
47
+ /* @__PURE__ */ jsx(
48
+ FormInput,
49
+ {
50
+ name: "billing_address.state",
51
+ rules: { required: t("payment.checkout.required") },
52
+ errorPosition: "right",
53
+ variant: "outlined",
54
+ placeholder: t("payment.checkout.billing.state")
55
+ }
56
+ ),
57
+ /* @__PURE__ */ jsx(
58
+ FormInput,
59
+ {
60
+ name: "billing_address.line1",
61
+ rules: { required: t("payment.checkout.required") },
62
+ errorPosition: "right",
63
+ variant: "outlined",
64
+ placeholder: t("payment.checkout.billing.line1")
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx(
68
+ FormInput,
69
+ {
70
+ name: "billing_address.city",
71
+ rules: { required: t("payment.checkout.required") },
72
+ errorPosition: "right",
73
+ variant: "outlined",
74
+ placeholder: t("payment.checkout.billing.city")
75
+ }
76
+ )
77
+ ] })
78
+ ] }) });
79
+ }
80
+ if (stripe) {
81
+ return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-payment-address cko-payment-form", children: [
82
+ /* @__PURE__ */ jsx(Typography, { sx: { mb: 1, color: "text.primary", fontWeight: 600 }, children: t(`payment.checkout.billing.${mode}`) }),
83
+ /* @__PURE__ */ jsx(Stack, { direction: "column", className: "cko-payment-form", spacing: 0, children: /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0, children: [
84
+ /* @__PURE__ */ jsx(
85
+ Controller,
86
+ {
87
+ name: "billing_address.country",
88
+ control,
89
+ render: ({ field }) => /* @__PURE__ */ jsx(
90
+ CountrySelector,
91
+ {
92
+ selectedCountry: field.value,
93
+ onSelect: ({ iso2 }) => setValue(field.name, iso2),
94
+ buttonStyle: {
95
+ width: "64px",
96
+ height: "40px",
97
+ border: "1px solid #ccc",
98
+ marginLeft: -1,
99
+ marginTop: -1
100
+ }
101
+ }
102
+ )
103
+ }
104
+ ),
105
+ /* @__PURE__ */ jsx(
106
+ FormInput,
107
+ {
108
+ name: "billing_address.postal_code",
109
+ rules: { required: t("payment.checkout.required") },
110
+ errorPosition: "right",
111
+ variant: "outlined",
112
+ placeholder: t("payment.checkout.billing.postal_code")
113
+ }
114
+ )
115
+ ] }) })
116
+ ] }) });
117
+ }
118
+ return null;
119
+ }
@@ -0,0 +1,9 @@
1
+ /// <reference types="react" />
2
+ import 'react-international-phone/style.css';
3
+ import { CheckoutCallbacks, CheckoutContext } from '../../types';
4
+ type PageData = CheckoutContext & CheckoutCallbacks;
5
+ declare function PaymentForm({ checkoutSession, paymentMethods, paymentIntent, customer, onPaid, onError, mode, }: PageData): import("react").JSX.Element;
6
+ declare namespace PaymentForm {
7
+ var defaultProps: {};
8
+ }
9
+ export default PaymentForm;
@@ -0,0 +1,337 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import "react-international-phone/style.css";
3
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
4
+ import { useTheme } from "@arcblock/ux/lib/Theme";
5
+ import Toast from "@arcblock/ux/lib/Toast";
6
+ import { LoadingButton } from "@mui/lab";
7
+ import { Avatar, Fade, InputAdornment, MenuItem, Select, Stack, Typography } from "@mui/material";
8
+ import { useCreation, useSetState, useSize } from "ahooks";
9
+ import { PhoneNumberUtil } from "google-libphonenumber";
10
+ import pWaitFor from "p-wait-for";
11
+ import { useEffect } from "react";
12
+ import { Controller, useFormContext, useWatch } from "react-hook-form";
13
+ import { dispatch } from "use-bus";
14
+ import isEmail from "validator/es/lib/isEmail";
15
+ import api from "../../api.js";
16
+ import FormInput from "../../components/input.js";
17
+ import { usePaymentContext } from "../../contexts/payment.js";
18
+ import { formatError, getStatementDescriptor } from "../../util.js";
19
+ import UserButtons from "./addon.js";
20
+ import AddressForm from "./address.js";
21
+ import PhoneInput from "./phone.js";
22
+ import StripeCheckout from "./stripe.js";
23
+ const phoneUtil = PhoneNumberUtil.getInstance();
24
+ const waitForCheckoutComplete = async (sessionId) => {
25
+ let result;
26
+ await pWaitFor(
27
+ async () => {
28
+ const { data } = await api.get(`/api/checkout-sessions/retrieve/${sessionId}`);
29
+ if (data.paymentIntent && data.paymentIntent.status === "requires_action" && data.paymentIntent.last_payment_error) {
30
+ throw new Error(data.paymentIntent.last_payment_error.message);
31
+ }
32
+ result = data;
33
+ return data.checkoutSession?.status === "complete" && ["paid", "no_payment_required"].includes(data.checkoutSession?.payment_status);
34
+ },
35
+ { interval: 2e3, timeout: 3 * 60 * 1e3 }
36
+ );
37
+ return result;
38
+ };
39
+ PaymentForm.defaultProps = {};
40
+ export default function PaymentForm({
41
+ checkoutSession,
42
+ paymentMethods,
43
+ paymentIntent,
44
+ customer,
45
+ onPaid,
46
+ onError,
47
+ mode
48
+ }) {
49
+ const theme = useTheme();
50
+ const { t } = useLocaleContext();
51
+ const { session, connect } = usePaymentContext();
52
+ const { control, getValues, setValue, handleSubmit } = useFormContext();
53
+ const [state, setState] = useSetState({
54
+ submitting: false,
55
+ paying: false,
56
+ paid: false,
57
+ paymentIntent,
58
+ stripeContext: void 0,
59
+ customer,
60
+ stripePaying: false
61
+ });
62
+ useEffect(() => {
63
+ if (session.user) {
64
+ const values = getValues();
65
+ if (!values.customer_name) {
66
+ setValue("customer_name", session.user.fullName);
67
+ }
68
+ if (!values.customer_email) {
69
+ setValue("customer_email", session.user.email);
70
+ }
71
+ if (!values.customer_phone) {
72
+ setValue("customer_phone", session.user.phone);
73
+ }
74
+ }
75
+ }, [session.user, getValues, setValue]);
76
+ const paymentMethod = useWatch({ control, name: "payment_method" });
77
+ const paymentCurrency = useWatch({ control, name: "payment_currency" });
78
+ const paymentCurrencies = paymentMethods.find((x) => x.id === paymentMethod)?.payment_currencies || [];
79
+ const domSize = useSize(document.body);
80
+ const isColumnLayout = useCreation(() => {
81
+ if (domSize) {
82
+ if (domSize?.width <= theme.breakpoints.values.md) {
83
+ return true;
84
+ }
85
+ }
86
+ return false;
87
+ }, [domSize, theme]);
88
+ const payee = getStatementDescriptor(checkoutSession.line_items);
89
+ const buttonText = session.user ? t(`payment.checkout.${checkoutSession.mode}`) : t("payment.checkout.connect", { action: t(`payment.checkout.${checkoutSession.mode}`) });
90
+ const method = paymentMethods.find((x) => x.id === paymentMethod);
91
+ const handleMethodChange = (e) => {
92
+ setValue("payment_method", e.target.value);
93
+ const currencies = paymentMethods.find((x) => x.id === e.target.value)?.payment_currencies || [];
94
+ if (currencies.some((x) => x.id === paymentCurrency) === false) {
95
+ setValue("payment_currency", currencies[0]?.id);
96
+ }
97
+ };
98
+ const handleConnected = async () => {
99
+ try {
100
+ const result = await waitForCheckoutComplete(checkoutSession.id);
101
+ setState({ paid: true, paying: false });
102
+ onPaid(result);
103
+ } catch (err) {
104
+ Toast.error(formatError(err));
105
+ } finally {
106
+ setState({ paying: false });
107
+ }
108
+ };
109
+ const onUserLoggedIn = async () => {
110
+ const { data: profile } = await api.get("/api/customers/me");
111
+ if (profile) {
112
+ const values = getValues();
113
+ if (!values.customer_name) {
114
+ setValue("customer_name", profile.name);
115
+ }
116
+ if (!values.customer_email) {
117
+ setValue("customer_email", profile.email);
118
+ }
119
+ if (!values.customer_phone) {
120
+ setValue("customer_phone", profile.phone);
121
+ }
122
+ if (profile.address?.country) {
123
+ setValue("billing_address.country", profile.address.country);
124
+ }
125
+ if (profile.address?.state) {
126
+ setValue("billing_address.state", profile.address.state);
127
+ }
128
+ if (profile.address?.line1) {
129
+ setValue("billing_address.line1", profile.address.line1);
130
+ }
131
+ if (profile.address?.line2) {
132
+ setValue("billing_address.line2", profile.address.line2);
133
+ }
134
+ if (profile.address?.city) {
135
+ setValue("billing_address.city", profile.address.city);
136
+ }
137
+ if (profile.address?.postal_code) {
138
+ setValue("billing_address.postal_code", profile.address.postal_code);
139
+ }
140
+ }
141
+ };
142
+ const onSubmit = async (data) => {
143
+ setState({ submitting: true });
144
+ try {
145
+ const result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
146
+ setState({
147
+ paymentIntent: result.data.paymentIntent,
148
+ stripeContext: result.data.stripeContext,
149
+ customer: result.data.customer,
150
+ submitting: false
151
+ });
152
+ if (["arcblock", "ethereum"].includes(method.type)) {
153
+ setState({ paying: true });
154
+ if (result.data.balance?.sufficient || result.data.delegation?.sufficient) {
155
+ await handleConnected();
156
+ } else {
157
+ connect.open({
158
+ action: checkoutSession.mode,
159
+ timeout: 5 * 60 * 1e3,
160
+ extraParams: { checkoutSessionId: checkoutSession.id },
161
+ onSuccess: async () => {
162
+ connect.close();
163
+ await handleConnected();
164
+ },
165
+ onClose: () => {
166
+ connect.close();
167
+ setState({ submitting: false, paying: false });
168
+ },
169
+ onError: (err) => {
170
+ setState({ submitting: false, paying: false });
171
+ onError(err);
172
+ }
173
+ });
174
+ }
175
+ }
176
+ if (["stripe"].includes(method.type)) {
177
+ if (result.data.stripeContext?.status === "succeeded") {
178
+ setState({ paying: true });
179
+ } else {
180
+ setState({ stripePaying: true });
181
+ }
182
+ }
183
+ } catch (err) {
184
+ if (err.response?.data?.code) {
185
+ dispatch(`error.${err.response?.data?.code}`);
186
+ }
187
+ Toast.error(formatError(err));
188
+ } finally {
189
+ setState({ submitting: false });
190
+ }
191
+ };
192
+ const onAction = () => {
193
+ if (session.user) {
194
+ handleSubmit(onSubmit)();
195
+ } else {
196
+ session.login({
197
+ onSuccess: onUserLoggedIn,
198
+ extraParams: {}
199
+ });
200
+ }
201
+ };
202
+ const onStripeConfirm = async () => {
203
+ setState({ stripePaying: false, paying: true });
204
+ await handleConnected();
205
+ };
206
+ const onStripeCancel = () => {
207
+ setState({ stripePaying: false });
208
+ };
209
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
210
+ /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-payment-contact", children: [
211
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", sx: { mb: 1 }, alignItems: "center", justifyContent: "space-between", children: [
212
+ /* @__PURE__ */ jsx(Typography, { sx: { color: "text.primary", fontWeight: 600 }, children: t("payment.checkout.contact") }),
213
+ isColumnLayout || mode !== "standalone" ? null : /* @__PURE__ */ jsx(UserButtons, {})
214
+ ] }),
215
+ /* @__PURE__ */ jsxs(Stack, { direction: "column", className: "cko-payment-form", spacing: 0, children: [
216
+ /* @__PURE__ */ jsx(
217
+ FormInput,
218
+ {
219
+ name: "customer_name",
220
+ variant: "outlined",
221
+ errorPosition: "right",
222
+ rules: {
223
+ required: t("payment.checkout.required")
224
+ },
225
+ InputProps: {
226
+ startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", children: t("payment.checkout.customer.name") })
227
+ }
228
+ }
229
+ ),
230
+ /* @__PURE__ */ jsx(
231
+ FormInput,
232
+ {
233
+ name: "customer_email",
234
+ variant: "outlined",
235
+ errorPosition: "right",
236
+ rules: {
237
+ required: t("payment.checkout.required"),
238
+ validate: (x) => isEmail(x) ? true : t("payment.checkout.invalid")
239
+ },
240
+ InputProps: {
241
+ startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", children: t("payment.checkout.customer.email") })
242
+ }
243
+ }
244
+ ),
245
+ checkoutSession.phone_number_collection?.enabled && /* @__PURE__ */ jsx(
246
+ PhoneInput,
247
+ {
248
+ name: "customer_phone",
249
+ variant: "outlined",
250
+ errorPosition: "right",
251
+ placeholder: "Phone number",
252
+ rules: {
253
+ required: t("payment.checkout.required"),
254
+ validate: (x) => {
255
+ try {
256
+ const parsed = phoneUtil.parseAndKeepRawInput(x);
257
+ return phoneUtil.isValidNumber(parsed) ? true : t("payment.checkout.invalid");
258
+ } catch {
259
+ return t("payment.checkout.invalid");
260
+ }
261
+ }
262
+ }
263
+ }
264
+ )
265
+ ] })
266
+ ] }) }),
267
+ /* @__PURE__ */ jsx(AddressForm, { mode: checkoutSession.billing_address_collection, stripe: method?.type === "stripe" }),
268
+ /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { direction: "column", alignItems: "flex-start", className: "cko-payment-methods", children: [
269
+ /* @__PURE__ */ jsx(Typography, { sx: { mb: 2, color: "text.primary", fontWeight: 600 }, children: t("payment.checkout.method") }),
270
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", sx: { width: 1 }, spacing: 1, children: [
271
+ /* @__PURE__ */ jsx(
272
+ Controller,
273
+ {
274
+ name: "payment_method",
275
+ control,
276
+ render: ({ field }) => /* @__PURE__ */ jsx(Select, { ...field, onChange: handleMethodChange, sx: { flex: 1 }, size: "small", children: paymentMethods.map((x) => {
277
+ const selected = x.id === paymentMethod;
278
+ return /* @__PURE__ */ jsx(MenuItem, { value: x.id, children: /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, children: [
279
+ /* @__PURE__ */ jsx(Avatar, { src: x.logo, alt: x.name, sx: { width: 20, height: 20 } }),
280
+ /* @__PURE__ */ jsx(Typography, { color: selected ? "text.primary" : "text.secondary", children: x.name })
281
+ ] }) }, x.id);
282
+ }) })
283
+ }
284
+ ),
285
+ /* @__PURE__ */ jsx(
286
+ Controller,
287
+ {
288
+ name: "payment_currency",
289
+ control,
290
+ render: ({ field }) => /* @__PURE__ */ jsx(Select, { ...field, sx: { flex: 1 }, size: "small", children: paymentCurrencies.map((x) => {
291
+ const selected = x.id === paymentCurrency;
292
+ return /* @__PURE__ */ jsx(MenuItem, { value: x.id, children: /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, children: [
293
+ /* @__PURE__ */ jsx(Avatar, { src: x.logo, alt: x.name, sx: { width: 20, height: 20 } }),
294
+ /* @__PURE__ */ jsx(Typography, { color: selected ? "text.primary" : "text.secondary", children: x.symbol })
295
+ ] }) }, x.id);
296
+ }) })
297
+ }
298
+ )
299
+ ] }),
300
+ state.stripePaying && state.stripeContext && /* @__PURE__ */ jsx(
301
+ StripeCheckout,
302
+ {
303
+ clientSecret: state.stripeContext.client_secret,
304
+ intentType: state.stripeContext.intent_type,
305
+ publicKey: method.settings.stripe?.publishable_key,
306
+ customer: state.customer,
307
+ mode: checkoutSession.mode,
308
+ onConfirm: onStripeConfirm,
309
+ onCancel: onStripeCancel
310
+ }
311
+ )
312
+ ] }) }),
313
+ /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-payment-submit", children: [
314
+ /* @__PURE__ */ jsx(
315
+ LoadingButton,
316
+ {
317
+ variant: "contained",
318
+ color: "primary",
319
+ size: "large",
320
+ onClick: onAction,
321
+ fullWidth: true,
322
+ loadingPosition: "end",
323
+ disabled: state.submitting || state.paying || state.stripePaying,
324
+ loading: state.submitting || state.paying,
325
+ children: state.submitting || state.paying ? t("payment.checkout.processing") : buttonText
326
+ }
327
+ ),
328
+ ["subscription", "setup"].includes(checkoutSession.mode) && /* @__PURE__ */ jsx(
329
+ Typography,
330
+ {
331
+ sx: { mt: 1, color: "text.secondary", fontSize: "0.9rem", lineHeight: "1.1rem", textAlign: "center" },
332
+ children: t("payment.checkout.confirm", { payee })
333
+ }
334
+ )
335
+ ] }) })
336
+ ] });
337
+ }
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ export default function PhoneInput({ ...props }: {
3
+ [x: string]: any;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,97 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { InputAdornment, MenuItem, Select, Typography } from "@mui/material";
3
+ import omit from "lodash/omit";
4
+ import { useEffect } from "react";
5
+ import { useFormContext, useWatch } from "react-hook-form";
6
+ import { FlagEmoji, defaultCountries, parseCountry, usePhoneInput } from "react-international-phone";
7
+ import FormInput from "../../components/input.js";
8
+ import { isValidCountry } from "../../util.js";
9
+ export default function PhoneInput({ ...props }) {
10
+ const countryFieldName = props.countryFieldName || "billing_address.country";
11
+ const { control, getValues, setValue } = useFormContext();
12
+ const values = getValues();
13
+ const { phone, handlePhoneValueChange, inputRef, country, setCountry } = usePhoneInput({
14
+ defaultCountry: isValidCountry(values[countryFieldName]) ? values[countryFieldName] : "us",
15
+ value: values[props.name] || "",
16
+ countries: defaultCountries,
17
+ onChange: (data) => {
18
+ setValue(props.name, data.phone);
19
+ }
20
+ });
21
+ const userCountry = useWatch({ control, name: countryFieldName });
22
+ useEffect(() => {
23
+ if (userCountry !== country) {
24
+ setCountry(userCountry);
25
+ }
26
+ }, [userCountry]);
27
+ const onCountryChange = (e) => {
28
+ setCountry(e.target.value);
29
+ setValue(countryFieldName, e.target.value);
30
+ };
31
+ return (
32
+ // @ts-ignore
33
+ /* @__PURE__ */ jsx(
34
+ FormInput,
35
+ {
36
+ value: phone,
37
+ onChange: handlePhoneValueChange,
38
+ type: "tel",
39
+ inputRef,
40
+ InputProps: {
41
+ startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", style: { marginRight: "2px", marginLeft: "-8px" }, children: /* @__PURE__ */ jsx(
42
+ Select,
43
+ {
44
+ MenuProps: {
45
+ style: {
46
+ height: "300px",
47
+ width: "360px",
48
+ top: "10px",
49
+ left: "-34px"
50
+ },
51
+ transformOrigin: {
52
+ vertical: "top",
53
+ horizontal: "left"
54
+ }
55
+ },
56
+ sx: {
57
+ width: "max-content",
58
+ // Remove default outline (display only on focus)
59
+ fieldset: {
60
+ display: "none"
61
+ },
62
+ '&.Mui-focused:has(div[aria-expanded="false"])': {
63
+ fieldset: {
64
+ display: "block"
65
+ }
66
+ },
67
+ // Update default spacing
68
+ ".MuiSelect-select": {
69
+ padding: "8px",
70
+ paddingRight: "24px !important"
71
+ },
72
+ svg: {
73
+ right: 0
74
+ }
75
+ },
76
+ value: country,
77
+ onChange: onCountryChange,
78
+ renderValue: (code) => /* @__PURE__ */ jsx(FlagEmoji, { iso2: code, style: { display: "flex" } }),
79
+ children: defaultCountries.map((c) => {
80
+ const parsed = parseCountry(c);
81
+ return /* @__PURE__ */ jsxs(MenuItem, { value: parsed.iso2, children: [
82
+ /* @__PURE__ */ jsx(FlagEmoji, { iso2: parsed.iso2, style: { marginRight: "8px" } }),
83
+ /* @__PURE__ */ jsx(Typography, { marginRight: "8px", children: parsed.name }),
84
+ /* @__PURE__ */ jsxs(Typography, { color: "gray", children: [
85
+ "+",
86
+ parsed.dialCode
87
+ ] })
88
+ ] }, parsed.iso2);
89
+ })
90
+ }
91
+ ) })
92
+ },
93
+ ...omit(props, ["countryFieldName"])
94
+ }
95
+ )
96
+ );
97
+ }
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import type { TCustomer } from '@blocklet/payment-types';
3
+ type StripeCheckoutProps = {
4
+ clientSecret: string;
5
+ intentType: string;
6
+ publicKey: string;
7
+ mode: string;
8
+ customer: TCustomer;
9
+ onConfirm: Function;
10
+ onCancel: Function;
11
+ };
12
+ export default function StripeCheckout({ clientSecret, intentType, publicKey, mode, customer, onConfirm, onCancel, }: StripeCheckoutProps): import("react").JSX.Element;
13
+ export {};