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,84 @@
1
+ import React, { type FC } from 'react'
2
+
3
+ import { hooks } from 'tf-checkout-shared'
4
+
5
+ import { Card } from '../ui/Card'
6
+ import { useCheckoutContext } from '../ui/CheckoutProvider'
7
+
8
+ export interface OrderSummaryProps {
9
+ eventId?: string
10
+ className?: string
11
+ }
12
+
13
+ /** Storefront-compatible order summary shown after the checkout controls. */
14
+ export const OrderSummary: FC<OrderSummaryProps> = ({ eventId, className }) => {
15
+ const checkout = useCheckoutContext()
16
+ const event = hooks.useEvent(eventId)
17
+ const breakdown = checkout.breakdown
18
+ const detailed = checkout.priceBreakdown
19
+
20
+ if (!breakdown || breakdown.tickets.length === 0) return null
21
+
22
+ return (
23
+ <Card className={['tf-checkout-order-summary', className].filter(Boolean).join(' ')}>
24
+ {event.data?.name && (
25
+ <div className="tf-checkout-order-summary__group">
26
+ <div className="tf-checkout-order-summary__label">Event</div>
27
+ <div className="tf-checkout-order-summary__event">{event.data.name}</div>
28
+ </div>
29
+ )}
30
+
31
+ <div className="tf-checkout-order-summary__group">
32
+ <div className="tf-checkout-order-summary__label">Your Tickets</div>
33
+ {breakdown.tickets.map((ticket, index) => {
34
+ const detail = detailed?.tickets[index]
35
+ return (
36
+ <div
37
+ key={`${ticket.ticketTypeId}-${index}`}
38
+ className="tf-checkout-order-summary__item"
39
+ >
40
+ <div className="tf-checkout-order-summary__ticket">
41
+ {ticket.quantity} x {ticket.name} - {detail?.unit_price ?? ticket.unit}{' '}
42
+ each
43
+ </div>
44
+ {detail?.line_total && detail.line_total !== detail.unit_price && (
45
+ <div className="tf-checkout-order-summary__fees">
46
+ ({detail.line_total} with fees)
47
+ </div>
48
+ )}
49
+ </div>
50
+ )
51
+ })}
52
+ </div>
53
+
54
+ {(detailed?.add_ons.length ?? 0) > 0 && (
55
+ <div className="tf-checkout-order-summary__group">
56
+ <div className="tf-checkout-order-summary__label">
57
+ {detailed?.add_ons_title || 'Add-ons'}
58
+ </div>
59
+ {detailed?.add_ons.map((addOn, index) => (
60
+ <div
61
+ key={`${addOn.name}-${index}`}
62
+ className="tf-checkout-order-summary__item"
63
+ >
64
+ <div className="tf-checkout-order-summary__ticket">
65
+ {addOn.quantity} x {addOn.name}
66
+ {addOn.show_price ? ` - ${addOn.unit_price} each` : ''}
67
+ </div>
68
+ </div>
69
+ ))}
70
+ </div>
71
+ )}
72
+
73
+ <div className="tf-checkout-order-summary__total">
74
+ <div className="tf-checkout-order-summary__label">Total</div>
75
+ <div className="tf-checkout-order-summary__amount">
76
+ {detailed?.total ??
77
+ `${breakdown.currencySymbol || `${breakdown.currencyCode} `}${Number(
78
+ breakdown.total
79
+ ).toFixed(2)}`}
80
+ </div>
81
+ </div>
82
+ </Card>
83
+ )
84
+ }
@@ -0,0 +1,541 @@
1
+ /**
2
+ * `<Payment/>` — order review + payment-method selection + T&C, then place the
3
+ * order. Buyer details come from `<BillingInfo/>` (read back off the shared
4
+ * checkout). The method list is built from the event's gateway + `preOrderMethods()`
5
+ * + the priced snapshot, and each selection maps to the right `placeOrder` rail
6
+ * (Stripe card, Xendit card/e-wallet, PayPal, redirect rails, payment plan).
7
+ */
8
+ import React, { useEffect, useMemo, useRef, useState, type FC } from 'react'
9
+
10
+ import {
11
+ XENDIT_EWALLET_EXTRA_FIELD,
12
+ errorMessage,
13
+ missingCheckoutDetails,
14
+ paymentPlanTerms,
15
+ planConfirmLabel,
16
+ planTermsTitle,
17
+ ttf,
18
+ type EventCondition,
19
+ type PaymentRequest,
20
+ type PlaceOrderResult,
21
+ } from 'tf-checkout-shared'
22
+
23
+ import { CardInput, StripePaymentElement, XenditCardInput } from '../CardInput'
24
+ import { Button } from '../ui/Button'
25
+ import { Card, SectionHeader } from '../ui/Card'
26
+ import { useCheckoutContext, useCheckoutValidation } from '../ui/CheckoutProvider'
27
+ import { Checkbox } from '../ui/Field'
28
+ import { cx } from '../ui/cx'
29
+ import { Loader } from '../ui/Loader'
30
+ import { PaymentMethods, type PaymentMethodOption } from '../ui/PaymentMethods'
31
+ import { OrderSummary } from './OrderSummary'
32
+
33
+ type PreOrderMethods = Awaited<ReturnType<typeof ttf.cart.preOrderMethods>>
34
+
35
+ /** Server spellings → display labels for Stripe redirect rails. */
36
+ const REDIRECT_LABELS: Record<string, string> = {
37
+ klarna: 'Klarna',
38
+ afterpay_clearpay: 'Afterpay / Clearpay',
39
+ affirm: 'Affirm',
40
+ ideal: 'iDEAL',
41
+ bancontact: 'Bancontact',
42
+ eps: 'EPS',
43
+ giropay: 'giropay',
44
+ p24: 'Przelewy24',
45
+ alipay: 'Alipay',
46
+ grabpay: 'GrabPay',
47
+ cashapp: 'Cash App Pay',
48
+ paypal: 'PayPal',
49
+ }
50
+ const redirectLabel = (t: string) =>
51
+ REDIRECT_LABELS[t] ?? t.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
52
+
53
+ const isCardFieldError = (message: string) =>
54
+ /(?:card|expiry|expiration|security code|cvc).*(?:incomplete|required|invalid)|(?:incomplete|required|invalid).*(?:card|expiry|expiration|security code|cvc)/i.test(
55
+ message
56
+ )
57
+
58
+ /**
59
+ * Anything the buyer would fix AT THE CARD FIELD — a bad number, a wrong CVC,
60
+ * an expired or declined card, missing details. These belong beside the card
61
+ * box; only order-level problems (conditions, billing, network) belong down by
62
+ * the pay button, where a card message is easy to miss entirely.
63
+ */
64
+ const isCardAreaError = (message: string) =>
65
+ isCardFieldError(message) ||
66
+ /card details|security code|cvc|cvv|expired|declined|not accepted|balance|stolen|inactive|authentication failed|name on the card|different card/i.test(
67
+ message
68
+ )
69
+
70
+ export interface PaymentProps {
71
+ onComplete?: (order: PlaceOrderResult) => void
72
+ /** Optional event context adds the event name to the order review. */
73
+ eventId?: string
74
+ /** Must match the policy used by the paired `<BillingInfo/>`. */
75
+ requireEmailConfirmation?: boolean
76
+ /** Must match the holder policy used by the paired `<BillingInfo/>`. */
77
+ collectTicketHolders?: boolean
78
+ /** Must match the holder-contact policy used by the paired `<BillingInfo/>`. */
79
+ requireHolderContact?: boolean
80
+ /** Host-owned acknowledgements such as a brand privacy policy. */
81
+ additionalConditions?: EventCondition[]
82
+ /** Require the privacy checkbox managed by BillingInfo before payment. */
83
+ requirePrivacyPolicy?: boolean
84
+ /** Called when payment is attempted before required privacy consent. */
85
+ onPrivacyRequired?: () => void
86
+ /** Test card copy is useful in examples, but should never appear by default. */
87
+ showTestCardHint?: boolean
88
+ className?: string
89
+ }
90
+
91
+ export const Payment: FC<PaymentProps> = ({
92
+ onComplete,
93
+ eventId,
94
+ requireEmailConfirmation = false,
95
+ collectTicketHolders = false,
96
+ requireHolderContact = false,
97
+ additionalConditions = [],
98
+ requirePrivacyPolicy = false,
99
+ onPrivacyRequired,
100
+ showTestCardHint = false,
101
+ className,
102
+ }) => {
103
+ const checkout = useCheckoutContext()
104
+ const validation = useCheckoutValidation()
105
+ const [error, setError] = useState('')
106
+ /** Field-level problem reported by `<XenditCardInput/>` (it renders none). */
107
+ const [cardFieldError, setCardFieldError] = useState<string | null>(null)
108
+ /** Card problem from the last pay attempt (declined, wrong CVC, expired…). */
109
+ const [payCardError, setPayCardError] = useState<string | null>(null)
110
+ /** True once the buyer edits the card after a failed attempt — their fix
111
+ * supersedes both our message and the engine's stale one. */
112
+ const [cardEditedSincePay, setCardEditedSincePay] = useState(true)
113
+ const [methods, setMethods] = useState<PreOrderMethods | null>(null)
114
+ const [selected, setSelected] = useState('')
115
+ const [extras, setExtras] = useState<
116
+ Record<string, { cashtag?: string; phoneNumber?: string }>
117
+ >({})
118
+ const [useSavedCard, setUseSavedCard] = useState(true)
119
+ const cardSectionRef = useRef<HTMLDivElement | null>(null)
120
+
121
+ useEffect(() => {
122
+ let active = true
123
+ ttf.cart
124
+ .preOrderMethods()
125
+ .then((m) => active && setMethods(m))
126
+ .catch(() => active && setMethods(null))
127
+ return () => {
128
+ active = false
129
+ }
130
+ }, [])
131
+
132
+ const bd = checkout.breakdown
133
+ const isFree = bd != null && Number(bd.total) === 0
134
+ const isXendit = checkout.gateway === 'xendit'
135
+
136
+ // Build the selectable method rows from gateway + probe + snapshot.
137
+ const options = useMemo<PaymentMethodOption[]>(() => {
138
+ if (isFree || !methods) return []
139
+ const out: PaymentMethodOption[] = []
140
+ if (isXendit) {
141
+ if (methods.xenditCard)
142
+ out.push({ id: { kind: 'xenditCard' }, value: 'xenditCard', label: 'Card' })
143
+ for (const w of methods.xenditEWallets)
144
+ out.push({
145
+ id: { kind: 'xenditEWallet', walletKey: w.key },
146
+ value: `ew:${w.key}`,
147
+ label: w.label,
148
+ iconUrl: w.icon,
149
+ extra: (XENDIT_EWALLET_EXTRA_FIELD[w.key] as 'cashtag' | 'phoneNumber') ?? null,
150
+ })
151
+ } else if (checkout.gateway === 'razorpay') {
152
+ out.push({ id: { kind: 'razorpay' }, value: 'razorpay', label: 'Razorpay' })
153
+ } else {
154
+ // Stripe (or unknown → fail open to card).
155
+ out.push({ id: { kind: 'card' }, value: 'card', label: 'Card' })
156
+ for (const t of checkout.redirectPaymentMethods ?? []) {
157
+ if (t === 'paypal' && methods.paypal) continue // dedupe vs PayPal Standard
158
+ out.push({
159
+ id: { kind: 'redirect', methodType: t },
160
+ value: `rd:${t}`,
161
+ label: redirectLabel(t),
162
+ })
163
+ }
164
+ if (checkout.paymentPlan?.available)
165
+ out.push({
166
+ id: { kind: 'paymentPlan' },
167
+ value: 'paymentPlan',
168
+ label: 'Payment plan',
169
+ })
170
+ // OXXO cash voucher — Mexico only, and never listed in redirect methods.
171
+ if (checkout.breakdown?.currencyCode === 'MXN')
172
+ out.push({ id: { kind: 'oxxo' }, value: 'oxxo', label: 'OXXO (pay in cash)' })
173
+ }
174
+ if (methods.paypal)
175
+ out.push({ id: { kind: 'paypal' }, value: 'paypal', label: 'PayPal' })
176
+ return out
177
+ }, [
178
+ isFree,
179
+ methods,
180
+ isXendit,
181
+ checkout.gateway,
182
+ checkout.redirectPaymentMethods,
183
+ checkout.paymentPlan,
184
+ checkout.breakdown,
185
+ ])
186
+
187
+ // Default the selection to the first row once options exist.
188
+ useEffect(() => {
189
+ if (options.length && !options.some((o) => o.value === selected))
190
+ setSelected(options[0].value)
191
+ }, [options, selected])
192
+
193
+ const cardValue = isXendit ? 'xenditCard' : 'card'
194
+ const selectedOption = options.find((o) => o.value === selected)
195
+ const isCardSelected = selected === cardValue
196
+ const isPlanSelected = selectedOption?.id.kind === 'paymentPlan'
197
+ const savedLast4 = checkout.paymentPlan?.savedCardLast4
198
+ /**
199
+ * "Reuse the card on file" only means something when there IS one. The raw
200
+ * `useSavedCard` toggle defaults to true (matching the hosted default-checked
201
+ * box), so reading it directly made a first-time buyer look like a returning
202
+ * one: `inputSlotFor` collapsed to undefined, the card field and the plan
203
+ * terms never mounted, and "Confirm Payment Plan" then failed in the
204
+ * confirmer with "No card element registered". Always gate on the card.
205
+ */
206
+ const reuseSavedCard = Boolean(savedLast4) && useSavedCard
207
+ const usesCardDetails = !isFree && (isCardSelected || (isPlanSelected && !reuseSavedCard))
208
+ // Stripe's CardElement renders its own inline "Card number is invalid" text, so
209
+ // the pay handler can stay quiet and just scroll to it. Xendit's card form is
210
+ // three plain inputs with no error slot — there, the message MUST be shown or
211
+ // a declined/invalid card looks like the button simply did nothing.
212
+ const cardWidgetReportsItsOwnError = usesCardDetails && !isXendit
213
+
214
+ // Wallets the old-checkout way: when the event's `stripe_wallets` gate is on,
215
+ // render the Payment Element (card + Apple/Google Pay in one widget) instead of
216
+ // the bare card field. Held back for MXN so the CardElement-based MSI path
217
+ // (Mexican months-without-interest) keeps working — matching old, which didn't
218
+ // run MSI off its web Payment Element either.
219
+ const hasWallets = Boolean(
220
+ checkout.walletAvailability?.applePay || checkout.walletAvailability?.googlePay
221
+ )
222
+ // A payment plan NEVER rides the wallet element, matching the hosted flow's
223
+ // `wallets: planMode ? { applePay: 'never', googlePay: 'never' }`. Two
224
+ // reasons, both load-bearing:
225
+ // 1. A plan charges installments off-session, so it needs a REUSABLE card.
226
+ // Wallet tokens are typically single-use and can't be charged later.
227
+ // 2. Mechanically: the plan rail confirms via `confirmer.getCardElement()`,
228
+ // which only exists for `<CardInput/>`. The Payment Element registers
229
+ // itself through `registerPaymentElement` instead, so mounting it here
230
+ // made `confirmPaymentPlanSetup` throw "No card element registered" —
231
+ // the plan could never be completed on a wallet-enabled event.
232
+ const useWalletElement =
233
+ !isXendit &&
234
+ !isPlanSelected &&
235
+ hasWallets &&
236
+ checkout.breakdown?.currencyCode !== 'MXN' &&
237
+ Boolean((checkout.stripeElementsConfig as { mode?: unknown } | undefined)?.mode)
238
+
239
+ // When there's only ONE way to pay and it's a card, there's nothing to
240
+ // *choose* — the old checkout just showed the card form, no radio wrapper.
241
+ // Render the field directly; keep the radio list only when there's a choice.
242
+ const onlyOption = options.length === 1 ? options[0] : undefined
243
+ const singleCard =
244
+ onlyOption?.id.kind === 'card' || onlyOption?.id.kind === 'xenditCard'
245
+
246
+ // Gating: buyer + every configured holder/custom field complete, required
247
+ // conditions accepted, and payment-method extras filled.
248
+ const b = checkout.billing
249
+ const missingDetails = missingCheckoutDetails(
250
+ {
251
+ billing: b,
252
+ holders: checkout.holders,
253
+ selections: checkout.selections,
254
+ breakdown: checkout.breakdown,
255
+ holderNamesRequired: checkout.holderNamesRequired,
256
+ fieldGates: checkout.fieldGates,
257
+ customFields: checkout.customFields,
258
+ },
259
+ { requireEmailConfirmation, collectTicketHolders, requireHolderContact }
260
+ )
261
+ const billingReady = missingDetails.length === 0
262
+ const conditions = [...(checkout.conditions ?? []), ...additionalConditions]
263
+ const requiredConditions = conditions.filter((c) => c.isRequired)
264
+ const conditionsOk = requiredConditions.every(
265
+ (c) => checkout.acceptedConditions?.[c.id]
266
+ )
267
+ const extra = selectedOption?.extra
268
+ const extrasOk =
269
+ !extra ||
270
+ (extra === 'cashtag'
271
+ ? Boolean(extras[selected]?.cashtag?.trim())
272
+ : Boolean(extras[selected]?.phoneNumber?.trim()))
273
+ const privacyOk = !requirePrivacyPolicy || checkout.consent.ttfOptIn
274
+ // The plan CTA carries the brand's terminology ("Confirm Layaway"), and the
275
+ // terms sentence quotes this same label — they must agree.
276
+ const payLabel = isFree
277
+ ? 'Complete Registration'
278
+ : isPlanSelected
279
+ ? planConfirmLabel(checkout.paymentPlan?.configuration)
280
+ : 'Submit Payment'
281
+ const planTerms = paymentPlanTerms(checkout.paymentPlan?.configuration)
282
+ // 'placing' → order in flight; 'succeeded' → placed, host navigating away.
283
+ // Both keep the CTA busy so it can't be re-clicked during the handoff.
284
+ const finalizing = checkout.status === 'placing' || checkout.status === 'succeeded'
285
+
286
+ const pay = () => {
287
+ setError('')
288
+ setPayCardError(null)
289
+ setCardEditedSincePay(false)
290
+ if (!billingReady || !conditionsOk || !extrasOk || !privacyOk) {
291
+ if (!privacyOk) onPrivacyRequired?.()
292
+ validation.requestValidation()
293
+ return
294
+ }
295
+ // Backfill one holder per ticket if billing was set without holders.
296
+ if (checkout.holders.length === 0 && b) {
297
+ const n = checkout.selections.reduce((acc, s) => acc + s.quantity, 0) || 1
298
+ checkout.setHolders(
299
+ Array.from({ length: n }, () => ({
300
+ firstName: b.firstName,
301
+ lastName: b.lastName,
302
+ email: b.email,
303
+ }))
304
+ )
305
+ }
306
+ let req: PaymentRequest = { method: 'auto' }
307
+ const id = selectedOption?.id
308
+ if (isFree || !id) req = { method: 'auto' }
309
+ else if (id.kind === 'xenditEWallet')
310
+ req = { method: 'xenditEWallet', walletKey: id.walletKey, extra: extras[selected] }
311
+ else if (id.kind === 'redirect')
312
+ req = { method: 'redirect', methodType: id.methodType }
313
+ else if (id.kind === 'paymentPlan')
314
+ req = { method: 'paymentPlan', useSavedCard: reuseSavedCard }
315
+ else req = { method: id.kind } as PaymentRequest
316
+ // NOTE: called synchronously in the click handler — popup rails (e-wallet,
317
+ // redirect, razorpay, paypal) need the user gesture or the browser blocks them.
318
+ checkout
319
+ .placeOrder(req)
320
+ .then((order) => onComplete?.(order))
321
+ .catch((e) => {
322
+ const message = errorMessage(e)
323
+ if (usesCardDetails && isCardAreaError(message)) {
324
+ const behavior = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches
325
+ ? 'auto'
326
+ : 'smooth'
327
+ cardSectionRef.current?.scrollIntoView({ behavior, block: 'center' })
328
+ // Stripe's CardElement prints the message inside its own widget, so
329
+ // scrolling to it is enough. Ours doesn't — show it AT the card box,
330
+ // not down by the button where it reads as an unrelated failure.
331
+ if (cardWidgetReportsItsOwnError) return
332
+ setPayCardError(message)
333
+ return
334
+ }
335
+ setError(message)
336
+ })
337
+ }
338
+
339
+ // A card problem surfaced by the engine belongs at the box too, not under the
340
+ // pay button — same rule as the ones we catch in `pay()`.
341
+ // Whether the engine's error is a CARD problem at all. This must not depend on
342
+ // whether the buyer has since edited: the edit decides if we still SHOW it, it
343
+ // must never decide whether it may fall through to the button (it may not — a
344
+ // card error belongs at the card, always).
345
+ const engineErrorIsCardArea = Boolean(
346
+ isXendit && checkout.error && isCardAreaError(checkout.error)
347
+ )
348
+ const engineCardError =
349
+ engineErrorIsCardArea && !cardEditedSincePay ? checkout.error : ''
350
+ // The buyer's live field state wins over a stale decline from a past attempt.
351
+ const cardAreaError = cardFieldError || payCardError || engineCardError
352
+ const checkoutError =
353
+ checkout.error &&
354
+ !(cardWidgetReportsItsOwnError && isCardFieldError(checkout.error)) &&
355
+ !engineErrorIsCardArea
356
+ ? checkout.error
357
+ : ''
358
+ // Single gate for the message under the pay button: whatever the source, a
359
+ // card problem is shown at the card and NEVER duplicated down here.
360
+ const bottomMessage = error || checkoutError
361
+ const bottomError =
362
+ bottomMessage && isXendit && isCardAreaError(bottomMessage) ? '' : bottomMessage
363
+
364
+ // The card/plan field + its note + plan terms. Rendered inside the selected
365
+ // method row when there's a choice, or directly when there's only a card.
366
+ const paymentInput = (
367
+ <>
368
+ {(isCardSelected || (isPlanSelected && !reuseSavedCard)) && (
369
+ <>
370
+ {useWalletElement ? (
371
+ // The Payment Element frames itself — don't box it again.
372
+ <div ref={cardSectionRef} className="tf-checkout-payment__element">
373
+ <StripePaymentElement
374
+ elementsConfig={checkout.stripeElementsConfig}
375
+ wallets={checkout.walletAvailability}
376
+ />
377
+ </div>
378
+ ) : (
379
+ <div
380
+ ref={cardSectionRef}
381
+ className={cx(
382
+ 'tf-checkout-payment__cardbox',
383
+ isXendit && cardAreaError && 'tf-checkout-payment__cardbox--invalid'
384
+ )}
385
+ >
386
+ {isXendit ? (
387
+ <XenditCardInput
388
+ onValidationChange={(m) => {
389
+ setCardFieldError(m)
390
+ // Any edit supersedes the previous attempt's verdict — the
391
+ // buyer shouldn't be told a number is invalid while they're
392
+ // typing a valid one.
393
+ setPayCardError(null)
394
+ setCardEditedSincePay(true)
395
+ }}
396
+ />
397
+ ) : (
398
+ <CardInput />
399
+ )}
400
+ </div>
401
+ )}
402
+ {/* Below the box, not inside it — Stripe prints its own message within
403
+ its iframe, but the Xendit fields are ours to caption. */}
404
+ {isXendit && cardAreaError && (
405
+ <p className="tf-checkout-error-text">{cardAreaError}</p>
406
+ )}
407
+ {showTestCardHint && (
408
+ <p className="tf-checkout-note">
409
+ {isXendit
410
+ ? 'Test card: 4000 0000 0000 0002 · any future date · any CVC'
411
+ : 'Test card: 4242 4242 4242 4242 · any future date · any CVC'}
412
+ </p>
413
+ )}
414
+ </>
415
+ )}
416
+ {/* The full hosted terms block. Composed in the SDK so web and native
417
+ state the identical schedule, admin fee and non-refundable clause —
418
+ these are disclosures, not summary copy. */}
419
+ {isPlanSelected && planTerms.length > 0 && (
420
+ <div className="tf-checkout-payment__plan">
421
+ <strong>{planTermsTitle(checkout.paymentPlan!.configuration!)}</strong>
422
+ {planTerms.map((part) => (
423
+ <p key={part.id} className="tf-checkout-note">
424
+ {part.text}
425
+ </p>
426
+ ))}
427
+ </div>
428
+ )}
429
+ {/* Returning plan buyer with a reusable card on file. Ticked by default,
430
+ and when it stays ticked the card fields never mount — the plan is
431
+ created straight off the saved payment method, like the hosted flow. */}
432
+ {isPlanSelected && savedLast4 && (
433
+ <div className="tf-checkout-payment__plan-savedcard">
434
+ <p className="tf-checkout-note">
435
+ Your payment will proceed with the card ending in{' '}
436
+ <strong>**** {savedLast4}</strong>
437
+ </p>
438
+ <Checkbox
439
+ checked={useSavedCard}
440
+ onChange={(e) => setUseSavedCard(e.target.checked)}
441
+ label="Use this card"
442
+ />
443
+ </div>
444
+ )}
445
+ </>
446
+ )
447
+
448
+ return (
449
+ <div className={['tf-checkout-payment-stack', className].filter(Boolean).join(' ')}>
450
+ <Card>
451
+ <SectionHeader title="Payment" />
452
+
453
+ {/* Payment method */}
454
+ {!isFree && (
455
+ <>
456
+ {!singleCard && (
457
+ <div className="tf-checkout-payment__label">Payment method</div>
458
+ )}
459
+ {!methods ? (
460
+ <div className="tf-checkout-payment__cardbox">
461
+ <Loader />
462
+ </div>
463
+ ) : singleCard ? (
464
+ paymentInput
465
+ ) : (
466
+ <PaymentMethods
467
+ options={options}
468
+ selected={selected}
469
+ onSelect={setSelected}
470
+ extraValues={extras}
471
+ onExtraChange={(v, patch) =>
472
+ setExtras((s) => ({ ...s, [v]: { ...s[v], ...patch } }))
473
+ }
474
+ showValidation={validation.attempt > 0}
475
+ /**
476
+ * The plan row ALWAYS owns the slot when it's selected. This
477
+ * used to be conditional on needing a card field, which meant a
478
+ * returning buyer reusing their saved card got `undefined` — and
479
+ * `undefined` renders the children nowhere, so the plan terms
480
+ * AND the "card ending in ****" block both vanished. The card
481
+ * field inside is separately gated on `!reuseSavedCard`, so the
482
+ * slot itself never needs to be.
483
+ */
484
+ inputSlotFor={isPlanSelected ? 'paymentPlan' : cardValue}
485
+ >
486
+ {paymentInput}
487
+ </PaymentMethods>
488
+ )}
489
+ </>
490
+ )}
491
+
492
+ {/* Conditions */}
493
+ {conditions.map((c) => {
494
+ const invalid =
495
+ validation.attempt > 0 && c.isRequired && !checkout.acceptedConditions?.[c.id]
496
+ return (
497
+ <div
498
+ key={c.id}
499
+ className={invalid ? 'tf-checkout-consent--error' : undefined}
500
+ data-checkout-invalid={invalid || undefined}
501
+ >
502
+ <Checkbox
503
+ required={c.isRequired}
504
+ checked={Boolean(checkout.acceptedConditions?.[c.id])}
505
+ aria-invalid={invalid}
506
+ onChange={(e) => checkout.acceptCondition(c.id, e.target.checked)}
507
+ label={
508
+ <>
509
+ <span dangerouslySetInnerHTML={{ __html: c.content || c.name }} />
510
+ {c.isRequired && ' *'}
511
+ </>
512
+ }
513
+ />
514
+ {invalid && (
515
+ <div className="tf-checkout-consent__error">
516
+ You must accept this condition to continue.
517
+ </div>
518
+ )}
519
+ </div>
520
+ )
521
+ })}
522
+ </Card>
523
+
524
+ <OrderSummary eventId={eventId} />
525
+
526
+ <div className="tf-checkout-payment__cta">
527
+ <Button
528
+ onClick={pay}
529
+ // Stay busy through 'succeeded' too: in redirect mode the checkout
530
+ // remains mounted while the host navigates away, so the button must
531
+ // not flicker back to a clickable state before the redirect lands.
532
+ loading={finalizing}
533
+ disabled={checkout.isBusy || finalizing || (!isFree && !methods)}
534
+ >
535
+ {finalizing ? 'Placing…' : payLabel}
536
+ </Button>
537
+ </div>
538
+ {bottomError && <p className="tf-checkout-error-text">{bottomError}</p>}
539
+ </div>
540
+ )
541
+ }