tf-checkout-react 1.6.6-beta.3 → 1.6.6-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +61 -40
  2. package/dist/adapters/customFields.d.ts +1 -0
  3. package/dist/api/checkout.d.ts +1 -0
  4. package/dist/api/common.d.ts +1 -0
  5. package/dist/api/index.d.ts +1 -0
  6. package/dist/api/preRegistrationComplete.d.ts +1 -1
  7. package/dist/components/addonsContainer/AddonComponent.d.ts +5 -1
  8. package/dist/components/addonsContainer/SimpleAddonsContainer.d.ts +17 -0
  9. package/dist/components/addonsContainer/index.d.ts +5 -1
  10. package/dist/components/billing-info-container/index.d.ts +8 -1
  11. package/dist/components/billing-info-container/utils.d.ts +25 -1
  12. package/dist/components/common/DatePickerField.d.ts +7 -1
  13. package/dist/components/countdown/index.d.ts +1 -1
  14. package/dist/components/forgotPasswordModal/index.d.ts +2 -1
  15. package/dist/components/myTicketsContainer/index.d.ts +3 -2
  16. package/dist/components/orderDetailsContainer/index.d.ts +7 -1
  17. package/dist/components/paymentContainer/OrderDetails.d.ts +8 -0
  18. package/dist/components/paymentContainer/handlePayment.d.ts +15 -0
  19. package/dist/components/paymentContainer/index.d.ts +10 -5
  20. package/dist/components/preRegistration/FieldsSection.d.ts +7 -1
  21. package/dist/components/preRegistration/PreRegistrationComplete.d.ts +6 -0
  22. package/dist/components/preRegistration/constants.d.ts +2 -2
  23. package/dist/components/preRegistration/index.d.ts +6 -0
  24. package/dist/components/resetPasswordContainer/index.d.ts +2 -2
  25. package/dist/components/stripePayment/index.d.ts +18 -3
  26. package/dist/components/ticketsContainer/InfoIcon.d.ts +5 -0
  27. package/dist/components/ticketsContainer/TicketsSection.d.ts +3 -2
  28. package/dist/components/ticketsContainer/TimeSlotsSection.d.ts +25 -0
  29. package/dist/components/ticketsContainer/index.d.ts +18 -5
  30. package/dist/components/timerWidget/index.d.ts +2 -1
  31. package/dist/constants/index.d.ts +5 -0
  32. package/dist/index.d.ts +4 -1
  33. package/dist/tf-checkout-react.cjs.development.js +5196 -3599
  34. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  35. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  36. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  37. package/dist/tf-checkout-react.esm.js +5199 -3605
  38. package/dist/tf-checkout-react.esm.js.map +1 -1
  39. package/dist/tf-checkout-styles.css +1 -1
  40. package/dist/types/add_on.d.ts +1 -0
  41. package/dist/types/checkoutPageConfigs.d.ts +1 -1
  42. package/dist/types/order-data.d.ts +2 -1
  43. package/dist/utils/auth.d.ts +8 -0
  44. package/dist/utils/customFields.d.ts +11 -0
  45. package/dist/utils/getDomain.d.ts +1 -1
  46. package/dist/utils/index.d.ts +1 -1
  47. package/dist/utils/setConfigs.d.ts +1 -0
  48. package/package.json +3 -2
  49. package/src/adapters/customFields.ts +7 -1
  50. package/src/api/auth.ts +2 -1
  51. package/src/api/checkout.ts +8 -4
  52. package/src/api/common.ts +49 -2
  53. package/src/api/interceptors.ts +7 -23
  54. package/src/api/preRegistrationComplete.ts +1 -1
  55. package/src/api/publicRequest.ts +10 -0
  56. package/src/components/addonsContainer/AddonComponent.tsx +71 -11
  57. package/src/components/addonsContainer/SimpleAddonsContainer.tsx +388 -0
  58. package/src/components/addonsContainer/index.tsx +189 -58
  59. package/src/components/billing-info-container/index.tsx +704 -390
  60. package/src/components/billing-info-container/{utils.ts → utils.tsx} +119 -0
  61. package/src/components/common/CheckboxField/index.tsx +1 -1
  62. package/src/components/common/DatePickerField.tsx +25 -10
  63. package/src/components/common/SnackbarAlert.tsx +32 -34
  64. package/src/components/confirmationContainer/index.tsx +1 -1
  65. package/src/components/countdown/index.tsx +22 -22
  66. package/src/components/delegationsContainer/IssueComponent.tsx +2 -1
  67. package/src/components/forgotPasswordModal/index.tsx +44 -13
  68. package/src/components/loginForm/index.tsx +1 -1
  69. package/src/components/loginModal/index.tsx +2 -2
  70. package/src/components/loginModal/style.css +3 -1
  71. package/src/components/myTicketsContainer/index.tsx +13 -9
  72. package/src/components/orderDetailsContainer/index.tsx +188 -173
  73. package/src/components/paymentContainer/OrderDetails.tsx +170 -0
  74. package/src/components/paymentContainer/handlePayment.ts +86 -0
  75. package/src/components/paymentContainer/index.tsx +253 -226
  76. package/src/components/paymentContainer/style.css +113 -0
  77. package/src/components/preRegistration/FieldsSection.tsx +8 -0
  78. package/src/components/preRegistration/PreRegistrationComplete.tsx +128 -118
  79. package/src/components/preRegistration/PreRegistrationInformations.tsx +21 -15
  80. package/src/components/preRegistration/constants.tsx +10 -4
  81. package/src/components/preRegistration/index.tsx +194 -174
  82. package/src/components/registerForm/constants.tsx +3 -1
  83. package/src/components/registerForm/index.tsx +3 -3
  84. package/src/components/resetPasswordContainer/index.tsx +12 -13
  85. package/src/components/seatMapContainer/TicketsSection.tsx +2 -2
  86. package/src/components/stripePayment/index.tsx +129 -24
  87. package/src/components/ticketsContainer/InfoIcon.tsx +35 -0
  88. package/src/components/ticketsContainer/PromoCodeSection.tsx +34 -28
  89. package/src/components/ticketsContainer/TicketRow.tsx +1 -1
  90. package/src/components/ticketsContainer/TicketsSection.tsx +178 -52
  91. package/src/components/ticketsContainer/TimeSlotsSection.tsx +120 -0
  92. package/src/components/ticketsContainer/index.tsx +209 -99
  93. package/src/components/timerWidget/index.tsx +15 -3
  94. package/src/constants/index.ts +2 -0
  95. package/src/hoc/CustomFields/index.tsx +9 -1
  96. package/src/index.ts +7 -2
  97. package/src/types/add_on.ts +1 -0
  98. package/src/types/api/common.d.ts +27 -0
  99. package/src/types/api/orders.d.ts +19 -3
  100. package/src/types/api/payment.d.ts +5 -2
  101. package/src/types/api/preRegistrationComplete.d.ts +2 -2
  102. package/src/types/checkoutPageConfigs.ts +1 -1
  103. package/src/types/order-data.ts +2 -1
  104. package/src/types/pre-registration-complete.d.ts +6 -1
  105. package/src/utils/auth.ts +32 -0
  106. package/src/utils/cookies.ts +42 -11
  107. package/src/utils/customFields.ts +22 -0
  108. package/src/utils/getDomain.ts +10 -4
  109. package/src/utils/index.ts +1 -1
  110. package/src/utils/setConfigs.ts +3 -1
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import './style.css'
2
3
 
3
4
  import { CircularProgress, ThemeOptions } from '@mui/material'
@@ -16,19 +17,21 @@ import _isEmpty from 'lodash/isEmpty'
16
17
  import _isEqual from 'lodash/isEqual'
17
18
  import _map from 'lodash/map'
18
19
  import { nanoid } from 'nanoid'
19
- import React, { FC, useEffect, useRef, useState } from 'react'
20
+ import React, { FC, useCallback, useEffect, useRef, useState } from 'react'
20
21
 
21
22
  import {
22
23
  AttributesConfig,
23
24
  getCart,
24
25
  getCheckoutPageConfigs,
25
26
  getCountries,
27
+ getPaymentData,
26
28
  getProfileData,
27
29
  getStates,
28
30
  postOnCheckout,
29
31
  register,
30
32
  setCustomHeader,
31
33
  } from '../../api'
34
+ import { updateCheckout } from '../../api/checkout'
32
35
  import { withCustomFields } from '../../hoc'
33
36
  import { usePixel } from '../../hooks/usePixel'
34
37
  import { IBillingInfoData } from '../../types'
@@ -41,21 +44,26 @@ import {
41
44
  } from '../../utils'
42
45
  import { ErrorFocus } from '../../utils/formikErrorFocus'
43
46
  import { AddonsContainter, IAddonContainterProps } from '../addonsContainer'
47
+ import SimpleAddonsContainer from '../addonsContainer/SimpleAddonsContainer'
44
48
  import SnackbarAlert from '../common/SnackbarAlert'
45
49
  import { ForgotPasswordModal } from '../forgotPasswordModal'
46
50
  import { VerificationPendingModal } from '../idVerificationContainer/VerificationPendingModal'
47
51
  import { LoginModal } from '../loginModal'
52
+ import { IPaymentPage, PaymentContainer } from '../paymentContainer'
53
+ import { handlePaymentMiddleWare } from '../paymentContainer/handlePayment'
48
54
  import { SignupModal } from '../signupModal'
49
55
  import TimerWidget from '../timerWidget'
50
56
  import {
51
57
  assingUniqueIds,
52
58
  createCheckoutDataBody,
53
59
  createRegisterFormData,
60
+ filterBillingInfoFields,
54
61
  getFieldComponent,
55
62
  getFieldLabel,
56
63
  getInitialValues,
57
64
  getValidateFunctions,
58
65
  ICheckoutBody,
66
+ renderComponentWithProps,
59
67
  } from './utils'
60
68
 
61
69
  export interface IBillingInfoPage {
@@ -65,7 +73,9 @@ export interface IBillingInfoPage {
65
73
  values: FormikValues,
66
74
  formikHelpers: FormikHelpers<FormikValues>,
67
75
  eventId: any,
68
- res: any
76
+ res: any,
77
+ checkoutUpdateResponse?: any,
78
+ paymentResponse?: any
69
79
  ) => void;
70
80
  onRegisterSuccess?: (value: any) => void;
71
81
  onRegisterError?: (e: AxiosError, email: string) => void;
@@ -83,8 +93,11 @@ export interface IBillingInfoPage {
83
93
  onLogin?: () => void;
84
94
  onLoginSuccess?: () => void;
85
95
  onErrorClose?: () => void;
96
+ onCheckoutUpdateSuccess?: (res: any) => void;
97
+ onCheckoutUpdateError?: (e: AxiosError) => void;
86
98
  initialValues?: FormikValues;
87
99
  buttonName?: string;
100
+ freeOrderButtonName?: string;
88
101
  theme?: 'light' | 'dark';
89
102
  isLoggedIn?: boolean;
90
103
  accountInfoTitle?: string | JSX.Element;
@@ -113,11 +126,15 @@ export interface IBillingInfoPage {
113
126
  onPendingVerification?: () => void;
114
127
  includeAddons?: boolean;
115
128
  addonsProps?: IAddonContainterProps;
129
+ addOnDataWithCustomFields?: any;
130
+ isSinglePageCheckout?: boolean;
131
+ paymentProps?: Partial<IPaymentPage>;
116
132
  }
117
133
 
118
134
  const LogicRunner: FC<{
119
135
  brandOptIn?: boolean;
120
136
  values: any;
137
+ errors: any;
121
138
  setStates: React.Dispatch<any>;
122
139
  setFieldValue: any;
123
140
  setValues: any;
@@ -136,72 +153,72 @@ const LogicRunner: FC<{
136
153
  shouldFetchCountries,
137
154
  brandOptIn,
138
155
  }) => {
139
- const prevCountry = useRef(values.country)
140
- useEffect(() => {
141
- const fetchStates = async () => {
142
- try {
143
- const res = await getStates(values.country)
144
- const mappedStates = _map(res.data, (item, key) => ({
145
- label: item,
146
- value: key,
147
- }))
148
- setStates(mappedStates)
149
- if (prevCountry.current !== values.country) {
150
- const stateExists = mappedStates.find(
151
- state => state.value === values.state
152
- )?.value
153
- setFieldValue('state', stateExists ?? mappedStates[0]?.value ?? '')
154
- prevCountry.current = values.country
155
- }
156
- onGetStatesSuccess(res.data)
157
- } catch (e) {
158
- if (axios.isAxiosError(e)) {
159
- onGetStatesError(e)
160
- }
156
+ const prevCountry = useRef(values.country)
157
+ useEffect(() => {
158
+ const fetchStates = async () => {
159
+ try {
160
+ const res = await getStates(values.country)
161
+ const mappedStates = _map(res.data, (item, key) => ({
162
+ label: item,
163
+ value: key,
164
+ }))
165
+ setStates(mappedStates)
166
+ if (prevCountry.current !== values.country) {
167
+ const stateExists = mappedStates.find(
168
+ state => state.value === values.state
169
+ )?.value
170
+ setFieldValue('state', stateExists ?? mappedStates[0]?.value ?? '')
171
+ prevCountry.current = values.country
172
+ }
173
+ onGetStatesSuccess(res.data)
174
+ } catch (e) {
175
+ if (axios.isAxiosError(e)) {
176
+ onGetStatesError(e)
161
177
  }
162
178
  }
163
- shouldFetchCountries && fetchStates()
164
- }, [values.country, setStates, setFieldValue])
165
- const userDataEncoded = isBrowser ? window.localStorage.getItem('user_data') : ''
166
- useEffect(() => {
167
- // set user data from local storage
168
- const getStoredUserData = () => {
169
- if (isBrowser) {
170
- if (userDataEncoded) {
171
- try {
172
- const parsedData = JSON.parse(userDataEncoded)
173
- const mappedValues = {
174
- firstName: parsedData?.first_name || parsedData?.firstName || '',
175
- lastName: parsedData?.last_name || parsedData?.lastName || '',
176
- email: parsedData?.email || '',
177
- phone: parsedData?.phone || '',
178
- confirmEmail: parsedData?.email || '',
179
- state: parsedData?.state || '',
180
- street_address: parsedData?.street_address || '',
181
- country: parsedData?.country || '1',
182
- zip: parsedData?.zip || '',
183
- brand_opt_in: brandOptIn ? brandOptIn : parsedData?.brand_opt_in || false,
184
- city: parsedData?.city || '',
185
- confirmPassword: '',
186
- password: '',
187
- 'holderFirstName-0': parsedData?.first_name || parsedData?.firstName || '',
188
- 'holderLastName-0': parsedData?.last_name || parsedData?.lastName || '',
189
- 'holderEmail-0': parsedData?.email || '',
190
- }
179
+ }
180
+ shouldFetchCountries && fetchStates()
181
+ }, [values.country, setStates, setFieldValue])
182
+ const userDataEncoded = isBrowser ? window.localStorage.getItem('user_data') : ''
183
+ useEffect(() => {
184
+ // set user data from local storage
185
+ const getStoredUserData = () => {
186
+ if (isBrowser) {
187
+ if (userDataEncoded) {
188
+ try {
189
+ const parsedData = JSON.parse(userDataEncoded)
190
+ const mappedValues = {
191
+ firstName: parsedData?.first_name || parsedData?.firstName || '',
192
+ lastName: parsedData?.last_name || parsedData?.lastName || '',
193
+ email: parsedData?.email || '',
194
+ phone: parsedData?.phone || '',
195
+ confirmEmail: parsedData?.email || '',
196
+ state: parsedData?.state || '',
197
+ street_address: parsedData?.street_address || '',
198
+ country: parsedData?.country || '1',
199
+ zip: parsedData?.zip || '',
200
+ brand_opt_in: brandOptIn ? brandOptIn : parsedData?.brand_opt_in || false,
201
+ city: parsedData?.city || '',
202
+ confirmPassword: '',
203
+ password: '',
204
+ 'holderFirstName-0': parsedData?.first_name || parsedData?.firstName || '',
205
+ 'holderLastName-0': parsedData?.last_name || parsedData?.lastName || '',
206
+ 'holderEmail-0': parsedData?.email || '',
207
+ }
191
208
 
192
- const extraDataJSON = window.localStorage.getItem('extraData')
193
- const extraData = extraDataJSON ? JSON.parse(extraDataJSON) : null
209
+ const extraDataJSON = window.localStorage.getItem('extraData')
210
+ const extraData = extraDataJSON ? JSON.parse(extraDataJSON) : null
194
211
 
195
- setValues({ ...values, ...mappedValues, ...(extraData ?? {}) })
196
- setUserValues(mappedValues)
197
- } catch (e) { }
198
- }
212
+ setValues({ ...values, ...mappedValues, ...(extraData ?? {}) })
213
+ setUserValues(mappedValues)
214
+ } catch (e) {}
199
215
  }
200
216
  }
201
- getStoredUserData()
202
- }, [userDataEncoded, setValues, setUserValues])
203
- return null
204
- }
217
+ }
218
+ getStoredUserData()
219
+ }, [userDataEncoded, setValues, setUserValues, brandOptIn])
220
+ return null
221
+ }
205
222
 
206
223
  const BillingInfoContainer = React.memo(
207
224
  ({
@@ -212,6 +229,7 @@ const BillingInfoContainer = React.memo(
212
229
  },
213
230
  initialValues = {},
214
231
  buttonName = 'Submit',
232
+ freeOrderButtonName = 'Complete Registration',
215
233
  handleSubmit = _identity,
216
234
  theme = 'light',
217
235
  onRegisterSuccess = _identity,
@@ -227,6 +245,8 @@ const BillingInfoContainer = React.memo(
227
245
  onGetProfileDataError = _identity,
228
246
  onLogin,
229
247
  onLoginSuccess = _identity,
248
+ onCheckoutUpdateSuccess = _identity,
249
+ onCheckoutUpdateError = _identity,
230
250
  isLoggedIn: pIsLoggedIn = false,
231
251
  accountInfoTitle = '',
232
252
  hideLogo,
@@ -254,12 +274,18 @@ const BillingInfoContainer = React.memo(
254
274
  onGetCheckoutConfigsError = _identity,
255
275
  includeAddons = false,
256
276
  addonsProps,
277
+ addOnDataWithCustomFields,
278
+ isSinglePageCheckout = false,
279
+ paymentProps = {},
257
280
  }: IBillingInfoPage) => {
258
281
  const [extraData, setExtraData] = useState(null)
259
282
  const [isConfigLoading, setIsConfigLoading] = useState(true)
260
283
  const [configs, setConfigs] = useState<null | AttributesConfig>(null)
261
284
  const [isNewUser, setIsNewUser] = useState(false)
262
285
  const themeMui = createTheme(themeOptions)
286
+ const addressRef = useRef<any>(null)
287
+ const cardRef = useRef<any>(null)
288
+ const stripeRef = useRef<any>(null)
263
289
 
264
290
  useEffect(() => {
265
291
  if (isBrowser) {
@@ -285,7 +311,7 @@ const BillingInfoContainer = React.memo(
285
311
  const defaultCountry = isBrowser ? window.localStorage.getItem('eventCountry') : ''
286
312
  const userData =
287
313
  isBrowser && window.localStorage.getItem('user_data')
288
- ? JSON.parse(window.localStorage.getItem('user_data') || '')
314
+ ? JSON.parse(window.localStorage.getItem('user_data') || '{}')
289
315
  : {}
290
316
  const [dataWithUniqueIds, setDataWithUniqueIds] = useState<IBillingInfoData[]>(
291
317
  assingUniqueIds(data)
@@ -319,7 +345,7 @@ const BillingInfoContainer = React.memo(
319
345
  const [loading, setLoading] = useState(true)
320
346
  const [cardLoading, setCardLoading] = useState(false)
321
347
  const [isCountriesLoading, setIsCountriesLoading] = useState(true)
322
- const [error, setError] = useState(null)
348
+ const [error, setError] = useState<string | null>(null)
323
349
  const [phoneValidationIsLoading, setPhoneValidationIsLoading] = useState(false)
324
350
  const emailLogged = _get(userData, 'email', '') || _get(userValues, 'email', '')
325
351
  const firstNameLogged =
@@ -357,15 +383,19 @@ const BillingInfoContainer = React.memo(
357
383
  const hideBusinessCategoryField =
358
384
  !collectMandatoryBusinessCategory && !collectOptionalBusinessCategory
359
385
 
360
- const [pendingVerificationMessage, setPendingVerificationMessage] = useState()
361
-
362
- // Get prevProps
386
+ const [pendingVerificationMessage, setPendingVerificationMessage] = useState<string>()
387
+ const [reviewData, setReviewData] = useState<any>({})
388
+ const [checkoutData, setCheckoutData] = useState<any>({})
389
+ const [checkoutUpdateData, setCheckoutUpdateData] = useState<any>({})
363
390
  const prevData = useRef(data)
364
391
 
365
- const addAddOnsInAttributes = (checkoutBody: any) => {
392
+ const addAddOnsInAttributes = useCallback((checkoutBody: any) => {
366
393
  const selectedAddOns = window.localStorage.getItem('add_ons') || '{}'
367
394
  checkoutBody.attributes.add_ons = JSON.parse(selectedAddOns)
368
- }
395
+ }, [])
396
+ const [singleCheckoutAddons, setSingleCheckoutAddOns] = useState<any>({})
397
+
398
+ const orderIsFree = !Number(checkoutData?.total)
369
399
 
370
400
  useEffect(() => {
371
401
  const hasUniqueId = _get(dataWithUniqueIds, '[0].uniqueId')
@@ -378,13 +408,13 @@ const BillingInfoContainer = React.memo(
378
408
  }
379
409
  }, [dataWithUniqueIds, data])
380
410
 
381
- const getQuantity = (cart: any = []) => {
411
+ const getQuantity = useCallback((cart: any = []) => {
382
412
  let qty = 0
383
413
  cart.forEach((item: any) => {
384
414
  qty += +item.quantity
385
415
  })
386
416
  return qty
387
- }
417
+ }, [])
388
418
 
389
419
  useEffect(() => {
390
420
  if (pIsLoggedIn !== isLoggedIn || xtfCookie) {
@@ -412,10 +442,22 @@ const BillingInfoContainer = React.memo(
412
442
  shouldFetchCountries && fetchCountries()
413
443
  fetchCart()
414
444
 
445
+ // Initialize checkout with event_id on first load
446
+ if (isSinglePageCheckout && eventId) {
447
+ updateCheckoutWithAddOns()
448
+ }
449
+
415
450
  return () => {
416
451
  isBrowser && localStorage.removeItem('selectedTicketsQuantity')
417
452
  }
418
- }, [])
453
+ // eslint-disable-next-line react-hooks/exhaustive-deps
454
+ }, [
455
+ eventId,
456
+ isSinglePageCheckout,
457
+ shouldFetchCountries,
458
+ onGetCountriesSuccess,
459
+ onGetCountriesError,
460
+ ])
419
461
 
420
462
  // fetch cart data
421
463
  const fetchCart = async () => {
@@ -464,6 +506,29 @@ const BillingInfoContainer = React.memo(
464
506
  fetchCart()
465
507
  }, [isLoggedIn])
466
508
 
509
+ useEffect(() => {
510
+ const fetchCheckoutUpdate = async () => {
511
+ if (!eventId) return
512
+
513
+ try {
514
+ const checkoutUpdateResponse = await updateCheckout({
515
+ attributes: {
516
+ event_id: eventId,
517
+ },
518
+ })
519
+
520
+ if (checkoutUpdateResponse.success) {
521
+ const checkoutAttributes = checkoutUpdateResponse.data.attributes
522
+ setCheckoutUpdateData(checkoutAttributes)
523
+ }
524
+ } catch (error) {
525
+ console.error('Failed to fetch checkout update:', error)
526
+ }
527
+ }
528
+
529
+ fetchCheckoutUpdate()
530
+ }, [eventId])
531
+
467
532
  useEffect(() => {
468
533
  const collectPaymentData = async () => {
469
534
  if (
@@ -489,9 +554,9 @@ const BillingInfoContainer = React.memo(
489
554
  onSkipBillingPage(checkoutResponse.data.attributes)
490
555
  setLoading(false)
491
556
  } catch (e) {
492
- onSubmitError(e)
493
- if (e.response?.data?.data?.hasUnverifiedOrder) {
494
- setPendingVerificationMessage(e.response?.data?.message)
557
+ onSubmitError(e as AxiosError)
558
+ if (_get(e, 'response.data.data.hasUnverifiedOrder')) {
559
+ setPendingVerificationMessage(_get(e, 'response.data.message'))
495
560
  }
496
561
  }
497
562
  } else {
@@ -501,90 +566,171 @@ const BillingInfoContainer = React.memo(
501
566
  collectPaymentData()
502
567
  }, [skipPage, ticketsQuantity])
503
568
 
504
- const collectCheckoutBody = (
505
- values: Record<string, any>,
506
- profileData?: any
507
- ): Record<string, any> => {
508
- let checkoutBody = {} as ICheckoutBody
509
-
510
- // Auto collect ticket holders name when it was skipped optionally
511
- if (showDOB && !showTicketHolders && canSkipHolderNames) {
512
- checkoutBody = createCheckoutDataBodyWithDefaultHolder(
513
- ticketsQuantity.length,
514
- values,
515
- true,
516
- { emailLogged, firstNameLogged, lastNameLogged }
517
- )
518
- } else {
519
- checkoutBody = createCheckoutDataBody(
520
- ticketsQuantity.length,
521
- values,
522
- {
523
- emailLogged: emailLogged || profileData.email,
524
- firstNameLogged:
525
- firstNameLogged || profileData.first_name || profileData.firstName,
526
- lastNameLogged:
527
- lastNameLogged || profileData.last_name || profileData.lastName,
528
- },
529
- showDOB
530
- )
531
- }
569
+ const collectCheckoutBody = useCallback(
570
+ (values: Record<string, any>, profileData?: any): Record<string, any> => {
571
+ let checkoutBody = {} as ICheckoutBody
532
572
 
533
- // Collect data_capture for Order Custom Fields
534
- const data_capture: Record<string, any> = {}
535
- _forEach(customFieldsOrderKeys, (key: string) => {
536
- data_capture[key] = values[key]
573
+ // Auto collect ticket holders name when it was skipped optionally
574
+ if (showDOB && !showTicketHolders && canSkipHolderNames) {
575
+ checkoutBody = createCheckoutDataBodyWithDefaultHolder(
576
+ ticketsQuantity.length,
577
+ values,
578
+ true,
579
+ { emailLogged, firstNameLogged, lastNameLogged }
580
+ )
581
+ } else {
582
+ checkoutBody = createCheckoutDataBody(
583
+ ticketsQuantity.length,
584
+ values,
585
+ {
586
+ emailLogged: emailLogged || profileData.email,
587
+ firstNameLogged:
588
+ firstNameLogged || profileData.first_name || profileData.firstName,
589
+ lastNameLogged:
590
+ lastNameLogged || profileData.last_name || profileData.lastName,
591
+ },
592
+ showDOB
593
+ )
594
+ }
537
595
 
538
- // Delete from values list
539
- delete checkoutBody.attributes[key]
540
- })
596
+ // Collect data_capture for Order Custom Fields
597
+ const data_capture: Record<string, any> = {}
598
+ _forEach(customFieldsOrderKeys, (key: string) => {
599
+ data_capture[key] = values[key]
541
600
 
542
- // Temp solution for hardcoded data capture values, to be deleted in the future
543
- const captureKeys = [
544
- 'businessCategory',
545
- 'company',
546
- 'instagram',
547
- 'jobTitle',
548
- 'wallet_address',
549
- ]
601
+ // Delete from values list
602
+ delete checkoutBody.attributes[key]
603
+ })
550
604
 
551
- captureKeys.forEach(key => {
552
- const path = `data_capture.${key}`
553
- const value = _get(values, path, '')
605
+ // Temp solution for hardcoded data capture values, to be deleted in the future
606
+ const captureKeys = [
607
+ 'businessCategory',
608
+ 'company',
609
+ 'instagram',
610
+ 'jobTitle',
611
+ 'wallet_address',
612
+ ]
554
613
 
555
- if (value !== '') {
556
- data_capture[key] = value
557
- }
614
+ captureKeys.forEach(key => {
615
+ const path = `data_capture.${key}`
616
+ const value = _get(values, path, '')
558
617
 
559
- const attributeKey = `data_capture[${key}]`
560
- delete checkoutBody.attributes?.[attributeKey]
561
- })
618
+ if (value !== '') {
619
+ data_capture[key] = value
620
+ }
621
+
622
+ const attributeKey = `data_capture[${key}]`
623
+ delete checkoutBody.attributes?.[attributeKey]
624
+ })
625
+
626
+ // Collect data_capture for Ticket Holders Fields
627
+ _forEach(checkoutBody.attributes.ticket_holders, (holder, holderIndex) => {
628
+ const holderDataCapture: Record<string, any> = {}
629
+
630
+ _forEach(customFieldsTicketHolderKeys, customFieldKey => {
631
+ const customFieldHolderName = `${customFieldKey}-${holderIndex}`
632
+ const customFieldHolderKey = values[customFieldHolderName] || ''
633
+ holderDataCapture[customFieldKey] = customFieldHolderKey
634
+
635
+ // Delete holder specific value from values list
636
+ delete checkoutBody.attributes[customFieldHolderName]
637
+ })
638
+
639
+ // Assign Ticket Holder data_capture final value
640
+ if (!_isEmpty(holderDataCapture)) {
641
+ holder.ticket_data_capture = holderDataCapture
642
+ }
643
+ })
562
644
 
563
- // Collect data_capture for Ticket Holders Fields
564
- _forEach(checkoutBody.attributes.ticket_holders, (holder, holderIndex) => {
565
- const holderDataCapture: Record<string, any> = {}
645
+ return { attributes: { ...checkoutBody.attributes, data_capture } }
646
+ },
647
+ [
648
+ showDOB,
649
+ showTicketHolders,
650
+ canSkipHolderNames,
651
+ customFieldsOrderKeys,
652
+ ticketsQuantity.length,
653
+ emailLogged,
654
+ firstNameLogged,
655
+ lastNameLogged,
656
+ customFieldsTicketHolderKeys,
657
+ ]
658
+ )
659
+
660
+ const removeReferralKey = useCallback(() => {
661
+ localStorage.removeItem('referral_key')
662
+ }, [])
566
663
 
567
- _forEach(customFieldsTicketHolderKeys, customFieldKey => {
568
- const customFieldHolderName = `${customFieldKey}-${holderIndex}`
569
- const customFieldHolderKey = values[customFieldHolderName] || ''
570
- holderDataCapture[customFieldKey] = customFieldHolderKey
664
+ const updateCheckoutWithAddOns = useCallback(
665
+ async (addOns: { [key: string]: number } = {}) => {
666
+ if (!isSinglePageCheckout) return
571
667
 
572
- // Delete holder specific value from values list
573
- delete checkoutBody.attributes[customFieldHolderName]
668
+ const mergedAddOns = { ...singleCheckoutAddons }
669
+
670
+ // Update existing entries and add new ones
671
+ Object.entries(addOns).forEach(([key, value]) => {
672
+ const amount = Number(value)
673
+ if (amount) {
674
+ mergedAddOns[key] = amount
675
+ } else {
676
+ delete mergedAddOns[key]
677
+ }
574
678
  })
575
679
 
576
- // Assign Ticket Holder data_capture final value
577
- if (!_isEmpty(holderDataCapture)) {
578
- holder.ticket_data_capture = holderDataCapture
680
+ try {
681
+ const checkoutUpdateData = {
682
+ attributes: {
683
+ event_id: eventId,
684
+ add_ons: mergedAddOns,
685
+ },
686
+ }
687
+
688
+ const checkoutResponse = await updateCheckout(checkoutUpdateData)
689
+
690
+ if (checkoutResponse.success) {
691
+ const checkoutDataObj = _get(
692
+ checkoutResponse,
693
+ 'data.attributes.cart_price_breakdown',
694
+ {}
695
+ )
696
+ setCheckoutData(checkoutDataObj)
697
+ onCheckoutUpdateSuccess(checkoutResponse.data.attributes)
698
+ setSingleCheckoutAddOns(mergedAddOns)
699
+ }
700
+ } catch (error) {
701
+ const errorMessage = _get(
702
+ error,
703
+ 'response.data.message',
704
+ 'Failed to update add-ons'
705
+ )
706
+ setError(errorMessage)
707
+ onCheckoutUpdateError(error as AxiosError)
579
708
  }
580
- })
709
+ },
710
+ [eventId, isSinglePageCheckout, onCheckoutUpdateError, onCheckoutUpdateSuccess]
711
+ )
581
712
 
582
- return { attributes: { ...checkoutBody.attributes, data_capture } }
583
- }
713
+ const handleAddOnSelect = useCallback(
714
+ async (selectedAddOns: { [key: string]: number }) => {
715
+ await updateCheckoutWithAddOns(selectedAddOns)
716
+ },
717
+ [updateCheckoutWithAddOns]
718
+ )
584
719
 
585
- const removeReferralKey = () => {
586
- localStorage.removeItem('referral_key')
587
- }
720
+ const onAddOnSelect = useCallback(
721
+ (id: string, value: string, addon: any) => {
722
+ const quantity = parseInt(value) || 0
723
+ const addonId = addon.id || id
724
+
725
+ // Create updated add-ons object
726
+ const updatedAddOns: { [key: string]: number } = {}
727
+ updatedAddOns[addonId] = quantity
728
+
729
+ // Call handleAddOnSelect with the updated addons object
730
+ handleAddOnSelect(updatedAddOns)
731
+ },
732
+ [handleAddOnSelect]
733
+ )
588
734
 
589
735
  if (loading || (enableTimer && !expirationTime && isBrowser)) {
590
736
  if (expirationTime === 0) {
@@ -602,6 +748,13 @@ const BillingInfoContainer = React.memo(
602
748
  if (isTable) {
603
749
  dataWithUniqueIds[0].label = 'Get Your Tables'
604
750
  }
751
+
752
+ const stripePublishableKey =
753
+ reviewData?.payment_method?.stripe_publishable_key ||
754
+ checkoutUpdateData?.additional_payment_information?.basic_config?.apiKey
755
+ const stripeAccountId = reviewData?.payment_method?.stripe_connected_account ||
756
+ checkoutUpdateData?.additional_payment_information?.basic_config?.accountId
757
+
605
758
  return (
606
759
  <ThemeProvider theme={themeMui}>
607
760
  {(loading || cardLoading || isCountriesLoading || isConfigLoading) && (
@@ -616,6 +769,7 @@ const BillingInfoContainer = React.memo(
616
769
  <TimerWidget
617
770
  expires_at={expirationTime}
618
771
  onCountdownFinish={onCountdownFinish}
772
+ container={isSinglePageCheckout ? 'body' : ''}
619
773
  />
620
774
  )}
621
775
  {!isCountriesLoading && !isConfigLoading && (
@@ -625,7 +779,7 @@ const BillingInfoContainer = React.memo(
625
779
  {
626
780
  country: initialCountry,
627
781
  state: _get(userData, 'stateId', '') || '1',
628
- brand_opt_in: optedInFieldValue,
782
+ brand_opt_in: Boolean(optedInFieldValue),
629
783
  ttf_opt_in: ttfOptIn,
630
784
  data_capture: {
631
785
  instagram: _get(extraData, 'data_capture.instagram', ''),
@@ -642,6 +796,31 @@ const BillingInfoContainer = React.memo(
642
796
  enableReinitialize={false}
643
797
  onSubmit={async (values, formikHelpers) => {
644
798
  try {
799
+ if ((!cardRef.current || !stripeRef.current) && !orderIsFree) {
800
+ setError('Fill in the card details')
801
+ return
802
+ }
803
+
804
+ let stripePaymentMethod = null
805
+
806
+ if (isSinglePageCheckout && !orderIsFree) {
807
+ const card = cardRef.current
808
+ const stripePaymentMethodResponse = await stripeRef.current.createPaymentMethod({
809
+ type: 'card',
810
+ card: card || { token: '' },
811
+ billing_details: {
812
+ address: addressRef.current,
813
+ },
814
+ })
815
+
816
+ if (stripePaymentMethodResponse?.error) {
817
+ setError('' + stripePaymentMethodResponse?.error?.message)
818
+ return
819
+ }
820
+
821
+ stripePaymentMethod = stripePaymentMethodResponse.paymentMethod
822
+ }
823
+
645
824
  if (isBrowser) {
646
825
  window.localStorage.setItem(
647
826
  'extraData',
@@ -659,124 +838,217 @@ const BillingInfoContainer = React.memo(
659
838
  })
660
839
  )
661
840
  }
662
- if (isLoggedIn) {
663
- const checkoutBody = collectCheckoutBody(values, userData)
664
-
665
- if (isBrowser) {
666
- addAddOnsInAttributes(checkoutBody)
667
- }
668
841
 
669
- const checkoutResponse = await postOnCheckout(
670
- checkoutBody,
842
+ if (!isLoggedIn) {
843
+ const checkoutBodyForRegistration = createCheckoutDataBody(
844
+ ticketsQuantity.length,
845
+ values,
846
+ { emailLogged, firstNameLogged, lastNameLogged },
847
+ showDOB
848
+ )
849
+ const bodyFormData = createRegisterFormData(
850
+ values,
851
+ checkoutBodyForRegistration,
671
852
  flagFreeTicket
672
853
  )
673
- removeReferralKey()
674
- // After checkout is successful recover updated profile and store it on local storage if needed
675
- if (isBrowser) {
676
- const updatedUserData = await getProfileData()
677
- const profileSpecifiedData = _get(updatedUserData, 'data')
678
- const profileDataObj = setLoggedUserData(profileSpecifiedData)
679
- window.localStorage.setItem(
680
- 'user_data',
681
- JSON.stringify(profileDataObj)
854
+ try {
855
+ setLoading(true)
856
+ const resRegister = await register(bodyFormData)
857
+ const xtfCookie = _get(resRegister, 'headers.x-tf-ecommerce')
858
+ const refreshToken = _get(
859
+ resRegister,
860
+ 'data.attributes.refresh_token'
682
861
  )
683
- }
862
+ const userProfile = _get(resRegister, 'data.attributes.user_profile')
684
863
 
685
- handleSubmit(
686
- values,
687
- formikHelpers as FormikHelpers<any>,
688
- eventId,
689
- checkoutResponse
690
- )
691
- return
692
- }
693
- const checkoutBodyForRegistration = createCheckoutDataBody(
694
- ticketsQuantity.length,
695
- values,
696
- { emailLogged, firstNameLogged, lastNameLogged },
697
- showDOB
698
- )
699
- const bodyFormData = createRegisterFormData(
700
- values,
701
- checkoutBodyForRegistration,
702
- flagFreeTicket
703
- )
704
- try {
705
- setLoading(true)
706
- const resRegister = await register(bodyFormData)
707
- const xtfCookie = _get(resRegister, 'headers.x-tf-ecommerce')
708
- const refreshToken = _get(resRegister, 'data.attributes.refresh_token')
709
- const userProfile = _get(resRegister, 'data.attributes.user_profile')
710
-
711
- setIsNewUser(true)
712
- onRegisterSuccess({
713
- xtfCookie,
714
- refreshToken,
715
- userProfile,
716
- })
717
- } catch (e) {
718
- setLoading(false)
719
-
720
- if (e.response?.data?.data?.hasUnverifiedOrder) {
721
- setPendingVerificationMessage(e.response?.data?.message)
722
- } else if (axios.isAxiosError(e)) {
723
- const error = e?.response?.data?.message
724
- if (_includes(error, 'You must be aged')) {
725
- formikHelpers.setFieldError('holderAge', error)
726
- }
727
- if (error?.password) {
728
- formikHelpers.setFieldError('password', error.password)
729
- formikHelpers.setFieldError('confirmPassword', error.password)
730
- }
731
- if (error?.email && !onLogin) {
732
- // False will stand for outside controll
733
- setAlreadyHasUser(true)
734
- setShowModalLogin(true)
735
- }
864
+ setIsNewUser(true)
865
+ onRegisterSuccess({
866
+ xtfCookie,
867
+ refreshToken,
868
+ userProfile,
869
+ })
870
+ } catch (e) {
871
+ setLoading(false)
872
+ const hasUnverifiedOrder = _get(
873
+ e,
874
+ 'response.data.data.hasUnverifiedOrder'
875
+ )
876
+ const message = _get(e, 'response.data.message', {}) as
877
+ | { password?: string | null, email?: string | null }
878
+ | string
736
879
 
737
- if (
738
- _includes(error, 'The cart is expired') &&
739
- !hideErrorsAlertSection
740
- ) {
741
- setError(error)
742
- }
880
+ if (hasUnverifiedOrder && typeof message === 'string') {
881
+ setPendingVerificationMessage(message)
882
+ } else if (axios.isAxiosError(e)) {
883
+ if (
884
+ _includes(message, 'You must be aged') &&
885
+ typeof message === 'string'
886
+ ) {
887
+ formikHelpers.setFieldError('holderAge', message)
888
+ }
889
+ if (typeof message !== 'string' && message?.password) {
890
+ formikHelpers.setFieldError('password', message.password)
891
+ formikHelpers.setFieldError('confirmPassword', message.password)
892
+ }
893
+ if (typeof message !== 'string' && message?.email && !onLogin) {
894
+ // False will stand for outside controll
895
+ setAlreadyHasUser(true)
896
+ setShowModalLogin(true)
897
+ }
898
+
899
+ if (
900
+ _includes(error, 'The cart is expired') &&
901
+ !hideErrorsAlertSection
902
+ ) {
903
+ setError(error)
904
+ }
743
905
 
744
- onRegisterError(e, values.email)
906
+ onRegisterError(e, values.email)
907
+ }
908
+ return
745
909
  }
746
- return
747
910
  }
911
+
748
912
  const profileData = await getProfileData()
749
913
  const profileSpecifiedData = _get(profileData, 'data')
750
914
  const profileDataObj = setLoggedUserData(profileSpecifiedData)
915
+ const userDataObj = isLoggedIn ? userData : profileDataObj
916
+
751
917
  if (isBrowser) {
752
- window.localStorage.setItem('user_data', JSON.stringify(profileDataObj))
918
+ window.localStorage.setItem('user_data', JSON.stringify(userDataObj))
753
919
  }
754
920
 
755
- const checkoutBody = collectCheckoutBody(values, profileDataObj)
921
+ const checkoutBody = collectCheckoutBody(values, userDataObj)
756
922
 
757
- if (isBrowser) {
923
+ if (isBrowser && !isSinglePageCheckout) {
758
924
  addAddOnsInAttributes(checkoutBody)
759
925
  }
760
926
 
927
+ if (isSinglePageCheckout) {
928
+ checkoutBody.attributes.add_ons = singleCheckoutAddons
929
+ }
930
+
761
931
  const checkoutResponse = await postOnCheckout(
762
932
  checkoutBody,
763
933
  flagFreeTicket
764
934
  )
935
+
936
+ const checkoutUpdateResponse = await updateCheckout({
937
+ attributes: {
938
+ event_id: eventId,
939
+ },
940
+ })
941
+
942
+ let paymentResponse = null
943
+
944
+ if (isSinglePageCheckout) {
945
+ const { hash, total } = checkoutResponse.data.attributes
946
+ localStorage.setItem('checkoutData', JSON.stringify({ hash, total }))
947
+
948
+ const paymentDataResponse = await getPaymentData(String(hash))
949
+
950
+ if (paymentDataResponse.success) {
951
+ const { attributes } = paymentDataResponse.data
952
+ setReviewData(attributes)
953
+
954
+ const { order_details, cart } = attributes
955
+ const {
956
+ tickets: [ticket],
957
+ } = order_details
958
+
959
+ const updatedOrderData = {
960
+ add_ons: order_details.add_ons || [],
961
+ total: order_details.total,
962
+ subtotal: order_details.subtotal,
963
+ fees: order_details.fees,
964
+ pay_now: order_details.pay_now || '',
965
+
966
+ id: order_details?.id,
967
+ product_name: cart[0]?.product_name,
968
+ ticketType: ticket?.name,
969
+ quantity: ticket?.quantity,
970
+ price: ticket?.price,
971
+ currency: order_details?.currency,
972
+ guest_count: order_details?.guest_count || '',
973
+ debt: order_details?.debt || null,
974
+ cost: ticket?.cost,
975
+ }
976
+
977
+ const isFreeTickets =
978
+ (!Number(total) && !Number(updatedOrderData.total)) ||
979
+ !Number(updatedOrderData?.pay_now || 0)
980
+ const paymentMethod = attributes.payment_method || {}
981
+ const paymentPlanAvailable = paymentMethod.stripe_payment_plan_enabled
982
+
983
+ if (!isFreeTickets) {
984
+ if (!stripePaymentMethod) {
985
+ setError('Fill in the card details')
986
+ return
987
+ }
988
+
989
+ const confirmationResult = await stripeRef.current.confirmCardPayment(
990
+ paymentMethod.stripe_client_secret,
991
+ {
992
+ payment_method: stripePaymentMethod.id,
993
+ }
994
+ )
995
+
996
+ if (confirmationResult?.error) {
997
+ setError('' + confirmationResult?.error?.message)
998
+ return
999
+ }
1000
+ }
1001
+
1002
+ await handlePaymentMiddleWare(
1003
+ null,
1004
+ {},
1005
+ {
1006
+ reviewData: attributes,
1007
+ isFreeTickets,
1008
+ paymentPlanIsAvailable: paymentPlanAvailable,
1009
+ showPaymentPlanSection: true,
1010
+ handlePayment: (data: any) => {
1011
+ paymentResponse = data
1012
+ },
1013
+ setPaymentIsLoading: _identity,
1014
+ setError: _identity,
1015
+ orderData: updatedOrderData,
1016
+ eventId,
1017
+ isBrowser,
1018
+ onPaymentError: (error: any) => {
1019
+ throw error
1020
+ },
1021
+ }
1022
+ )
1023
+ }
1024
+ }
1025
+
765
1026
  removeReferralKey()
766
1027
  handleSubmit(
767
1028
  values,
768
1029
  formikHelpers as FormikHelpers<any>,
769
1030
  eventId,
770
- checkoutResponse
1031
+ checkoutResponse,
1032
+ checkoutUpdateResponse,
1033
+ paymentResponse
771
1034
  )
772
1035
  } catch (e) {
773
1036
  setLoading(false)
774
- if (e.response?.data?.data?.hasUnverifiedOrder) {
775
- setPendingVerificationMessage(e.response?.data?.message)
1037
+ onSubmitError(e as AxiosError)
1038
+ const hasUnverifiedOrder = _get(
1039
+ e,
1040
+ 'response.data.data.hasUnverifiedOrder'
1041
+ )
1042
+ const message = _get(e, 'response.data.message', {}) as
1043
+ | { password?: string | null, email?: string | null }
1044
+ | string
1045
+
1046
+ if (hasUnverifiedOrder && typeof message === 'string') {
1047
+ setPendingVerificationMessage(message)
776
1048
  } else if (axios.isAxiosError(e)) {
777
1049
  if (
778
1050
  e.response?.status === 401 ||
779
- e.response?.data?.error === 'invalid_token'
1051
+ _get(e, 'response.data.error') === 'invalid_token'
780
1052
  ) {
781
1053
  if (isBrowser) {
782
1054
  window.localStorage.removeItem('user_data')
@@ -790,8 +1062,8 @@ const BillingInfoContainer = React.memo(
790
1062
  window.document.dispatchEvent(event)
791
1063
  }
792
1064
  }
793
- if (e.response?.data.message && !hideErrorsAlertSection) {
794
- setError(_get(e, 'response.data.message'))
1065
+ if (message && !hideErrorsAlertSection && typeof message === 'string') {
1066
+ setError(message)
795
1067
  }
796
1068
  onSubmitError(e)
797
1069
  }
@@ -806,6 +1078,7 @@ const BillingInfoContainer = React.memo(
806
1078
  <LogicRunner
807
1079
  brandOptIn={brandOptIn}
808
1080
  values={props.values}
1081
+ errors={props.errors}
809
1082
  setStates={setStates}
810
1083
  setFieldValue={props.setFieldValue}
811
1084
  setValues={props.setValues}
@@ -824,7 +1097,7 @@ const BillingInfoContainer = React.memo(
824
1097
  onErrorClose()
825
1098
  }}
826
1099
  />
827
- {!isLoggedIn && (
1100
+ {!isLoggedIn && !isSinglePageCheckout && (
828
1101
  <div className="account-actions-block">
829
1102
  <div className="action-item">
830
1103
  <div>{accountInfoTitle}</div>
@@ -860,180 +1133,146 @@ const BillingInfoContainer = React.memo(
860
1133
  </div>
861
1134
  </div>
862
1135
  )}
863
- {includeAddons ? <AddonsContainter
864
- {...addonsProps ?? {}}
865
- /> : null}
1136
+ {isSinglePageCheckout && eventId ? (
1137
+ <SimpleAddonsContainer
1138
+ {...(addonsProps ?? {})}
1139
+ eventId={eventId}
1140
+ addOnDataWithCustomFields={addOnDataWithCustomFields}
1141
+ configs={configs}
1142
+ onAddOnSelect={onAddOnSelect}
1143
+ />
1144
+ ) : includeAddons ? (
1145
+ <AddonsContainter
1146
+ {...(addonsProps ?? {})}
1147
+ addOnDataWithCustomFields={addOnDataWithCustomFields}
1148
+ configs={configs}
1149
+ onAddOnSelect={onAddOnSelect}
1150
+ />
1151
+ ) : null}
866
1152
  {!cardLoading &&
867
1153
  _map(dataWithUniqueIds, item => {
868
1154
  const { label, labelClassName, fields } = item
869
1155
  return (
870
- <React.Fragment key={item.uniqueId}>
1156
+ <div key={item.uniqueId} className="billing-info-fields">
871
1157
  <p className={labelClassName}>{label}</p>
872
1158
  {_map(fields, group => {
873
1159
  const { groupClassname, groupItems } = group
1160
+ const filteredGroupItems = filterBillingInfoFields(
1161
+ groupItems,
1162
+ {
1163
+ showDOB: Boolean(showDOB),
1164
+ hideTtfOptIn: Boolean(hideTtfOptIn),
1165
+ hidePhoneField: Boolean(hidePhoneField),
1166
+ flagRequirePhone: Boolean(flagRequirePhone),
1167
+ collectMandatoryWalletAddress: Boolean(
1168
+ collectMandatoryWalletAddress
1169
+ ),
1170
+ collectMandatoryJobTitle: Boolean(
1171
+ collectMandatoryJobTitle
1172
+ ),
1173
+ collectMandatoryBusinessCategory: Boolean(
1174
+ collectMandatoryBusinessCategory
1175
+ ),
1176
+ collectMandatoryCompany: Boolean(collectMandatoryCompany),
1177
+ collectMandatoryInstagram: Boolean(
1178
+ collectMandatoryInstagram
1179
+ ),
1180
+ flagFreeTicket: Boolean(flagFreeTicket),
1181
+ hideWalletAddressField: Boolean(hideWalletAddressField),
1182
+ hideJobTitleField: Boolean(hideJobTitleField),
1183
+ hideBusinessCategoryField: Boolean(
1184
+ hideBusinessCategoryField
1185
+ ),
1186
+ hideCompanyField: Boolean(hideCompanyField),
1187
+ hideInstagramField,
1188
+ }
1189
+ )
874
1190
  return (
875
1191
  <React.Fragment key={group.uniqueId}>
876
1192
  <div className={groupClassname}>
877
- {_map(
878
- groupItems.filter(el => {
879
- if (el.name === 'holderAge' && !showDOB) {
880
- return false
881
- }
882
- if (el.name === 'ttf_opt_in' && hideTtfOptIn) {
883
- return false
884
- }
885
- if (el.name === 'phone') {
886
- if (!hidePhoneField) {
887
- el.required = flagRequirePhone
888
- } else {
889
- return false
890
- }
891
- }
892
- if (el.name === 'data_capture[wallet_address]') {
893
- if (collectMandatoryWalletAddress) {
894
- el.required = true
895
- }
896
- }
897
- if (el.name === 'data_capture[jobTitle]') {
898
- if (collectMandatoryJobTitle) {
899
- el.required = true
900
- }
901
- }
902
- if (el.name === 'data_capture[businessCategory]') {
903
- if (collectMandatoryBusinessCategory) {
904
- el.required = true
905
- }
906
- }
907
- if (el.name === 'data_capture[company]') {
908
- if (collectMandatoryCompany) {
909
- el.required = true
910
- }
911
- }
912
- if (el.name === 'data_capture[instagram]') {
913
- if (collectMandatoryInstagram) {
914
- el.required = true
915
- }
916
- }
917
- if (
918
- [
919
- 'street_address',
920
- 'country',
921
- 'state',
922
- 'city',
923
- ].includes(el.name)
924
- ) {
925
- if (flagFreeTicket) {
926
- el.required = false
927
- return false
928
- }
929
- }
930
- if (
931
- hideWalletAddressField &&
932
- (el.name === 'wallet-address-info' ||
933
- el.name === 'data_capture[wallet_address]')
934
- ) {
935
- return false
936
- }
937
- if (
938
- hideJobTitleField &&
939
- el.name === 'data_capture[jobTitle]'
940
- ) {
941
- return false
942
- }
943
- if (
944
- hideBusinessCategoryField &&
945
- el.name === 'data_capture[businessCategory]'
946
- ) {
947
- return false
948
- }
949
- if (
950
- hideCompanyField &&
951
- el.name === 'data_capture[company]'
952
- ) {
953
- return false
954
- }
955
- if (
956
- hideInstagramField &&
957
- (el.name === 'data_capture[instagram]' ||
958
- el.name === 'instagram-info')
959
- ) {
960
- return false
961
- }
962
- return true
963
- }),
964
- element =>
965
- [
966
- 'password',
967
- 'confirmPassword',
968
- 'password-info',
969
- ].includes(element.name) && isLoggedIn ? null : (
970
- <React.Fragment key={element.uniqueId}>
971
- <div
972
- className={`${element.className} ${props?.errors[element.name] || ''
973
- }`}
974
- >
975
- {element.component ? (
976
- element.component
1193
+ {_map(filteredGroupItems, element =>
1194
+ [
1195
+ 'password',
1196
+ 'confirmPassword',
1197
+ 'password-info',
1198
+ ].includes(element.name) && isLoggedIn ? null : (
1199
+ <React.Fragment key={element.uniqueId}>
1200
+ <div
1201
+ className={`${element.className} ${
1202
+ props?.errors[element.name] || ''
1203
+ }`}
1204
+ >
1205
+ {element.component ? (
1206
+ typeof element.component === 'function' ? (
1207
+ renderComponentWithProps(
1208
+ element.component as React.ComponentType<any>,
1209
+ element.name === 'payment_info'
1210
+ ? { reviewData }
1211
+ : {}
1212
+ )
977
1213
  ) : (
978
- <Field
979
- {...element}
980
- type={
981
- element.type === 'radio' ||
982
- element.type === 'checkbox'
983
- ? undefined
984
- : element.type
985
- }
986
- setPhoneValidationIsLoading={
987
- element.type === 'phone'
988
- ? setPhoneValidationIsLoading
989
- : undefined
990
- }
991
- label={getFieldLabel(element, configs)}
992
- validate={getValidateFunctions(
993
- element,
994
- states,
995
- props.values,
996
- props.errors
997
- )}
998
- setFieldValue={props.setFieldValue}
999
- onBlur={props.handleBlur}
1000
- component={getFieldComponent(element)}
1001
- selectOptions={
1002
- element.name === 'country'
1003
- ? _map(countries, item => ({
1214
+ element.component
1215
+ )
1216
+ ) : (
1217
+ <Field
1218
+ {...element}
1219
+ type={
1220
+ element.type === 'radio' ||
1221
+ element.type === 'checkbox'
1222
+ ? undefined
1223
+ : element.type
1224
+ }
1225
+ setPhoneValidationIsLoading={
1226
+ element.type === 'phone'
1227
+ ? setPhoneValidationIsLoading
1228
+ : undefined
1229
+ }
1230
+ label={getFieldLabel(element, configs)}
1231
+ validate={getValidateFunctions(
1232
+ element,
1233
+ states,
1234
+ props.values,
1235
+ props.errors
1236
+ )}
1237
+ setFieldValue={props.setFieldValue}
1238
+ onBlur={props.handleBlur}
1239
+ component={getFieldComponent(element)}
1240
+ selectOptions={
1241
+ element.name === 'country'
1242
+ ? _map(countries, item => ({
1004
1243
  value: item.id,
1005
1244
  label: item.name,
1006
1245
  }))
1007
- : element.name === 'state'
1008
- ? [
1009
- {
1010
- label: element.label,
1011
- value: '',
1012
- disabled: true,
1013
- },
1014
- ...states,
1015
- ]
1016
- : element.selectOptions || []
1017
- }
1018
- theme={theme}
1019
- defaultCountry={
1020
- defaultCountry || element.defaultCountry
1021
- }
1022
- dateFormat={element.format}
1023
- isCountryCodeEditable={
1024
- isCountryCodeEditable
1025
- }
1026
- />
1027
- )}
1028
- </div>
1029
- </React.Fragment>
1030
- )
1246
+ : element.name === 'state'
1247
+ ? [
1248
+ {
1249
+ label: element.label,
1250
+ value: '',
1251
+ disabled: true,
1252
+ },
1253
+ ...states,
1254
+ ]
1255
+ : element.selectOptions || []
1256
+ }
1257
+ theme={theme}
1258
+ defaultCountry={
1259
+ defaultCountry || element.defaultCountry
1260
+ }
1261
+ dateFormat={element.format}
1262
+ isCountryCodeEditable={
1263
+ isCountryCodeEditable
1264
+ }
1265
+ />
1266
+ )}
1267
+ </div>
1268
+ </React.Fragment>
1269
+ )
1031
1270
  )}
1032
1271
  </div>
1033
1272
  </React.Fragment>
1034
1273
  )
1035
1274
  })}
1036
- </React.Fragment>
1275
+ </div>
1037
1276
  )
1038
1277
  })}
1039
1278
  {!_isEmpty(ticketHoldersFields.fields) && (
@@ -1053,7 +1292,7 @@ const BillingInfoContainer = React.memo(
1053
1292
  {...element}
1054
1293
  type={
1055
1294
  element.type === 'radio' ||
1056
- element.type === 'checkbox'
1295
+ element.type === 'checkbox'
1057
1296
  ? undefined
1058
1297
  : element.type
1059
1298
  }
@@ -1084,6 +1323,74 @@ const BillingInfoContainer = React.memo(
1084
1323
  ))}
1085
1324
  </div>
1086
1325
  )}
1326
+ {isSinglePageCheckout && !orderIsFree && stripePublishableKey && (
1327
+ <PaymentContainer
1328
+ stripePublishableKey={stripePublishableKey}
1329
+ stripeAccountId={stripeAccountId}
1330
+ formTitle="Payment Information"
1331
+ orderInfoLabel=""
1332
+ enableTimer={false}
1333
+ checkoutData={checkoutData}
1334
+ paymentFields={paymentProps.paymentFields || []}
1335
+ onPaymentError={paymentProps.onPaymentError || _identity}
1336
+ handlePayment={paymentProps.handlePayment || _identity}
1337
+ onGetPaymentDataSuccess={
1338
+ paymentProps.onGetPaymentDataSuccess || _identity
1339
+ }
1340
+ onGetPaymentDataError={
1341
+ paymentProps.onGetPaymentDataError || _identity
1342
+ }
1343
+ themeOptions={themeOptions}
1344
+ paymentInfoLabel=""
1345
+ displayPaymentButton={false}
1346
+ hidePaymentForm={false}
1347
+ hideFieldsBlock={true}
1348
+ isSinglePageCheckout={true}
1349
+ stripePaymentProps={{
1350
+ stripeCardOptions: {
1351
+ style: {
1352
+ base: {
1353
+ fontFamily: 'OpenGround',
1354
+ fontSize: '14px',
1355
+ lineHeight: '20px',
1356
+ fontWeight: 600,
1357
+ color: '#000',
1358
+ backgroundColor: '#fff',
1359
+ ':-webkit-autofill': {
1360
+ color: '#000',
1361
+ },
1362
+ '::placeholder': {
1363
+ color: 'rgba(201, 201, 201, 0.5)',
1364
+ },
1365
+ },
1366
+ invalid: {
1367
+ color: '#E53935',
1368
+ },
1369
+ },
1370
+ },
1371
+ disableZipSection: true,
1372
+ paymentButtonText: '',
1373
+ enableAddressElement: false,
1374
+ onPaymentFieldsUpdate: async (
1375
+ _error,
1376
+ paymentFieldsData,
1377
+ stripe,
1378
+ card
1379
+ ) => {
1380
+ try {
1381
+ const address = {
1382
+ city: paymentFieldsData?.billing_info?.city,
1383
+ line1: paymentFieldsData?.billing_info?.street_address,
1384
+ state: paymentFieldsData?.billing_info?.state,
1385
+ }
1386
+ addressRef.current = address
1387
+ cardRef.current = card
1388
+ stripeRef.current = stripe
1389
+ } catch (error) {}
1390
+ },
1391
+ }}
1392
+ />
1393
+ )}
1087
1394
  <div className="button-container">
1088
1395
  <Button
1089
1396
  type="submit"
@@ -1091,7 +1398,13 @@ const BillingInfoContainer = React.memo(
1091
1398
  className="login-register-button"
1092
1399
  disabled={props.isSubmitting || phoneValidationIsLoading}
1093
1400
  >
1094
- {props.isSubmitting ? <CircularProgress size={26} /> : buttonName}
1401
+ {props.isSubmitting ? (
1402
+ <CircularProgress size={26} />
1403
+ ) : orderIsFree ? (
1404
+ freeOrderButtonName
1405
+ ) : (
1406
+ buttonName
1407
+ )}
1095
1408
  </Button>
1096
1409
  </div>
1097
1410
  </div>
@@ -1156,6 +1469,7 @@ const BillingInfoContainer = React.memo(
1156
1469
  onForgotPasswordSuccess={onForgotPasswordSuccess}
1157
1470
  onForgotPasswordError={onForgotPasswordError}
1158
1471
  showPoweredByImage={showPoweredByImage}
1472
+ displaySuccessMessage
1159
1473
  />
1160
1474
  )}
1161
1475
  <VerificationPendingModal