tf-checkout-react 1.7.30 → 2.0.0-beta.0

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 (453) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +141 -1033
  3. package/dist/checkout.css +17 -0
  4. package/dist/index.d.mts +3930 -0
  5. package/dist/index.d.ts +3930 -30
  6. package/dist/index.esm.js +9123 -0
  7. package/dist/index.esm.js.map +1 -0
  8. package/dist/index.js +9277 -6
  9. package/dist/index.js.map +1 -0
  10. package/dist/styles/addons.css +75 -0
  11. package/dist/styles/auth.css +294 -0
  12. package/dist/styles/billing.css +98 -0
  13. package/dist/styles/confirmation.css +51 -0
  14. package/dist/styles/foundation.css +146 -0
  15. package/dist/styles/payment.css +179 -0
  16. package/dist/styles/primitives.css +356 -0
  17. package/dist/styles/seat-map.css +46 -0
  18. package/dist/styles/tickets.css +285 -0
  19. package/dist/styles/verification-confirmation.css +258 -0
  20. package/package.json +93 -78
  21. package/src/.d.ts +1 -1
  22. package/src/CardInput.tsx +374 -0
  23. package/src/EmbeddedCheckout.tsx +400 -0
  24. package/src/ResumedCheckout.tsx +132 -0
  25. package/src/auth/AuthModal.tsx +231 -0
  26. package/src/auth/ForgotPasswordForm.tsx +93 -0
  27. package/src/auth/LoginForm.tsx +104 -0
  28. package/src/auth/PasswordInput.tsx +33 -0
  29. package/src/auth/RegisterForm.tsx +333 -0
  30. package/src/auth/ResetPasswordForm.tsx +112 -0
  31. package/src/auth/index.ts +5 -0
  32. package/src/checkout.css +17 -0
  33. package/src/configure.ts +29 -0
  34. package/src/confirmer.ts +439 -0
  35. package/src/index.ts +41 -30
  36. package/src/instance.ts +21 -0
  37. package/src/sections/AddOns.tsx +241 -0
  38. package/src/sections/BillingInfo.tsx +743 -0
  39. package/src/sections/Confirmation.tsx +146 -0
  40. package/src/sections/IDVerification.tsx +76 -0
  41. package/src/sections/OrderConfirmation.tsx +277 -0
  42. package/src/sections/OrderIDVerification.tsx +117 -0
  43. package/src/sections/OrderSummary.tsx +84 -0
  44. package/src/sections/Payment.tsx +541 -0
  45. package/src/sections/SeatMap.tsx +512 -0
  46. package/src/sections/Tickets.tsx +573 -0
  47. package/src/sections/billing/BillingAddressFields.tsx +138 -0
  48. package/src/sections/billing/BuyerField.tsx +75 -0
  49. package/src/sections/billing/TicketHoldersCard.tsx +119 -0
  50. package/src/sections/billing/types.ts +10 -0
  51. package/src/sections/index.ts +15 -0
  52. package/src/sections/seatMap.utils.ts +105 -0
  53. package/src/styles/addons.css +75 -0
  54. package/src/styles/auth.css +294 -0
  55. package/src/styles/billing.css +98 -0
  56. package/src/styles/confirmation.css +51 -0
  57. package/src/styles/foundation.css +146 -0
  58. package/src/styles/payment.css +179 -0
  59. package/src/styles/primitives.css +356 -0
  60. package/src/styles/seat-map.css +46 -0
  61. package/src/styles/tickets.css +285 -0
  62. package/src/styles/verification-confirmation.css +258 -0
  63. package/src/typings.d.ts +2 -2
  64. package/src/ui/Button.tsx +38 -0
  65. package/src/ui/Card.tsx +54 -0
  66. package/src/ui/CheckoutProvider.tsx +172 -0
  67. package/src/ui/CustomFields.tsx +195 -0
  68. package/src/ui/Field.tsx +114 -0
  69. package/src/ui/I18nProvider.tsx +36 -0
  70. package/src/ui/InstallmentPicker.tsx +69 -0
  71. package/src/ui/Loader.tsx +12 -0
  72. package/src/ui/PaymentMethods.tsx +133 -0
  73. package/src/ui/PriceLine.tsx +24 -0
  74. package/src/ui/QuantitySelect.tsx +50 -0
  75. package/src/ui/Stepper.tsx +36 -0
  76. package/src/ui/Timer.tsx +34 -0
  77. package/src/ui/TimerBanner.tsx +55 -0
  78. package/src/ui/cx.ts +3 -0
  79. package/src/ui/index.ts +54 -0
  80. package/src/ui/theme.ts +83 -0
  81. package/src/useCheckout.ts +35 -0
  82. package/src/xendit.ts +438 -0
  83. package/dist/adapters/customFields.d.ts +0 -12
  84. package/dist/adapters/index.d.ts +0 -1
  85. package/dist/api/auth.d.ts +0 -27
  86. package/dist/api/cart.d.ts +0 -2
  87. package/dist/api/checkout.d.ts +0 -3
  88. package/dist/api/common.d.ts +0 -11
  89. package/dist/api/guestTicketDelegation.d.ts +0 -47
  90. package/dist/api/index.d.ts +0 -82
  91. package/dist/api/interceptors.d.ts +0 -1
  92. package/dist/api/orders.d.ts +0 -2
  93. package/dist/api/payment.d.ts +0 -5
  94. package/dist/api/preRegistrationComplete.d.ts +0 -3
  95. package/dist/api/publicRequest.d.ts +0 -9
  96. package/dist/api/resale.d.ts +0 -5
  97. package/dist/components/account-settings/index.d.ts +0 -3
  98. package/dist/components/addonsContainer/AddonComponent.d.ts +0 -18
  99. package/dist/components/addonsContainer/SimpleAddonsContainer.d.ts +0 -20
  100. package/dist/components/addonsContainer/adapters/index.d.ts +0 -12
  101. package/dist/components/addonsContainer/index.d.ts +0 -22
  102. package/dist/components/addonsContainer/normalizers/index.d.ts +0 -1
  103. package/dist/components/addonsContainer/useAddons.d.ts +0 -23
  104. package/dist/components/addonsContainer/utils/index.d.ts +0 -16
  105. package/dist/components/billing-info-container/hooks/index.d.ts +0 -3
  106. package/dist/components/billing-info-container/hooks/usePaymentContext.d.ts +0 -5
  107. package/dist/components/billing-info-container/hooks/usePaymentRedirect.d.ts +0 -14
  108. package/dist/components/billing-info-container/hooks/useStripePayment.d.ts +0 -18
  109. package/dist/components/billing-info-container/index.d.ts +0 -69
  110. package/dist/components/billing-info-container/utils.d.ts +0 -59
  111. package/dist/components/common/Checkbox.d.ts +0 -11
  112. package/dist/components/common/CheckboxField/index.d.ts +0 -9
  113. package/dist/components/common/CopyField.d.ts +0 -12
  114. package/dist/components/common/CopyMessageModal.d.ts +0 -7
  115. package/dist/components/common/CustomField.d.ts +0 -26
  116. package/dist/components/common/DatePickerField.d.ts +0 -20
  117. package/dist/components/common/FieldSection/index.d.ts +0 -19
  118. package/dist/components/common/FieldSection/utils/index.d.ts +0 -8
  119. package/dist/components/common/FormikPhoneNumberField.d.ts +0 -11
  120. package/dist/components/common/Loader.d.ts +0 -2
  121. package/dist/components/common/ModalComponent/index.d.ts +0 -16
  122. package/dist/components/common/NativeSelectFeild/index.d.ts +0 -21
  123. package/dist/components/common/PhoneNumberField.d.ts +0 -14
  124. package/dist/components/common/PoweredBy.d.ts +0 -2
  125. package/dist/components/common/RadioField.d.ts +0 -11
  126. package/dist/components/common/RadioGroupField/index.d.ts +0 -17
  127. package/dist/components/common/RedirectModal.d.ts +0 -7
  128. package/dist/components/common/SelectField/index.d.ts +0 -19
  129. package/dist/components/common/SnackbarAlert.d.ts +0 -13
  130. package/dist/components/common/index.d.ts +0 -11
  131. package/dist/components/common/socials.d.ts +0 -10
  132. package/dist/components/confirmModal/index.d.ts +0 -10
  133. package/dist/components/confirmationContainer/config.d.ts +0 -1
  134. package/dist/components/confirmationContainer/index.d.ts +0 -46
  135. package/dist/components/confirmationContainer/social-buttons.d.ts +0 -16
  136. package/dist/components/countdown/index.d.ts +0 -14
  137. package/dist/components/delegationsContainer/IssueComponent.d.ts +0 -10
  138. package/dist/components/delegationsContainer/IssueTicketForm.d.ts +0 -9
  139. package/dist/components/delegationsContainer/TicketsAssignedTable.d.ts +0 -11
  140. package/dist/components/delegationsContainer/TicketsAvailableTable.d.ts +0 -11
  141. package/dist/components/delegationsContainer/index.d.ts +0 -10
  142. package/dist/components/forgotPasswordModal/index.d.ts +0 -12
  143. package/dist/components/idVerificationContainer/VerificationPendingModal.d.ts +0 -10
  144. package/dist/components/idVerificationContainer/constants.d.ts +0 -21
  145. package/dist/components/idVerificationContainer/index.d.ts +0 -16
  146. package/dist/components/index.d.ts +0 -12
  147. package/dist/components/loginForm/index.d.ts +0 -31
  148. package/dist/components/loginModal/SignUpForm.d.ts +0 -10
  149. package/dist/components/loginModal/constants.d.ts +0 -39
  150. package/dist/components/loginModal/index.d.ts +0 -22
  151. package/dist/components/myTicketsContainer/index.d.ts +0 -16
  152. package/dist/components/myTicketsContainer/row.d.ts +0 -3
  153. package/dist/components/myTicketsContainer/tableConfig.d.ts +0 -5
  154. package/dist/components/orderDetailsContainer/CustomFieldsForm.d.ts +0 -12
  155. package/dist/components/orderDetailsContainer/TicketHolderCustomFields.d.ts +0 -10
  156. package/dist/components/orderDetailsContainer/index.d.ts +0 -66
  157. package/dist/components/orderDetailsContainer/ticketsTable.d.ts +0 -46
  158. package/dist/components/orderDetailsContainer/utils/index.d.ts +0 -6
  159. package/dist/components/paymentContainer/OrderDetails.d.ts +0 -9
  160. package/dist/components/paymentContainer/PaymentPlanSection.d.ts +0 -10
  161. package/dist/components/paymentContainer/handlePayment.d.ts +0 -15
  162. package/dist/components/paymentContainer/index.d.ts +0 -39
  163. package/dist/components/preRegistration/FieldsSection.d.ts +0 -19
  164. package/dist/components/preRegistration/Influancers.d.ts +0 -2
  165. package/dist/components/preRegistration/PreRegistrationComplete.d.ts +0 -13
  166. package/dist/components/preRegistration/PreRegistrationInformations.d.ts +0 -2
  167. package/dist/components/preRegistration/Prewards.d.ts +0 -2
  168. package/dist/components/preRegistration/ShareOptions.d.ts +0 -2
  169. package/dist/components/preRegistration/constants.d.ts +0 -2
  170. package/dist/components/preRegistration/index.d.ts +0 -23
  171. package/dist/components/preRegistration/utils.d.ts +0 -12
  172. package/dist/components/registerForm/adapters/index.d.ts +0 -4
  173. package/dist/components/registerForm/constants.d.ts +0 -1
  174. package/dist/components/registerForm/index.d.ts +0 -16
  175. package/dist/components/registerModal/index.d.ts +0 -12
  176. package/dist/components/resetPasswordContainer/index.d.ts +0 -10
  177. package/dist/components/rsvpContainer/index.d.ts +0 -7
  178. package/dist/components/seatMapContainer/SeatMapComponent.d.ts +0 -8
  179. package/dist/components/seatMapContainer/TicketsSection.d.ts +0 -9
  180. package/dist/components/seatMapContainer/addToCart.d.ts +0 -14
  181. package/dist/components/seatMapContainer/index.d.ts +0 -2
  182. package/dist/components/seatMapContainer/utils.d.ts +0 -6
  183. package/dist/components/signupModal/index.d.ts +0 -12
  184. package/dist/components/ticketResale/index.d.ts +0 -12
  185. package/dist/components/ticketResaleModal/index.d.ts +0 -19
  186. package/dist/components/ticketsContainer/AccessCodeSection.d.ts +0 -7
  187. package/dist/components/ticketsContainer/InfoIcon.d.ts +0 -5
  188. package/dist/components/ticketsContainer/PromoCodeSection.d.ts +0 -15
  189. package/dist/components/ticketsContainer/ReferralLogic.d.ts +0 -5
  190. package/dist/components/ticketsContainer/TicketRow.d.ts +0 -13
  191. package/dist/components/ticketsContainer/TicketsSection.d.ts +0 -20
  192. package/dist/components/ticketsContainer/TimeSlotTicketRow.d.ts +0 -19
  193. package/dist/components/ticketsContainer/TimeSlotsSection.d.ts +0 -25
  194. package/dist/components/ticketsContainer/index.d.ts +0 -93
  195. package/dist/components/ticketsContainer/utils.d.ts +0 -13
  196. package/dist/components/timerWidget/index.d.ts +0 -16
  197. package/dist/components/waitingList/index.d.ts +0 -9
  198. package/dist/constants/index.d.ts +0 -7
  199. package/dist/env.d.ts +0 -16
  200. package/dist/hoc/CustomFields/index.d.ts +0 -3
  201. package/dist/hoc/index.d.ts +0 -1
  202. package/dist/hooks/index.d.ts +0 -1
  203. package/dist/hooks/useCookieListener.d.ts +0 -1
  204. package/dist/hooks/useEventListener.d.ts +0 -1
  205. package/dist/hooks/useLocalStorageListener.d.ts +0 -1
  206. package/dist/hooks/useOnline.d.ts +0 -1
  207. package/dist/hooks/usePixel.d.ts +0 -6
  208. package/dist/images/Polygon.png +0 -0
  209. package/dist/images/cross.svg +0 -44
  210. package/dist/images/done.svg +0 -3
  211. package/dist/images/edit.svg +0 -10
  212. package/dist/images/email.svg +0 -1
  213. package/dist/images/instagram.svg +0 -5
  214. package/dist/images/logo-ttf.png +0 -0
  215. package/dist/images/spotify.svg +0 -6
  216. package/dist/images/user.svg +0 -1
  217. package/dist/images/xmark.svg +0 -92
  218. package/dist/normalizers/index.d.ts +0 -4
  219. package/dist/tf-checkout-react.cjs.development.js +0 -16149
  220. package/dist/tf-checkout-react.cjs.development.js.map +0 -1
  221. package/dist/tf-checkout-react.cjs.production.min.js +0 -2
  222. package/dist/tf-checkout-react.cjs.production.min.js.map +0 -1
  223. package/dist/tf-checkout-react.esm.js +0 -16116
  224. package/dist/tf-checkout-react.esm.js.map +0 -1
  225. package/dist/tf-checkout-styles.css +0 -1
  226. package/dist/types/add_on.d.ts +0 -8
  227. package/dist/types/billing-info-data.d.ts +0 -27
  228. package/dist/types/checkoutPageConfigs.d.ts +0 -13
  229. package/dist/types/index.d.ts +0 -6
  230. package/dist/types/order-data.d.ts +0 -15
  231. package/dist/types/payment-field.d.ts +0 -6
  232. package/dist/types/payment-plan-configuration.d.ts +0 -18
  233. package/dist/types/referral-promotion.d.ts +0 -6
  234. package/dist/types/verification.d.ts +0 -12
  235. package/dist/utils/adaptStripeErrors.d.ts +0 -8
  236. package/dist/utils/auth.d.ts +0 -21
  237. package/dist/utils/cookies.d.ts +0 -3
  238. package/dist/utils/createCheckoutDataBodyWithDefaultHolder.d.ts +0 -23
  239. package/dist/utils/createMarkup.d.ts +0 -3
  240. package/dist/utils/customFields.d.ts +0 -35
  241. package/dist/utils/downloadPDF.d.ts +0 -1
  242. package/dist/utils/form.d.ts +0 -3
  243. package/dist/utils/formikErrorFocus.d.ts +0 -2
  244. package/dist/utils/getDomain.d.ts +0 -1
  245. package/dist/utils/getImage.d.ts +0 -1
  246. package/dist/utils/getQueryVariable.d.ts +0 -1
  247. package/dist/utils/htmlNodeFromString.d.ts +0 -1
  248. package/dist/utils/index.d.ts +0 -15
  249. package/dist/utils/isBrowser.d.ts +0 -1
  250. package/dist/utils/isValidNumber.d.ts +0 -1
  251. package/dist/utils/jsonUtils.d.ts +0 -1
  252. package/dist/utils/replaceVarInString.d.ts +0 -1
  253. package/dist/utils/setConfigs.d.ts +0 -11
  254. package/dist/utils/showZero.d.ts +0 -1
  255. package/dist/validators/index.d.ts +0 -8
  256. package/src/adapters/customFields.ts +0 -85
  257. package/src/adapters/index.ts +0 -1
  258. package/src/api/auth.ts +0 -88
  259. package/src/api/cart.ts +0 -28
  260. package/src/api/checkout.ts +0 -28
  261. package/src/api/common.ts +0 -190
  262. package/src/api/guestTicketDelegation.ts +0 -79
  263. package/src/api/index.ts +0 -346
  264. package/src/api/interceptors.ts +0 -77
  265. package/src/api/orders.ts +0 -30
  266. package/src/api/payment.ts +0 -77
  267. package/src/api/preRegistrationComplete.ts +0 -37
  268. package/src/api/publicRequest.ts +0 -47
  269. package/src/api/resale.ts +0 -28
  270. package/src/assets/images/Polygon.png +0 -0
  271. package/src/assets/images/cross.svg +0 -44
  272. package/src/assets/images/done.svg +0 -3
  273. package/src/assets/images/edit.svg +0 -10
  274. package/src/assets/images/email.svg +0 -1
  275. package/src/assets/images/instagram.svg +0 -5
  276. package/src/assets/images/logo-ttf.png +0 -0
  277. package/src/assets/images/spotify.svg +0 -6
  278. package/src/assets/images/user.svg +0 -1
  279. package/src/assets/images/xmark.svg +0 -92
  280. package/src/components/account-settings/index.tsx +0 -161
  281. package/src/components/account-settings/style.css +0 -200
  282. package/src/components/addonsContainer/AddonComponent.tsx +0 -204
  283. package/src/components/addonsContainer/SimpleAddonsContainer.tsx +0 -459
  284. package/src/components/addonsContainer/adapters/index.tsx +0 -62
  285. package/src/components/addonsContainer/index.tsx +0 -353
  286. package/src/components/addonsContainer/normalizers/index.ts +0 -5
  287. package/src/components/addonsContainer/useAddons.ts +0 -248
  288. package/src/components/addonsContainer/utils/index.tsx +0 -231
  289. package/src/components/billing-info-container/hooks/index.ts +0 -3
  290. package/src/components/billing-info-container/hooks/usePaymentContext.ts +0 -22
  291. package/src/components/billing-info-container/hooks/usePaymentRedirect.ts +0 -145
  292. package/src/components/billing-info-container/hooks/useStripePayment.ts +0 -119
  293. package/src/components/billing-info-container/index.tsx +0 -1695
  294. package/src/components/billing-info-container/style.css +0 -150
  295. package/src/components/billing-info-container/utils.tsx +0 -413
  296. package/src/components/common/Checkbox.tsx +0 -51
  297. package/src/components/common/CheckboxField/index.tsx +0 -41
  298. package/src/components/common/CopyField.tsx +0 -53
  299. package/src/components/common/CopyMessageModal.tsx +0 -34
  300. package/src/components/common/CustomField.tsx +0 -168
  301. package/src/components/common/DatePickerField.tsx +0 -126
  302. package/src/components/common/FieldSection/index.tsx +0 -141
  303. package/src/components/common/FieldSection/utils/index.tsx +0 -92
  304. package/src/components/common/FormikPhoneNumberField.tsx +0 -51
  305. package/src/components/common/Loader.tsx +0 -8
  306. package/src/components/common/ModalComponent/index.tsx +0 -68
  307. package/src/components/common/NativeSelectFeild/index.tsx +0 -86
  308. package/src/components/common/PhoneNumberField.tsx +0 -117
  309. package/src/components/common/PoweredBy.tsx +0 -15
  310. package/src/components/common/RadioField.tsx +0 -36
  311. package/src/components/common/RadioGroupField/index.tsx +0 -76
  312. package/src/components/common/RedirectModal.tsx +0 -43
  313. package/src/components/common/SelectField/index.tsx +0 -104
  314. package/src/components/common/SnackbarAlert.tsx +0 -52
  315. package/src/components/common/index.tsx +0 -11
  316. package/src/components/common/socials.tsx +0 -33
  317. package/src/components/confirmModal/index.tsx +0 -60
  318. package/src/components/confirmationContainer/config.ts +0 -79
  319. package/src/components/confirmationContainer/index.tsx +0 -349
  320. package/src/components/confirmationContainer/social-buttons.tsx +0 -149
  321. package/src/components/confirmationContainer/style.css +0 -206
  322. package/src/components/countdown/index.tsx +0 -100
  323. package/src/components/countdown/style.css +0 -10
  324. package/src/components/delegationsContainer/IssueComponent.tsx +0 -156
  325. package/src/components/delegationsContainer/IssueTicketForm.tsx +0 -109
  326. package/src/components/delegationsContainer/TicketsAssignedTable.tsx +0 -55
  327. package/src/components/delegationsContainer/TicketsAvailableTable.tsx +0 -54
  328. package/src/components/delegationsContainer/index.tsx +0 -83
  329. package/src/components/forgotPasswordModal/index.tsx +0 -138
  330. package/src/components/forgotPasswordModal/style.css +0 -47
  331. package/src/components/idVerificationContainer/VerificationPendingModal.tsx +0 -47
  332. package/src/components/idVerificationContainer/constants.ts +0 -27
  333. package/src/components/idVerificationContainer/index.tsx +0 -323
  334. package/src/components/index.ts +0 -12
  335. package/src/components/loginForm/index.tsx +0 -202
  336. package/src/components/loginModal/SignUpForm.tsx +0 -329
  337. package/src/components/loginModal/constants.ts +0 -46
  338. package/src/components/loginModal/index.tsx +0 -263
  339. package/src/components/loginModal/style.css +0 -116
  340. package/src/components/myTicketsContainer/index.tsx +0 -228
  341. package/src/components/myTicketsContainer/row.tsx +0 -46
  342. package/src/components/myTicketsContainer/style.css +0 -40
  343. package/src/components/myTicketsContainer/tableConfig.tsx +0 -80
  344. package/src/components/myTicketsContainer/types.d.ts +0 -41
  345. package/src/components/orderDetailsContainer/CustomFieldsForm.tsx +0 -75
  346. package/src/components/orderDetailsContainer/TicketHolderCustomFields.tsx +0 -100
  347. package/src/components/orderDetailsContainer/index.tsx +0 -586
  348. package/src/components/orderDetailsContainer/style.css +0 -77
  349. package/src/components/orderDetailsContainer/ticketsTable.tsx +0 -246
  350. package/src/components/orderDetailsContainer/utils/index.tsx +0 -55
  351. package/src/components/paymentContainer/OrderDetails.tsx +0 -277
  352. package/src/components/paymentContainer/PaymentPlanSection.tsx +0 -169
  353. package/src/components/paymentContainer/handlePayment.ts +0 -86
  354. package/src/components/paymentContainer/index.tsx +0 -643
  355. package/src/components/paymentContainer/style.css +0 -196
  356. package/src/components/preRegistration/FieldsSection.tsx +0 -150
  357. package/src/components/preRegistration/Influancers.tsx +0 -34
  358. package/src/components/preRegistration/PreRegistrationComplete.tsx +0 -186
  359. package/src/components/preRegistration/PreRegistrationInformations.tsx +0 -60
  360. package/src/components/preRegistration/Prewards.tsx +0 -41
  361. package/src/components/preRegistration/ShareOptions.tsx +0 -77
  362. package/src/components/preRegistration/constants.tsx +0 -169
  363. package/src/components/preRegistration/index.tsx +0 -330
  364. package/src/components/preRegistration/style.css +0 -3
  365. package/src/components/preRegistration/utils.ts +0 -163
  366. package/src/components/registerForm/adapters/index.tsx +0 -10
  367. package/src/components/registerForm/constants.tsx +0 -98
  368. package/src/components/registerForm/index.tsx +0 -188
  369. package/src/components/registerModal/index.tsx +0 -154
  370. package/src/components/registerModal/style.css +0 -18
  371. package/src/components/resetPasswordContainer/index.tsx +0 -102
  372. package/src/components/resetPasswordContainer/style.css +0 -36
  373. package/src/components/rsvpContainer/index.tsx +0 -126
  374. package/src/components/seatMapContainer/SeatMapComponent.tsx +0 -77
  375. package/src/components/seatMapContainer/TicketsSection.tsx +0 -286
  376. package/src/components/seatMapContainer/addToCart.ts +0 -66
  377. package/src/components/seatMapContainer/index.tsx +0 -443
  378. package/src/components/seatMapContainer/utils.ts +0 -133
  379. package/src/components/signupModal/index.tsx +0 -178
  380. package/src/components/signupModal/style.css +0 -58
  381. package/src/components/ticketResale/index.tsx +0 -86
  382. package/src/components/ticketResaleModal/index.tsx +0 -224
  383. package/src/components/ticketResaleModal/style.css +0 -28
  384. package/src/components/ticketsContainer/AccessCodeSection.tsx +0 -50
  385. package/src/components/ticketsContainer/InfoIcon.tsx +0 -35
  386. package/src/components/ticketsContainer/PromoCodeSection.tsx +0 -116
  387. package/src/components/ticketsContainer/ReferralLogic.tsx +0 -33
  388. package/src/components/ticketsContainer/TicketRow.tsx +0 -107
  389. package/src/components/ticketsContainer/TicketsSection.tsx +0 -350
  390. package/src/components/ticketsContainer/TimeSlotTicketRow.tsx +0 -243
  391. package/src/components/ticketsContainer/TimeSlotsSection.tsx +0 -194
  392. package/src/components/ticketsContainer/index.tsx +0 -986
  393. package/src/components/ticketsContainer/style.css +0 -178
  394. package/src/components/ticketsContainer/utils.ts +0 -35
  395. package/src/components/timerWidget/index.tsx +0 -97
  396. package/src/components/timerWidget/style.css +0 -35
  397. package/src/components/waitingList/index.tsx +0 -190
  398. package/src/components/waitingList/style.css +0 -27
  399. package/src/constants/index.ts +0 -3
  400. package/src/env.ts +0 -29
  401. package/src/hoc/CustomFields/index.tsx +0 -85
  402. package/src/hoc/index.ts +0 -1
  403. package/src/hooks/index.ts +0 -1
  404. package/src/hooks/useCookieListener.ts +0 -32
  405. package/src/hooks/useEventListener.ts +0 -32
  406. package/src/hooks/useLocalStorageListener.ts +0 -32
  407. package/src/hooks/useOnline.ts +0 -21
  408. package/src/hooks/usePixel.ts +0 -88
  409. package/src/normalizers/index.ts +0 -49
  410. package/src/types/add_on.ts +0 -8
  411. package/src/types/api/auth.d.ts +0 -63
  412. package/src/types/api/axiosResponse.d.ts +0 -6
  413. package/src/types/api/cart.d.ts +0 -73
  414. package/src/types/api/checkout.d.ts +0 -92
  415. package/src/types/api/common.d.ts +0 -153
  416. package/src/types/api/guestTicketDelegation.d.ts +0 -18
  417. package/src/types/api/orders.d.ts +0 -116
  418. package/src/types/api/payment.d.ts +0 -180
  419. package/src/types/api/preRegistration.d.ts +0 -11
  420. package/src/types/api/preRegistrationComplete.d.ts +0 -95
  421. package/src/types/api/ticketResale.d.ts +0 -13
  422. package/src/types/billing-info-data.ts +0 -37
  423. package/src/types/checkoutPageConfigs.ts +0 -13
  424. package/src/types/formFields.d.ts +0 -29
  425. package/src/types/index.ts +0 -6
  426. package/src/types/order-data.ts +0 -16
  427. package/src/types/payment-field.ts +0 -7
  428. package/src/types/payment-plan-configuration.ts +0 -19
  429. package/src/types/pre-registration-complete.d.ts +0 -47
  430. package/src/types/referral-promotion.ts +0 -7
  431. package/src/types/seatMap.d.ts +0 -159
  432. package/src/types/verification.ts +0 -12
  433. package/src/utils/adaptStripeErrors.ts +0 -26
  434. package/src/utils/auth.ts +0 -45
  435. package/src/utils/cookies.ts +0 -73
  436. package/src/utils/createCheckoutDataBodyWithDefaultHolder.ts +0 -81
  437. package/src/utils/createMarkup.ts +0 -1
  438. package/src/utils/customFields.ts +0 -80
  439. package/src/utils/downloadPDF.tsx +0 -42
  440. package/src/utils/form.ts +0 -34
  441. package/src/utils/formikErrorFocus.ts +0 -24
  442. package/src/utils/getDomain.ts +0 -21
  443. package/src/utils/getImage.ts +0 -14
  444. package/src/utils/getQueryVariable.ts +0 -13
  445. package/src/utils/htmlNodeFromString.ts +0 -6
  446. package/src/utils/index.ts +0 -15
  447. package/src/utils/isBrowser.ts +0 -2
  448. package/src/utils/isValidNumber.ts +0 -8
  449. package/src/utils/jsonUtils.ts +0 -8
  450. package/src/utils/replaceVarInString.ts +0 -9
  451. package/src/utils/setConfigs.ts +0 -24
  452. package/src/utils/showZero.tsx +0 -10
  453. package/src/validators/index.ts +0 -61
@@ -0,0 +1,743 @@
1
+ /**
2
+ * `<BillingInfo/>` — the buyer + attendee details step. Collects: the buyer's
3
+ * name/email + event-gated buyer fields (Instagram/nationality/gender), any
4
+ * ORDER-level custom fields, PER-HOLDER name + ticket-level custom fields (when
5
+ * the event requires holder names or has ticket-scoped fields), and marketing
6
+ * opt-ins. Writes it all into the engine (`setBilling` with `dataCapture`,
7
+ * `setHolders` with `ticketDataCapture`, `setConsent`) so `<Payment/>`'s
8
+ * pre-flight passes. Use it alongside `<Payment/>`, or set those yourself.
9
+ */
10
+ import React, {
11
+ Fragment,
12
+ useEffect,
13
+ useMemo,
14
+ useRef,
15
+ useState,
16
+ type ChangeEvent,
17
+ type FC,
18
+ type ReactNode,
19
+ } from 'react'
20
+
21
+ import {
22
+ hooks,
23
+ mapProfileToBilling,
24
+ missingCheckoutDetails,
25
+ isEmail,
26
+ ticketFieldsFor,
27
+ type CheckoutBilling,
28
+ type CheckoutHolder,
29
+ type CustomFieldValues,
30
+ type EventCustomFieldGroup,
31
+ } from 'tf-checkout-shared'
32
+ import { PhoneInput, type CountryIso2 } from 'react-international-phone'
33
+
34
+ import { Button } from '../ui/Button'
35
+ import { Card, SectionHeader } from '../ui/Card'
36
+ import { useCheckoutContext, useCheckoutValidation } from '../ui/CheckoutProvider'
37
+ import { CustomFieldInput } from '../ui/CustomFields'
38
+ import { Checkbox, Field, FieldRow, Input } from '../ui/Field'
39
+ import { BillingAddressFields } from './billing/BillingAddressFields'
40
+ import { BuyerField } from './billing/BuyerField'
41
+ import { TicketHoldersCard } from './billing/TicketHoldersCard'
42
+ import type { BillingDraft, HolderDraft } from './billing/types'
43
+
44
+ export interface BillingInfoProps {
45
+ /** Event context is used to default the country and phone dial code. */
46
+ eventId?: string
47
+ /** Fired once billing is saved to the engine — e.g. reveal `<Payment/>`. */
48
+ onContinue?: () => void
49
+ /** Section heading. Old checkout uses "Billing Information". */
50
+ heading?: string
51
+ /** CTA label. */
52
+ buttonLabel?: string
53
+ /** When provided and the buyer isn't signed in, shows a "Login & skip ahead"
54
+ * row. The current email is passed when login follows an account match. */
55
+ onLogin?: (email?: string) => void
56
+ /** Hide this card only after a signed-in profile satisfies every ordinary
57
+ * billing requirement and the event needs no extra buyer/holder answers. */
58
+ skipWhenProfileComplete?: boolean
59
+ /** Ask guests to repeat their email and require an exact match. */
60
+ requireEmailConfirmation?: boolean
61
+ /** Always collect one named holder per selected ticket. EmbeddedCheckout uses
62
+ * this to match tf-sports; standalone sections default to backend gates. */
63
+ collectTicketHolders?: boolean
64
+ /** When holder details are enabled, also collect each holder's email and phone. */
65
+ collectHolderContact?: boolean
66
+ /** Marketing opt-in labels. Render a checkbox for each provided (unchecked). */
67
+ ttfOptInLabel?: string
68
+ brandOptInLabel?: string
69
+ /** Required host privacy acknowledgement. The URL is supplied by the consumer. */
70
+ privacyPolicy?: CheckoutPrivacyPolicy
71
+ /** Show the legacy inline "Required" error after a failed payment attempt. */
72
+ showPrivacyError?: boolean
73
+ /** Optional numbered badge (old checkout shows none — omitted by default). */
74
+ step?: ReactNode
75
+ className?: string
76
+ }
77
+
78
+ export interface CheckoutPrivacyPolicy {
79
+ url: string
80
+ brandName: string
81
+ linkLabel?: string
82
+ }
83
+
84
+ export const BillingInfo: FC<BillingInfoProps> = ({
85
+ eventId,
86
+ onContinue,
87
+ heading = 'Billing Information',
88
+ buttonLabel = 'Continue to payment',
89
+ onLogin,
90
+ skipWhenProfileComplete = false,
91
+ requireEmailConfirmation = false,
92
+ collectTicketHolders = false,
93
+ collectHolderContact = false,
94
+ ttfOptInLabel = 'Keep me updated about future events from The Ticket Fairy',
95
+ brandOptInLabel,
96
+ privacyPolicy,
97
+ showPrivacyError = false,
98
+ step,
99
+ className,
100
+ }) => {
101
+ const checkout = useCheckoutContext()
102
+ const validation = useCheckoutValidation()
103
+ const profile = hooks.useProfile({ retry: false })
104
+ const event = hooks.useEvent(eventId)
105
+ // No onContinue ⇒ this is one combined form (inside <EmbeddedCheckout/>): mirror the
106
+ // fields into the engine live and drop the "continue" button, so the buyer
107
+ // fills billing + pays with ONE button — the way the old checkout flowed.
108
+ const combined = !onContinue
109
+
110
+ const [billing, setBilling] = useState<BillingDraft>({
111
+ firstName: checkout.billing?.firstName ?? '',
112
+ lastName: checkout.billing?.lastName ?? '',
113
+ email: checkout.billing?.email ?? '',
114
+ confirmEmail: checkout.billing?.confirmEmail ?? '',
115
+ phone: checkout.billing?.phone,
116
+ streetAddress: checkout.billing?.streetAddress,
117
+ city: checkout.billing?.city,
118
+ zip: checkout.billing?.zip,
119
+ countryId: checkout.billing?.countryId,
120
+ stateId: checkout.billing?.stateId,
121
+ countryCode: checkout.billing?.countryCode,
122
+ stateCode: checkout.billing?.stateCode,
123
+ nationality: checkout.billing?.nationality,
124
+ gender: checkout.billing?.gender,
125
+ instagramHandle: checkout.billing?.instagramHandle,
126
+ })
127
+ const [dataCapture, setDataCapture] = useState<CustomFieldValues>(
128
+ checkout.billing?.dataCapture ?? {}
129
+ )
130
+ const [holders, setHolders] = useState<HolderDraft[]>(() =>
131
+ checkout.holders.map((holder) => ({
132
+ firstName: holder.firstName,
133
+ lastName: holder.lastName,
134
+ email: holder.email,
135
+ phone: holder.phone ?? '',
136
+ ticketTypeId: holder.ticketTypeId,
137
+ ticketDataCapture: holder.ticketDataCapture ?? {},
138
+ }))
139
+ )
140
+ const [consent, setConsent] = useState({ ttfOptIn: false, brandOptIn: false })
141
+ const [dob, setDob] = useState(() => {
142
+ const b = checkout.billing
143
+ if (!b?.dobDay || !b.dobMonth || !b.dobYear) return ''
144
+ return `${b.dobYear}-${String(b.dobMonth).padStart(2, '0')}-${String(
145
+ b.dobDay
146
+ ).padStart(2, '0')}`
147
+ }) // ISO yyyy-mm-dd
148
+ const restoredHolders = useRef(checkout.holders)
149
+ const profileSeeded = useRef(false)
150
+ const countryDefaultApplied = useRef(Boolean(checkout.billing?.countryId))
151
+
152
+ const gates = checkout.fieldGates
153
+
154
+ // Custom-field groups by scope.
155
+ const orderGroups = useMemo(
156
+ () => checkout.customFields.filter((g) => g.scope === 'order'),
157
+ [checkout.customFields]
158
+ )
159
+ const ticketGroups = useMemo(
160
+ () => checkout.customFields.filter((g) => g.scope === 'ticket'),
161
+ [checkout.customFields]
162
+ )
163
+ const ticketFields = useMemo(
164
+ () => ticketGroups.flatMap((g) => g.fields),
165
+ [ticketGroups]
166
+ )
167
+ const holderNamesRequired = checkout.holderNamesRequired || collectTicketHolders
168
+ const showHolders = holderNamesRequired || ticketFields.length > 0
169
+
170
+ // One holder slot per ticket, tagged with its ticket type (drives ticket-field
171
+ // scoping + the engine's per-holder validation).
172
+ const slots = useMemo(() => {
173
+ const out: { ticketTypeId?: string; ticketName?: string }[] = []
174
+ const lines = checkout.breakdown?.tickets ?? []
175
+ for (const line of lines)
176
+ for (let i = 0; i < line.quantity; i++)
177
+ out.push({ ticketTypeId: line.ticketTypeId, ticketName: line.name })
178
+ if (!out.length) {
179
+ const total = checkout.selections.reduce((n, s) => n + s.quantity, 0)
180
+ for (let i = 0; i < total; i++) out.push({})
181
+ }
182
+ return out
183
+ }, [checkout.breakdown, checkout.selections])
184
+
185
+ // The initial state above restores anything already on the engine. A profile
186
+ // that arrives later may fill blanks ONCE, but must never be consulted again
187
+ // while the buyer edits — otherwise clearing the final character restores the
188
+ // previous engine value on the next live commit.
189
+ useEffect(() => {
190
+ const p = profile.data
191
+ if (!p || profileSeeded.current) return
192
+ profileSeeded.current = true
193
+ const profileBilling = mapProfileToBilling(p)
194
+ setBilling((prev) => {
195
+ const next = {
196
+ ...prev,
197
+ firstName: prev.firstName || profileBilling.firstName || '',
198
+ lastName: prev.lastName || profileBilling.lastName || '',
199
+ email: prev.email || profileBilling.email || '',
200
+ confirmEmail:
201
+ prev.confirmEmail || (checkout.isLoggedIn ? profileBilling.email : '') || '',
202
+ phone: prev.phone || profileBilling.phone,
203
+ streetAddress: prev.streetAddress || profileBilling.streetAddress,
204
+ city: prev.city || profileBilling.city,
205
+ zip: prev.zip || profileBilling.zip,
206
+ countryId: prev.countryId || profileBilling.countryId,
207
+ stateId: prev.stateId || profileBilling.stateId,
208
+ }
209
+ const keys = Object.keys(next) as (keyof BillingDraft)[]
210
+ return keys.every((k) => next[k] === prev[k]) ? prev : next
211
+ })
212
+ }, [profile.data, checkout.isLoggedIn])
213
+
214
+ // Resize holders to the slot count, preserving typed values; tag ticket type.
215
+ useEffect(() => {
216
+ setHolders((prev) =>
217
+ slots.map((s, i) => ({
218
+ firstName: prev[i]?.firstName ?? restoredHolders.current[i]?.firstName ?? '',
219
+ lastName: prev[i]?.lastName ?? restoredHolders.current[i]?.lastName ?? '',
220
+ email: prev[i]?.email ?? restoredHolders.current[i]?.email ?? '',
221
+ phone: prev[i]?.phone ?? restoredHolders.current[i]?.phone ?? '',
222
+ ticketDataCapture:
223
+ prev[i]?.ticketDataCapture ??
224
+ restoredHolders.current[i]?.ticketDataCapture ??
225
+ {},
226
+ ticketTypeId: s.ticketTypeId,
227
+ ticketName: s.ticketName,
228
+ }))
229
+ )
230
+ }, [slots])
231
+
232
+ // Match the storefront: ticket 1 silently starts as the buyer. The legacy
233
+ // checkout has no extra "use buyer details" control.
234
+ useEffect(() => {
235
+ if (!showHolders) return
236
+ setHolders((prev) =>
237
+ prev.map((holder, index) =>
238
+ index === 0
239
+ ? {
240
+ ...holder,
241
+ firstName: billing.firstName,
242
+ lastName: billing.lastName,
243
+ email: billing.email,
244
+ phone: billing.phone ?? '',
245
+ }
246
+ : holder
247
+ )
248
+ )
249
+ }, [showHolders, billing.firstName, billing.lastName, billing.email, billing.phone])
250
+
251
+ // Debounced "this email already has an account" check → nudges the buyer to
252
+ // sign in (autofill + avoid duplicate accounts). Skips signed-in buyers.
253
+ useEffect(() => {
254
+ const email = billing.email.trim()
255
+ if (checkout.isLoggedIn || !isEmail(email)) return
256
+ const t = setTimeout(
257
+ () => checkout.checkBuyerEmail(email).catch(() => undefined),
258
+ 600
259
+ )
260
+ return () => clearTimeout(t)
261
+ // eslint-disable-next-line react-hooks/exhaustive-deps
262
+ }, [billing.email, checkout.isLoggedIn])
263
+ const emailTaken =
264
+ !checkout.isLoggedIn && checkout.existingAccountEmail === billing.email.trim()
265
+
266
+ const needsNationality = checkout.buyerFields.some((f) => f.kind === 'nationality')
267
+ const countriesQuery = hooks.useCountries({
268
+ enabled: needsNationality || gates.showAddress,
269
+ })
270
+ const countries = useMemo(() => countriesQuery.data ?? [], [countriesQuery.data])
271
+ const statesQuery = hooks.useStates(billing.countryId, {
272
+ enabled: Boolean(billing.countryId),
273
+ })
274
+ const states = useMemo(() => statesQuery.data ?? [], [statesQuery.data])
275
+
276
+ // Event country → signed-in profile → US, matching the hosted checkout's
277
+ // country preference order. Also retain the ISO code for Stripe + phone UI.
278
+ useEffect(() => {
279
+ if (
280
+ countryDefaultApplied.current ||
281
+ billing.countryId ||
282
+ countries.length === 0 ||
283
+ profile.isLoading ||
284
+ (eventId && event.isLoading)
285
+ ) {
286
+ return
287
+ }
288
+ const eventCode = event.data?.countryCode?.toLowerCase()
289
+ const preferred =
290
+ countries.find((country) => country.code?.toLowerCase() === eventCode) ??
291
+ countries.find(
292
+ (country) =>
293
+ profile.data?.countryId !== null &&
294
+ profile.data?.countryId !== undefined &&
295
+ String(country.id) === String(profile.data.countryId)
296
+ ) ??
297
+ countries.find((country) => country.code?.toLowerCase() === 'us')
298
+ if (!preferred) return
299
+ countryDefaultApplied.current = true
300
+ setBilling((current) => ({
301
+ ...current,
302
+ countryId: String(preferred.id),
303
+ countryCode: preferred.code?.toUpperCase(),
304
+ stateId: undefined,
305
+ stateCode: undefined,
306
+ }))
307
+ }, [
308
+ billing.countryId,
309
+ countries,
310
+ profile.isLoading,
311
+ profile.data?.countryId,
312
+ eventId,
313
+ event.isLoading,
314
+ event.data?.countryCode,
315
+ ])
316
+
317
+ useEffect(() => {
318
+ if (!billing.countryId) return
319
+ const country = countries.find(
320
+ (candidate) => String(candidate.id) === String(billing.countryId)
321
+ )
322
+ const countryCode = country?.code?.toUpperCase()
323
+ if (countryCode && countryCode !== billing.countryCode) {
324
+ setBilling((current) => ({ ...current, countryCode }))
325
+ }
326
+ }, [billing.countryId, billing.countryCode, countries])
327
+
328
+ useEffect(() => {
329
+ if (!billing.stateId) return
330
+ const state = states.find(
331
+ (candidate) => String(candidate.id) === String(billing.stateId)
332
+ )
333
+ const stateCode = state?.code
334
+ if (stateCode && stateCode !== billing.stateCode) {
335
+ setBilling((current) => ({ ...current, stateCode }))
336
+ }
337
+ }, [billing.stateId, billing.stateCode, states])
338
+
339
+ const setB = (k: keyof BillingDraft) => (e: ChangeEvent<HTMLInputElement>) =>
340
+ setBilling((b) => ({ ...b, [k]: e.target.value }))
341
+
342
+ const patchHolder = (i: number, patch: Partial<HolderDraft>) =>
343
+ setHolders((hs) => hs.map((h, j) => (j === i ? { ...h, ...patch } : h)))
344
+
345
+ const [dobYear, dobMonth, dobDay] = dob ? dob.split('-').map(Number) : []
346
+ const committedBilling: CheckoutBilling = {
347
+ ...checkout.billing,
348
+ ...billing,
349
+ stateRequired: gates.showAddress && Boolean(billing.countryId) && states.length > 0,
350
+ dataCapture,
351
+ dobDay,
352
+ dobMonth,
353
+ dobYear,
354
+ }
355
+ const committedHolders: CheckoutHolder[] = holders.map((holder) => ({
356
+ firstName: holderNamesRequired
357
+ ? holder.firstName
358
+ : holder.firstName || billing.firstName,
359
+ lastName: holderNamesRequired ? holder.lastName : holder.lastName || billing.lastName,
360
+ email:
361
+ showHolders && collectHolderContact ? holder.email : holder.email || billing.email,
362
+ phone:
363
+ showHolders && collectHolderContact ? holder.phone : holder.phone || billing.phone,
364
+ ticketTypeId: holder.ticketTypeId,
365
+ ticketDataCapture: holder.ticketDataCapture,
366
+ }))
367
+ const missingDetails = missingCheckoutDetails(
368
+ {
369
+ billing: committedBilling,
370
+ holders: committedHolders,
371
+ selections: checkout.selections,
372
+ breakdown: checkout.breakdown,
373
+ holderNamesRequired: checkout.holderNamesRequired,
374
+ fieldGates: checkout.fieldGates,
375
+ customFields: checkout.customFields,
376
+ },
377
+ {
378
+ requireEmailConfirmation,
379
+ collectTicketHolders,
380
+ requireHolderContact: collectHolderContact,
381
+ }
382
+ )
383
+ const complete = missingDetails.length === 0
384
+ const showValidation = validation.attempt > 0
385
+ const missingSet = new Set(missingDetails)
386
+ const fieldError = (key: string, message = 'This field is required.') =>
387
+ showValidation && missingSet.has(key) ? message : undefined
388
+ const dobError = showValidation
389
+ ? missingDetails.find(
390
+ (detail) => detail === 'Date of birth' || detail.startsWith('Age ')
391
+ )
392
+ : undefined
393
+ const phoneCountry = (
394
+ billing.countryCode ??
395
+ event.data?.countryCode ??
396
+ 'US'
397
+ )?.toLowerCase() as CountryIso2
398
+
399
+ const commit = () => {
400
+ checkout.setBilling(committedBilling)
401
+ checkout.setHolders(committedHolders)
402
+ if (ttfOptInLabel || brandOptInLabel) checkout.setConsent(consent)
403
+ }
404
+
405
+ // Combined mode: keep the engine in sync as the form is filled, so <Payment/>
406
+ // is always chargeable without a separate "continue" click.
407
+ useEffect(() => {
408
+ if (combined) commit()
409
+ // eslint-disable-next-line react-hooks/exhaustive-deps
410
+ }, [combined, billing, holders, consent, dob, dataCapture])
411
+
412
+ const renderGroupFields = (
413
+ group: EventCustomFieldGroup,
414
+ values: CustomFieldValues,
415
+ onChange: (name: string, v: string | string[]) => void,
416
+ ticketTypeId?: string,
417
+ ticketIndex?: number
418
+ ) =>
419
+ ticketFieldsFor(group.fields, ticketTypeId).map((f) => {
420
+ const label = f.label || f.name
421
+ const missingKey =
422
+ ticketIndex === undefined ? label : `${label} (ticket ${ticketIndex + 1})`
423
+ return (
424
+ <CustomFieldInput
425
+ key={f.id}
426
+ field={f}
427
+ value={values[f.name]}
428
+ error={fieldError(missingKey)}
429
+ onChange={(v) => onChange(f.name, v)}
430
+ />
431
+ )
432
+ })
433
+
434
+ const hasEventSpecificDetails =
435
+ checkout.buyerFields.length > 0 ||
436
+ checkout.customFields.some((group) => group.fields.length > 0) ||
437
+ showHolders ||
438
+ gates.showDob
439
+ const skipBilling =
440
+ skipWhenProfileComplete &&
441
+ checkout.isLoggedIn &&
442
+ profile.isSuccess &&
443
+ complete &&
444
+ !hasEventSpecificDetails
445
+
446
+ // This is the safe EmbeddedCheckout interpretation of legacy
447
+ // `skip_billing_page`: payment remains visible; only a fully satisfied,
448
+ // ordinary billing card disappears.
449
+ if (skipBilling) return null
450
+
451
+ return (
452
+ <>
453
+ <Card className={className}>
454
+ <SectionHeader step={step} title={heading} />
455
+
456
+ {onLogin && !checkout.isLoggedIn && (
457
+ <div className="tf-checkout-billing__login">
458
+ <span>Login &amp; skip ahead:</span>
459
+ <button
460
+ type="button"
461
+ className="tf-checkout-billing__login-btn"
462
+ onClick={() => onLogin()}
463
+ >
464
+ Login
465
+ </button>
466
+ </div>
467
+ )}
468
+
469
+ <FieldRow>
470
+ <Field
471
+ error={fieldError('First name', 'First name is required.')}
472
+ invalid={Boolean(fieldError('First name'))}
473
+ >
474
+ <Input
475
+ placeholder="First name *"
476
+ value={billing.firstName}
477
+ required
478
+ invalid={Boolean(fieldError('First name'))}
479
+ aria-invalid={Boolean(fieldError('First name'))}
480
+ onChange={setB('firstName')}
481
+ />
482
+ </Field>
483
+ <Field
484
+ error={fieldError('Last name', 'Last name is required.')}
485
+ invalid={Boolean(fieldError('Last name'))}
486
+ >
487
+ <Input
488
+ placeholder="Last name *"
489
+ value={billing.lastName}
490
+ required
491
+ invalid={Boolean(fieldError('Last name'))}
492
+ aria-invalid={Boolean(fieldError('Last name'))}
493
+ onChange={setB('lastName')}
494
+ />
495
+ </Field>
496
+ </FieldRow>
497
+ <FieldRow>
498
+ <Field
499
+ error={fieldError('Valid email address', 'Enter a valid email address.')}
500
+ invalid={Boolean(fieldError('Valid email address'))}
501
+ >
502
+ <Input
503
+ type="email"
504
+ autoComplete="email"
505
+ placeholder="Email *"
506
+ value={billing.email}
507
+ required
508
+ invalid={Boolean(fieldError('Valid email address'))}
509
+ aria-invalid={Boolean(fieldError('Valid email address'))}
510
+ onChange={setB('email')}
511
+ />
512
+ </Field>
513
+ {requireEmailConfirmation && !checkout.isLoggedIn && (
514
+ <Field
515
+ error={fieldError(
516
+ 'Matching email confirmation',
517
+ 'Email addresses must match.'
518
+ )}
519
+ invalid={Boolean(fieldError('Matching email confirmation'))}
520
+ >
521
+ <Input
522
+ type="email"
523
+ autoComplete="email"
524
+ placeholder="Confirm email *"
525
+ value={billing.confirmEmail ?? ''}
526
+ required
527
+ invalid={Boolean(fieldError('Matching email confirmation'))}
528
+ aria-invalid={Boolean(fieldError('Matching email confirmation'))}
529
+ onChange={setB('confirmEmail')}
530
+ />
531
+ </Field>
532
+ )}
533
+ </FieldRow>
534
+ {!showValidation &&
535
+ requireEmailConfirmation &&
536
+ billing.confirmEmail &&
537
+ billing.confirmEmail.trim().toLowerCase() !==
538
+ billing.email.trim().toLowerCase() && (
539
+ <p className="tf-checkout-error-text">The email addresses do not match.</p>
540
+ )}
541
+ {emailTaken && (
542
+ <p className="tf-checkout-note tf-checkout-billing__email-taken">
543
+ This email is already registered.{' '}
544
+ {onLogin ? (
545
+ <button
546
+ type="button"
547
+ className="tf-checkout-billing__login-link"
548
+ onClick={() => onLogin(billing.email)}
549
+ >
550
+ Log in to autofill your details
551
+ </button>
552
+ ) : (
553
+ 'Log in to autofill your details.'
554
+ )}
555
+ </p>
556
+ )}
557
+
558
+ {checkout.buyerFields.map((f) => (
559
+ <BuyerField
560
+ key={f.key}
561
+ field={f}
562
+ value={String(billing[f.key] ?? '')}
563
+ onChange={(v) => setBilling((b) => ({ ...b, [f.key]: v }))}
564
+ countries={countries}
565
+ error={fieldError(
566
+ f.kind === 'nationality'
567
+ ? 'Nationality'
568
+ : f.kind === 'gender'
569
+ ? 'Gender'
570
+ : 'Instagram handle'
571
+ )}
572
+ />
573
+ ))}
574
+
575
+ {gates.showPhone && (
576
+ <Field
577
+ label={`Phone${gates.phoneRequired ? ' *' : ''}`}
578
+ error={fieldError('Valid phone number', 'Enter a valid phone number.')}
579
+ invalid={Boolean(fieldError('Valid phone number'))}
580
+ >
581
+ <PhoneInput
582
+ className="tf-checkout-phone"
583
+ inputClassName={`tf-checkout-input tf-checkout-phone__input${
584
+ fieldError('Valid phone number') ? ' tf-checkout-input--invalid' : ''
585
+ }`}
586
+ defaultCountry={phoneCountry}
587
+ disableDialCodePrefill
588
+ value={billing.phone ?? ''}
589
+ required={gates.phoneRequired}
590
+ placeholder="Phone number"
591
+ inputProps={{
592
+ autoComplete: 'tel',
593
+ 'aria-label': 'Phone',
594
+ 'aria-invalid': Boolean(fieldError('Valid phone number')),
595
+ }}
596
+ onChange={(phone) => setBilling((current) => ({ ...current, phone }))}
597
+ />
598
+ </Field>
599
+ )}
600
+
601
+ {gates.showDob && (
602
+ <Field
603
+ label={`Date of birth *${
604
+ gates.minimumAge ? ` (must be ${gates.minimumAge}+)` : ''
605
+ }`}
606
+ error={
607
+ dobError === 'Date of birth'
608
+ ? 'Date of birth is required.'
609
+ : dobError
610
+ ? `You must be ${gates.minimumAge} or older.`
611
+ : undefined
612
+ }
613
+ invalid={Boolean(dobError)}
614
+ >
615
+ <Input
616
+ type="date"
617
+ value={dob}
618
+ required
619
+ invalid={Boolean(dobError)}
620
+ aria-invalid={Boolean(dobError)}
621
+ onChange={(e) => setDob(e.target.value)}
622
+ />
623
+ </Field>
624
+ )}
625
+
626
+ {gates.showAddress && (
627
+ <BillingAddressFields
628
+ billing={billing}
629
+ countries={countries}
630
+ states={states}
631
+ fieldError={fieldError}
632
+ setBilling={setBilling}
633
+ />
634
+ )}
635
+
636
+ {/* Order-level custom fields */}
637
+ {orderGroups.map((g) => (
638
+ <Fragment key={g.id}>
639
+ {g.label && (
640
+ <div className="tf-checkout-billing__section-label">{g.label}</div>
641
+ )}
642
+ {renderGroupFields(g, dataCapture, (name, v) =>
643
+ setDataCapture((d) => ({ ...d, [name]: v }))
644
+ )}
645
+ </Fragment>
646
+ ))}
647
+
648
+ {/* Marketing opt-ins (optional) */}
649
+ {brandOptInLabel && (
650
+ <Checkbox
651
+ checked={consent.brandOptIn}
652
+ onChange={(e) => setConsent((c) => ({ ...c, brandOptIn: e.target.checked }))}
653
+ className="tf-checkout-checkbox--consent"
654
+ label={brandOptInLabel}
655
+ />
656
+ )}
657
+ {privacyPolicy ? (
658
+ <div
659
+ className={
660
+ (showPrivacyError || showValidation) && !consent.ttfOptIn
661
+ ? 'tf-checkout-consent--error'
662
+ : ''
663
+ }
664
+ data-checkout-invalid={
665
+ ((showPrivacyError || showValidation) && !consent.ttfOptIn) || undefined
666
+ }
667
+ >
668
+ <Checkbox
669
+ required
670
+ checked={consent.ttfOptIn}
671
+ aria-invalid={(showPrivacyError || showValidation) && !consent.ttfOptIn}
672
+ onChange={(e) => setConsent((c) => ({ ...c, ttfOptIn: e.target.checked }))}
673
+ className="tf-checkout-checkbox--consent"
674
+ label={
675
+ <>
676
+ I have read and agree to {privacyPolicy.brandName}{' '}
677
+ <a href={privacyPolicy.url} target="_blank" rel="noreferrer">
678
+ {privacyPolicy.linkLabel || 'Privacy Policy.'}
679
+ </a>
680
+ {' *'}
681
+ </>
682
+ }
683
+ />
684
+ {(showPrivacyError || showValidation) && !consent.ttfOptIn && (
685
+ <div className="tf-checkout-consent__error">Required</div>
686
+ )}
687
+ </div>
688
+ ) : ttfOptInLabel ? (
689
+ <Checkbox
690
+ checked={consent.ttfOptIn}
691
+ onChange={(e) => setConsent((c) => ({ ...c, ttfOptIn: e.target.checked }))}
692
+ className="tf-checkout-checkbox--consent"
693
+ label={ttfOptInLabel}
694
+ />
695
+ ) : null}
696
+ {!combined && (
697
+ <>
698
+ <Button
699
+ block
700
+ onClick={() => {
701
+ if (!complete) {
702
+ validation.requestValidation()
703
+ return
704
+ }
705
+ commit()
706
+ onContinue?.()
707
+ }}
708
+ >
709
+ {buttonLabel}
710
+ </Button>
711
+ </>
712
+ )}
713
+ </Card>
714
+ {showHolders && (
715
+ <TicketHoldersCard
716
+ holders={holders}
717
+ holderNamesRequired={holderNamesRequired}
718
+ collectHolderContact={collectHolderContact}
719
+ phoneCountry={phoneCountry}
720
+ fieldError={fieldError}
721
+ patchHolder={patchHolder}
722
+ renderCustomFields={(holder, index) =>
723
+ ticketGroups.map((group) =>
724
+ renderGroupFields(
725
+ group,
726
+ holder.ticketDataCapture,
727
+ (name, value) =>
728
+ patchHolder(index, {
729
+ ticketDataCapture: {
730
+ ...holder.ticketDataCapture,
731
+ [name]: value,
732
+ },
733
+ }),
734
+ holder.ticketTypeId,
735
+ index
736
+ )
737
+ )
738
+ }
739
+ />
740
+ )}
741
+ </>
742
+ )
743
+ }