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.
- package/LICENSE +1 -1
- package/README.md +141 -1033
- package/dist/checkout.css +17 -0
- package/dist/index.d.mts +3930 -0
- package/dist/index.d.ts +3930 -30
- package/dist/index.esm.js +9123 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +9277 -6
- package/dist/index.js.map +1 -0
- package/dist/styles/addons.css +75 -0
- package/dist/styles/auth.css +294 -0
- package/dist/styles/billing.css +98 -0
- package/dist/styles/confirmation.css +51 -0
- package/dist/styles/foundation.css +146 -0
- package/dist/styles/payment.css +179 -0
- package/dist/styles/primitives.css +356 -0
- package/dist/styles/seat-map.css +46 -0
- package/dist/styles/tickets.css +285 -0
- package/dist/styles/verification-confirmation.css +258 -0
- package/package.json +93 -78
- package/src/.d.ts +1 -1
- package/src/CardInput.tsx +374 -0
- package/src/EmbeddedCheckout.tsx +400 -0
- package/src/ResumedCheckout.tsx +132 -0
- package/src/auth/AuthModal.tsx +231 -0
- package/src/auth/ForgotPasswordForm.tsx +93 -0
- package/src/auth/LoginForm.tsx +104 -0
- package/src/auth/PasswordInput.tsx +33 -0
- package/src/auth/RegisterForm.tsx +333 -0
- package/src/auth/ResetPasswordForm.tsx +112 -0
- package/src/auth/index.ts +5 -0
- package/src/checkout.css +17 -0
- package/src/configure.ts +29 -0
- package/src/confirmer.ts +439 -0
- package/src/index.ts +41 -30
- package/src/instance.ts +21 -0
- package/src/sections/AddOns.tsx +241 -0
- package/src/sections/BillingInfo.tsx +743 -0
- package/src/sections/Confirmation.tsx +146 -0
- package/src/sections/IDVerification.tsx +76 -0
- package/src/sections/OrderConfirmation.tsx +277 -0
- package/src/sections/OrderIDVerification.tsx +117 -0
- package/src/sections/OrderSummary.tsx +84 -0
- package/src/sections/Payment.tsx +541 -0
- package/src/sections/SeatMap.tsx +512 -0
- package/src/sections/Tickets.tsx +573 -0
- package/src/sections/billing/BillingAddressFields.tsx +138 -0
- package/src/sections/billing/BuyerField.tsx +75 -0
- package/src/sections/billing/TicketHoldersCard.tsx +119 -0
- package/src/sections/billing/types.ts +10 -0
- package/src/sections/index.ts +15 -0
- package/src/sections/seatMap.utils.ts +105 -0
- package/src/styles/addons.css +75 -0
- package/src/styles/auth.css +294 -0
- package/src/styles/billing.css +98 -0
- package/src/styles/confirmation.css +51 -0
- package/src/styles/foundation.css +146 -0
- package/src/styles/payment.css +179 -0
- package/src/styles/primitives.css +356 -0
- package/src/styles/seat-map.css +46 -0
- package/src/styles/tickets.css +285 -0
- package/src/styles/verification-confirmation.css +258 -0
- package/src/typings.d.ts +2 -2
- package/src/ui/Button.tsx +38 -0
- package/src/ui/Card.tsx +54 -0
- package/src/ui/CheckoutProvider.tsx +172 -0
- package/src/ui/CustomFields.tsx +195 -0
- package/src/ui/Field.tsx +114 -0
- package/src/ui/I18nProvider.tsx +36 -0
- package/src/ui/InstallmentPicker.tsx +69 -0
- package/src/ui/Loader.tsx +12 -0
- package/src/ui/PaymentMethods.tsx +133 -0
- package/src/ui/PriceLine.tsx +24 -0
- package/src/ui/QuantitySelect.tsx +50 -0
- package/src/ui/Stepper.tsx +36 -0
- package/src/ui/Timer.tsx +34 -0
- package/src/ui/TimerBanner.tsx +55 -0
- package/src/ui/cx.ts +3 -0
- package/src/ui/index.ts +54 -0
- package/src/ui/theme.ts +83 -0
- package/src/useCheckout.ts +35 -0
- package/src/xendit.ts +438 -0
- package/dist/adapters/customFields.d.ts +0 -12
- package/dist/adapters/index.d.ts +0 -1
- package/dist/api/auth.d.ts +0 -27
- package/dist/api/cart.d.ts +0 -2
- package/dist/api/checkout.d.ts +0 -3
- package/dist/api/common.d.ts +0 -11
- package/dist/api/guestTicketDelegation.d.ts +0 -47
- package/dist/api/index.d.ts +0 -82
- package/dist/api/interceptors.d.ts +0 -1
- package/dist/api/orders.d.ts +0 -2
- package/dist/api/payment.d.ts +0 -5
- package/dist/api/preRegistrationComplete.d.ts +0 -3
- package/dist/api/publicRequest.d.ts +0 -9
- package/dist/api/resale.d.ts +0 -5
- package/dist/components/account-settings/index.d.ts +0 -3
- package/dist/components/addonsContainer/AddonComponent.d.ts +0 -18
- package/dist/components/addonsContainer/SimpleAddonsContainer.d.ts +0 -20
- package/dist/components/addonsContainer/adapters/index.d.ts +0 -12
- package/dist/components/addonsContainer/index.d.ts +0 -22
- package/dist/components/addonsContainer/normalizers/index.d.ts +0 -1
- package/dist/components/addonsContainer/useAddons.d.ts +0 -23
- package/dist/components/addonsContainer/utils/index.d.ts +0 -16
- package/dist/components/billing-info-container/hooks/index.d.ts +0 -3
- package/dist/components/billing-info-container/hooks/usePaymentContext.d.ts +0 -5
- package/dist/components/billing-info-container/hooks/usePaymentRedirect.d.ts +0 -14
- package/dist/components/billing-info-container/hooks/useStripePayment.d.ts +0 -18
- package/dist/components/billing-info-container/index.d.ts +0 -69
- package/dist/components/billing-info-container/utils.d.ts +0 -59
- package/dist/components/common/Checkbox.d.ts +0 -11
- package/dist/components/common/CheckboxField/index.d.ts +0 -9
- package/dist/components/common/CopyField.d.ts +0 -12
- package/dist/components/common/CopyMessageModal.d.ts +0 -7
- package/dist/components/common/CustomField.d.ts +0 -26
- package/dist/components/common/DatePickerField.d.ts +0 -20
- package/dist/components/common/FieldSection/index.d.ts +0 -19
- package/dist/components/common/FieldSection/utils/index.d.ts +0 -8
- package/dist/components/common/FormikPhoneNumberField.d.ts +0 -11
- package/dist/components/common/Loader.d.ts +0 -2
- package/dist/components/common/ModalComponent/index.d.ts +0 -16
- package/dist/components/common/NativeSelectFeild/index.d.ts +0 -21
- package/dist/components/common/PhoneNumberField.d.ts +0 -14
- package/dist/components/common/PoweredBy.d.ts +0 -2
- package/dist/components/common/RadioField.d.ts +0 -11
- package/dist/components/common/RadioGroupField/index.d.ts +0 -17
- package/dist/components/common/RedirectModal.d.ts +0 -7
- package/dist/components/common/SelectField/index.d.ts +0 -19
- package/dist/components/common/SnackbarAlert.d.ts +0 -13
- package/dist/components/common/index.d.ts +0 -11
- package/dist/components/common/socials.d.ts +0 -10
- package/dist/components/confirmModal/index.d.ts +0 -10
- package/dist/components/confirmationContainer/config.d.ts +0 -1
- package/dist/components/confirmationContainer/index.d.ts +0 -46
- package/dist/components/confirmationContainer/social-buttons.d.ts +0 -16
- package/dist/components/countdown/index.d.ts +0 -14
- package/dist/components/delegationsContainer/IssueComponent.d.ts +0 -10
- package/dist/components/delegationsContainer/IssueTicketForm.d.ts +0 -9
- package/dist/components/delegationsContainer/TicketsAssignedTable.d.ts +0 -11
- package/dist/components/delegationsContainer/TicketsAvailableTable.d.ts +0 -11
- package/dist/components/delegationsContainer/index.d.ts +0 -10
- package/dist/components/forgotPasswordModal/index.d.ts +0 -12
- package/dist/components/idVerificationContainer/VerificationPendingModal.d.ts +0 -10
- package/dist/components/idVerificationContainer/constants.d.ts +0 -21
- package/dist/components/idVerificationContainer/index.d.ts +0 -16
- package/dist/components/index.d.ts +0 -12
- package/dist/components/loginForm/index.d.ts +0 -31
- package/dist/components/loginModal/SignUpForm.d.ts +0 -10
- package/dist/components/loginModal/constants.d.ts +0 -39
- package/dist/components/loginModal/index.d.ts +0 -22
- package/dist/components/myTicketsContainer/index.d.ts +0 -16
- package/dist/components/myTicketsContainer/row.d.ts +0 -3
- package/dist/components/myTicketsContainer/tableConfig.d.ts +0 -5
- package/dist/components/orderDetailsContainer/CustomFieldsForm.d.ts +0 -12
- package/dist/components/orderDetailsContainer/TicketHolderCustomFields.d.ts +0 -10
- package/dist/components/orderDetailsContainer/index.d.ts +0 -66
- package/dist/components/orderDetailsContainer/ticketsTable.d.ts +0 -46
- package/dist/components/orderDetailsContainer/utils/index.d.ts +0 -6
- package/dist/components/paymentContainer/OrderDetails.d.ts +0 -9
- package/dist/components/paymentContainer/PaymentPlanSection.d.ts +0 -10
- package/dist/components/paymentContainer/handlePayment.d.ts +0 -15
- package/dist/components/paymentContainer/index.d.ts +0 -39
- package/dist/components/preRegistration/FieldsSection.d.ts +0 -19
- package/dist/components/preRegistration/Influancers.d.ts +0 -2
- package/dist/components/preRegistration/PreRegistrationComplete.d.ts +0 -13
- package/dist/components/preRegistration/PreRegistrationInformations.d.ts +0 -2
- package/dist/components/preRegistration/Prewards.d.ts +0 -2
- package/dist/components/preRegistration/ShareOptions.d.ts +0 -2
- package/dist/components/preRegistration/constants.d.ts +0 -2
- package/dist/components/preRegistration/index.d.ts +0 -23
- package/dist/components/preRegistration/utils.d.ts +0 -12
- package/dist/components/registerForm/adapters/index.d.ts +0 -4
- package/dist/components/registerForm/constants.d.ts +0 -1
- package/dist/components/registerForm/index.d.ts +0 -16
- package/dist/components/registerModal/index.d.ts +0 -12
- package/dist/components/resetPasswordContainer/index.d.ts +0 -10
- package/dist/components/rsvpContainer/index.d.ts +0 -7
- package/dist/components/seatMapContainer/SeatMapComponent.d.ts +0 -8
- package/dist/components/seatMapContainer/TicketsSection.d.ts +0 -9
- package/dist/components/seatMapContainer/addToCart.d.ts +0 -14
- package/dist/components/seatMapContainer/index.d.ts +0 -2
- package/dist/components/seatMapContainer/utils.d.ts +0 -6
- package/dist/components/signupModal/index.d.ts +0 -12
- package/dist/components/ticketResale/index.d.ts +0 -12
- package/dist/components/ticketResaleModal/index.d.ts +0 -19
- package/dist/components/ticketsContainer/AccessCodeSection.d.ts +0 -7
- package/dist/components/ticketsContainer/InfoIcon.d.ts +0 -5
- package/dist/components/ticketsContainer/PromoCodeSection.d.ts +0 -15
- package/dist/components/ticketsContainer/ReferralLogic.d.ts +0 -5
- package/dist/components/ticketsContainer/TicketRow.d.ts +0 -13
- package/dist/components/ticketsContainer/TicketsSection.d.ts +0 -20
- package/dist/components/ticketsContainer/TimeSlotTicketRow.d.ts +0 -19
- package/dist/components/ticketsContainer/TimeSlotsSection.d.ts +0 -25
- package/dist/components/ticketsContainer/index.d.ts +0 -93
- package/dist/components/ticketsContainer/utils.d.ts +0 -13
- package/dist/components/timerWidget/index.d.ts +0 -16
- package/dist/components/waitingList/index.d.ts +0 -9
- package/dist/constants/index.d.ts +0 -7
- package/dist/env.d.ts +0 -16
- package/dist/hoc/CustomFields/index.d.ts +0 -3
- package/dist/hoc/index.d.ts +0 -1
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/useCookieListener.d.ts +0 -1
- package/dist/hooks/useEventListener.d.ts +0 -1
- package/dist/hooks/useLocalStorageListener.d.ts +0 -1
- package/dist/hooks/useOnline.d.ts +0 -1
- package/dist/hooks/usePixel.d.ts +0 -6
- package/dist/images/Polygon.png +0 -0
- package/dist/images/cross.svg +0 -44
- package/dist/images/done.svg +0 -3
- package/dist/images/edit.svg +0 -10
- package/dist/images/email.svg +0 -1
- package/dist/images/instagram.svg +0 -5
- package/dist/images/logo-ttf.png +0 -0
- package/dist/images/spotify.svg +0 -6
- package/dist/images/user.svg +0 -1
- package/dist/images/xmark.svg +0 -92
- package/dist/normalizers/index.d.ts +0 -4
- package/dist/tf-checkout-react.cjs.development.js +0 -16149
- package/dist/tf-checkout-react.cjs.development.js.map +0 -1
- package/dist/tf-checkout-react.cjs.production.min.js +0 -2
- package/dist/tf-checkout-react.cjs.production.min.js.map +0 -1
- package/dist/tf-checkout-react.esm.js +0 -16116
- package/dist/tf-checkout-react.esm.js.map +0 -1
- package/dist/tf-checkout-styles.css +0 -1
- package/dist/types/add_on.d.ts +0 -8
- package/dist/types/billing-info-data.d.ts +0 -27
- package/dist/types/checkoutPageConfigs.d.ts +0 -13
- package/dist/types/index.d.ts +0 -6
- package/dist/types/order-data.d.ts +0 -15
- package/dist/types/payment-field.d.ts +0 -6
- package/dist/types/payment-plan-configuration.d.ts +0 -18
- package/dist/types/referral-promotion.d.ts +0 -6
- package/dist/types/verification.d.ts +0 -12
- package/dist/utils/adaptStripeErrors.d.ts +0 -8
- package/dist/utils/auth.d.ts +0 -21
- package/dist/utils/cookies.d.ts +0 -3
- package/dist/utils/createCheckoutDataBodyWithDefaultHolder.d.ts +0 -23
- package/dist/utils/createMarkup.d.ts +0 -3
- package/dist/utils/customFields.d.ts +0 -35
- package/dist/utils/downloadPDF.d.ts +0 -1
- package/dist/utils/form.d.ts +0 -3
- package/dist/utils/formikErrorFocus.d.ts +0 -2
- package/dist/utils/getDomain.d.ts +0 -1
- package/dist/utils/getImage.d.ts +0 -1
- package/dist/utils/getQueryVariable.d.ts +0 -1
- package/dist/utils/htmlNodeFromString.d.ts +0 -1
- package/dist/utils/index.d.ts +0 -15
- package/dist/utils/isBrowser.d.ts +0 -1
- package/dist/utils/isValidNumber.d.ts +0 -1
- package/dist/utils/jsonUtils.d.ts +0 -1
- package/dist/utils/replaceVarInString.d.ts +0 -1
- package/dist/utils/setConfigs.d.ts +0 -11
- package/dist/utils/showZero.d.ts +0 -1
- package/dist/validators/index.d.ts +0 -8
- package/src/adapters/customFields.ts +0 -85
- package/src/adapters/index.ts +0 -1
- package/src/api/auth.ts +0 -88
- package/src/api/cart.ts +0 -28
- package/src/api/checkout.ts +0 -28
- package/src/api/common.ts +0 -190
- package/src/api/guestTicketDelegation.ts +0 -79
- package/src/api/index.ts +0 -346
- package/src/api/interceptors.ts +0 -77
- package/src/api/orders.ts +0 -30
- package/src/api/payment.ts +0 -77
- package/src/api/preRegistrationComplete.ts +0 -37
- package/src/api/publicRequest.ts +0 -47
- package/src/api/resale.ts +0 -28
- package/src/assets/images/Polygon.png +0 -0
- package/src/assets/images/cross.svg +0 -44
- package/src/assets/images/done.svg +0 -3
- package/src/assets/images/edit.svg +0 -10
- package/src/assets/images/email.svg +0 -1
- package/src/assets/images/instagram.svg +0 -5
- package/src/assets/images/logo-ttf.png +0 -0
- package/src/assets/images/spotify.svg +0 -6
- package/src/assets/images/user.svg +0 -1
- package/src/assets/images/xmark.svg +0 -92
- package/src/components/account-settings/index.tsx +0 -161
- package/src/components/account-settings/style.css +0 -200
- package/src/components/addonsContainer/AddonComponent.tsx +0 -204
- package/src/components/addonsContainer/SimpleAddonsContainer.tsx +0 -459
- package/src/components/addonsContainer/adapters/index.tsx +0 -62
- package/src/components/addonsContainer/index.tsx +0 -353
- package/src/components/addonsContainer/normalizers/index.ts +0 -5
- package/src/components/addonsContainer/useAddons.ts +0 -248
- package/src/components/addonsContainer/utils/index.tsx +0 -231
- package/src/components/billing-info-container/hooks/index.ts +0 -3
- package/src/components/billing-info-container/hooks/usePaymentContext.ts +0 -22
- package/src/components/billing-info-container/hooks/usePaymentRedirect.ts +0 -145
- package/src/components/billing-info-container/hooks/useStripePayment.ts +0 -119
- package/src/components/billing-info-container/index.tsx +0 -1695
- package/src/components/billing-info-container/style.css +0 -150
- package/src/components/billing-info-container/utils.tsx +0 -413
- package/src/components/common/Checkbox.tsx +0 -51
- package/src/components/common/CheckboxField/index.tsx +0 -41
- package/src/components/common/CopyField.tsx +0 -53
- package/src/components/common/CopyMessageModal.tsx +0 -34
- package/src/components/common/CustomField.tsx +0 -168
- package/src/components/common/DatePickerField.tsx +0 -126
- package/src/components/common/FieldSection/index.tsx +0 -141
- package/src/components/common/FieldSection/utils/index.tsx +0 -92
- package/src/components/common/FormikPhoneNumberField.tsx +0 -51
- package/src/components/common/Loader.tsx +0 -8
- package/src/components/common/ModalComponent/index.tsx +0 -68
- package/src/components/common/NativeSelectFeild/index.tsx +0 -86
- package/src/components/common/PhoneNumberField.tsx +0 -117
- package/src/components/common/PoweredBy.tsx +0 -15
- package/src/components/common/RadioField.tsx +0 -36
- package/src/components/common/RadioGroupField/index.tsx +0 -76
- package/src/components/common/RedirectModal.tsx +0 -43
- package/src/components/common/SelectField/index.tsx +0 -104
- package/src/components/common/SnackbarAlert.tsx +0 -52
- package/src/components/common/index.tsx +0 -11
- package/src/components/common/socials.tsx +0 -33
- package/src/components/confirmModal/index.tsx +0 -60
- package/src/components/confirmationContainer/config.ts +0 -79
- package/src/components/confirmationContainer/index.tsx +0 -349
- package/src/components/confirmationContainer/social-buttons.tsx +0 -149
- package/src/components/confirmationContainer/style.css +0 -206
- package/src/components/countdown/index.tsx +0 -100
- package/src/components/countdown/style.css +0 -10
- package/src/components/delegationsContainer/IssueComponent.tsx +0 -156
- package/src/components/delegationsContainer/IssueTicketForm.tsx +0 -109
- package/src/components/delegationsContainer/TicketsAssignedTable.tsx +0 -55
- package/src/components/delegationsContainer/TicketsAvailableTable.tsx +0 -54
- package/src/components/delegationsContainer/index.tsx +0 -83
- package/src/components/forgotPasswordModal/index.tsx +0 -138
- package/src/components/forgotPasswordModal/style.css +0 -47
- package/src/components/idVerificationContainer/VerificationPendingModal.tsx +0 -47
- package/src/components/idVerificationContainer/constants.ts +0 -27
- package/src/components/idVerificationContainer/index.tsx +0 -323
- package/src/components/index.ts +0 -12
- package/src/components/loginForm/index.tsx +0 -202
- package/src/components/loginModal/SignUpForm.tsx +0 -329
- package/src/components/loginModal/constants.ts +0 -46
- package/src/components/loginModal/index.tsx +0 -263
- package/src/components/loginModal/style.css +0 -116
- package/src/components/myTicketsContainer/index.tsx +0 -228
- package/src/components/myTicketsContainer/row.tsx +0 -46
- package/src/components/myTicketsContainer/style.css +0 -40
- package/src/components/myTicketsContainer/tableConfig.tsx +0 -80
- package/src/components/myTicketsContainer/types.d.ts +0 -41
- package/src/components/orderDetailsContainer/CustomFieldsForm.tsx +0 -75
- package/src/components/orderDetailsContainer/TicketHolderCustomFields.tsx +0 -100
- package/src/components/orderDetailsContainer/index.tsx +0 -586
- package/src/components/orderDetailsContainer/style.css +0 -77
- package/src/components/orderDetailsContainer/ticketsTable.tsx +0 -246
- package/src/components/orderDetailsContainer/utils/index.tsx +0 -55
- package/src/components/paymentContainer/OrderDetails.tsx +0 -277
- package/src/components/paymentContainer/PaymentPlanSection.tsx +0 -169
- package/src/components/paymentContainer/handlePayment.ts +0 -86
- package/src/components/paymentContainer/index.tsx +0 -643
- package/src/components/paymentContainer/style.css +0 -196
- package/src/components/preRegistration/FieldsSection.tsx +0 -150
- package/src/components/preRegistration/Influancers.tsx +0 -34
- package/src/components/preRegistration/PreRegistrationComplete.tsx +0 -186
- package/src/components/preRegistration/PreRegistrationInformations.tsx +0 -60
- package/src/components/preRegistration/Prewards.tsx +0 -41
- package/src/components/preRegistration/ShareOptions.tsx +0 -77
- package/src/components/preRegistration/constants.tsx +0 -169
- package/src/components/preRegistration/index.tsx +0 -330
- package/src/components/preRegistration/style.css +0 -3
- package/src/components/preRegistration/utils.ts +0 -163
- package/src/components/registerForm/adapters/index.tsx +0 -10
- package/src/components/registerForm/constants.tsx +0 -98
- package/src/components/registerForm/index.tsx +0 -188
- package/src/components/registerModal/index.tsx +0 -154
- package/src/components/registerModal/style.css +0 -18
- package/src/components/resetPasswordContainer/index.tsx +0 -102
- package/src/components/resetPasswordContainer/style.css +0 -36
- package/src/components/rsvpContainer/index.tsx +0 -126
- package/src/components/seatMapContainer/SeatMapComponent.tsx +0 -77
- package/src/components/seatMapContainer/TicketsSection.tsx +0 -286
- package/src/components/seatMapContainer/addToCart.ts +0 -66
- package/src/components/seatMapContainer/index.tsx +0 -443
- package/src/components/seatMapContainer/utils.ts +0 -133
- package/src/components/signupModal/index.tsx +0 -178
- package/src/components/signupModal/style.css +0 -58
- package/src/components/ticketResale/index.tsx +0 -86
- package/src/components/ticketResaleModal/index.tsx +0 -224
- package/src/components/ticketResaleModal/style.css +0 -28
- package/src/components/ticketsContainer/AccessCodeSection.tsx +0 -50
- package/src/components/ticketsContainer/InfoIcon.tsx +0 -35
- package/src/components/ticketsContainer/PromoCodeSection.tsx +0 -116
- package/src/components/ticketsContainer/ReferralLogic.tsx +0 -33
- package/src/components/ticketsContainer/TicketRow.tsx +0 -107
- package/src/components/ticketsContainer/TicketsSection.tsx +0 -350
- package/src/components/ticketsContainer/TimeSlotTicketRow.tsx +0 -243
- package/src/components/ticketsContainer/TimeSlotsSection.tsx +0 -194
- package/src/components/ticketsContainer/index.tsx +0 -986
- package/src/components/ticketsContainer/style.css +0 -178
- package/src/components/ticketsContainer/utils.ts +0 -35
- package/src/components/timerWidget/index.tsx +0 -97
- package/src/components/timerWidget/style.css +0 -35
- package/src/components/waitingList/index.tsx +0 -190
- package/src/components/waitingList/style.css +0 -27
- package/src/constants/index.ts +0 -3
- package/src/env.ts +0 -29
- package/src/hoc/CustomFields/index.tsx +0 -85
- package/src/hoc/index.ts +0 -1
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useCookieListener.ts +0 -32
- package/src/hooks/useEventListener.ts +0 -32
- package/src/hooks/useLocalStorageListener.ts +0 -32
- package/src/hooks/useOnline.ts +0 -21
- package/src/hooks/usePixel.ts +0 -88
- package/src/normalizers/index.ts +0 -49
- package/src/types/add_on.ts +0 -8
- package/src/types/api/auth.d.ts +0 -63
- package/src/types/api/axiosResponse.d.ts +0 -6
- package/src/types/api/cart.d.ts +0 -73
- package/src/types/api/checkout.d.ts +0 -92
- package/src/types/api/common.d.ts +0 -153
- package/src/types/api/guestTicketDelegation.d.ts +0 -18
- package/src/types/api/orders.d.ts +0 -116
- package/src/types/api/payment.d.ts +0 -180
- package/src/types/api/preRegistration.d.ts +0 -11
- package/src/types/api/preRegistrationComplete.d.ts +0 -95
- package/src/types/api/ticketResale.d.ts +0 -13
- package/src/types/billing-info-data.ts +0 -37
- package/src/types/checkoutPageConfigs.ts +0 -13
- package/src/types/formFields.d.ts +0 -29
- package/src/types/index.ts +0 -6
- package/src/types/order-data.ts +0 -16
- package/src/types/payment-field.ts +0 -7
- package/src/types/payment-plan-configuration.ts +0 -19
- package/src/types/pre-registration-complete.d.ts +0 -47
- package/src/types/referral-promotion.ts +0 -7
- package/src/types/seatMap.d.ts +0 -159
- package/src/types/verification.ts +0 -12
- package/src/utils/adaptStripeErrors.ts +0 -26
- package/src/utils/auth.ts +0 -45
- package/src/utils/cookies.ts +0 -73
- package/src/utils/createCheckoutDataBodyWithDefaultHolder.ts +0 -81
- package/src/utils/createMarkup.ts +0 -1
- package/src/utils/customFields.ts +0 -80
- package/src/utils/downloadPDF.tsx +0 -42
- package/src/utils/form.ts +0 -34
- package/src/utils/formikErrorFocus.ts +0 -24
- package/src/utils/getDomain.ts +0 -21
- package/src/utils/getImage.ts +0 -14
- package/src/utils/getQueryVariable.ts +0 -13
- package/src/utils/htmlNodeFromString.ts +0 -6
- package/src/utils/index.ts +0 -15
- package/src/utils/isBrowser.ts +0 -2
- package/src/utils/isValidNumber.ts +0 -8
- package/src/utils/jsonUtils.ts +0 -8
- package/src/utils/replaceVarInString.ts +0 -9
- package/src/utils/setConfigs.ts +0 -24
- package/src/utils/showZero.tsx +0 -10
- package/src/validators/index.ts +0 -61
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Tickets/>` — ticket selection. Lists the event's ticket types with a
|
|
3
|
+
* quantity dropdown, applies promo / access codes (re-pricing + unlocking
|
|
4
|
+
* tickets), offers a waiting-list sign-up on sold-out types, and primes the
|
|
5
|
+
* cart. Matches the old checkout: no running total, a `GET TICKETS` CTA.
|
|
6
|
+
*/
|
|
7
|
+
import React, {
|
|
8
|
+
Fragment,
|
|
9
|
+
useEffect,
|
|
10
|
+
useRef,
|
|
11
|
+
useState,
|
|
12
|
+
type FC,
|
|
13
|
+
type ReactNode,
|
|
14
|
+
} from 'react'
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
errorMessage,
|
|
18
|
+
hooks,
|
|
19
|
+
ticketQuantityRange,
|
|
20
|
+
type TicketType,
|
|
21
|
+
type WaitingListEntry,
|
|
22
|
+
} from 'tf-checkout-shared'
|
|
23
|
+
|
|
24
|
+
import { Button } from '../ui/Button'
|
|
25
|
+
import { Card, SectionHeader } from '../ui/Card'
|
|
26
|
+
import { useCheckoutContext } from '../ui/CheckoutProvider'
|
|
27
|
+
import { cx } from '../ui/cx'
|
|
28
|
+
import { Field, FieldRow, Input } from '../ui/Field'
|
|
29
|
+
import { Loader } from '../ui/Loader'
|
|
30
|
+
import { QuantitySelect } from '../ui/QuantitySelect'
|
|
31
|
+
|
|
32
|
+
/** Inline waiting-list sign-up for a sold-out type. */
|
|
33
|
+
const WaitingListForm: FC<{
|
|
34
|
+
ticket: TicketType
|
|
35
|
+
onJoin: (entry: WaitingListEntry) => Promise<void>
|
|
36
|
+
}> = ({ ticket, onJoin }) => {
|
|
37
|
+
const [form, setForm] = useState({ firstName: '', lastName: '', email: '' })
|
|
38
|
+
const [state, setState] = useState<'idle' | 'busy' | 'done' | 'error'>('idle')
|
|
39
|
+
const [error, setError] = useState('')
|
|
40
|
+
const ok = form.firstName.trim() && form.lastName.trim() && form.email.trim()
|
|
41
|
+
|
|
42
|
+
if (state === 'done')
|
|
43
|
+
return (
|
|
44
|
+
<p className="tf-checkout-note tf-checkout-tickets__wl-done">
|
|
45
|
+
You’re on the waiting list — we’ll email you if a spot opens.
|
|
46
|
+
</p>
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className="tf-checkout-tickets__wl">
|
|
51
|
+
<FieldRow>
|
|
52
|
+
<Field>
|
|
53
|
+
<Input
|
|
54
|
+
placeholder="First name"
|
|
55
|
+
value={form.firstName}
|
|
56
|
+
onChange={(e) => setForm((f) => ({ ...f, firstName: e.target.value }))}
|
|
57
|
+
/>
|
|
58
|
+
</Field>
|
|
59
|
+
<Field>
|
|
60
|
+
<Input
|
|
61
|
+
placeholder="Last name"
|
|
62
|
+
value={form.lastName}
|
|
63
|
+
onChange={(e) => setForm((f) => ({ ...f, lastName: e.target.value }))}
|
|
64
|
+
/>
|
|
65
|
+
</Field>
|
|
66
|
+
</FieldRow>
|
|
67
|
+
<Field>
|
|
68
|
+
<Input
|
|
69
|
+
placeholder="Email"
|
|
70
|
+
value={form.email}
|
|
71
|
+
onChange={(e) => setForm((f) => ({ ...f, email: e.target.value }))}
|
|
72
|
+
/>
|
|
73
|
+
</Field>
|
|
74
|
+
<Button
|
|
75
|
+
onClick={() => {
|
|
76
|
+
setState('busy')
|
|
77
|
+
setError('')
|
|
78
|
+
onJoin({ ...form, ticketTypeId: ticket.id })
|
|
79
|
+
.then(() => setState('done'))
|
|
80
|
+
.catch((e) => {
|
|
81
|
+
setState('error')
|
|
82
|
+
setError(errorMessage(e))
|
|
83
|
+
})
|
|
84
|
+
}}
|
|
85
|
+
loading={state === 'busy'}
|
|
86
|
+
disabled={!ok || state === 'busy'}
|
|
87
|
+
variant="secondary"
|
|
88
|
+
>
|
|
89
|
+
Join the waiting list
|
|
90
|
+
</Button>
|
|
91
|
+
{error && <p className="tf-checkout-error-text">{error}</p>}
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface TicketsProps {
|
|
97
|
+
eventId: string
|
|
98
|
+
/** Optional heading above the catalog. The legacy storefront does not show
|
|
99
|
+
* one, so the default is intentionally hidden. */
|
|
100
|
+
title?: ReactNode | false
|
|
101
|
+
/** Fired once the cart is primed (tickets added) — e.g. reveal `<AddOns/>`. */
|
|
102
|
+
onContinue?: () => void
|
|
103
|
+
/** CTA label. Old storefront uses "Get tickets". */
|
|
104
|
+
buttonLabel?: string
|
|
105
|
+
/** Force time-slot mode + supply the selectable session dates (ISO yyyy-mm-dd).
|
|
106
|
+
* Omit to auto-detect from the event (`isTimeSlotEvent` / `availableDates`). */
|
|
107
|
+
timeSlotDates?: string[]
|
|
108
|
+
/** Optional numbered badge (old checkout shows none — omitted by default). */
|
|
109
|
+
step?: ReactNode
|
|
110
|
+
/** SEATED events: fired when the buyer clicks "Select seats". Wire this to
|
|
111
|
+
* reveal `<SeatMap/>`. Without it the seat CTA is hidden (the seat-map ticket
|
|
112
|
+
* types then have no way to be bought — provide it for seated events). */
|
|
113
|
+
onSelectSeats?: () => void
|
|
114
|
+
/** Apply this code once when the ticket catalog mounts. */
|
|
115
|
+
initialPromoCode?: string
|
|
116
|
+
/** Attribute this visit once. URL values use `ttf_r` / `referrer_id`. */
|
|
117
|
+
referrer?: string | number
|
|
118
|
+
/** Also read promo/referral values from the current URL. Defaults true. */
|
|
119
|
+
readAttributionFromUrl?: boolean
|
|
120
|
+
className?: string
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const Tickets: FC<TicketsProps> = ({
|
|
124
|
+
eventId,
|
|
125
|
+
title = false,
|
|
126
|
+
onContinue,
|
|
127
|
+
buttonLabel = 'Get tickets',
|
|
128
|
+
timeSlotDates,
|
|
129
|
+
step,
|
|
130
|
+
onSelectSeats,
|
|
131
|
+
initialPromoCode,
|
|
132
|
+
referrer,
|
|
133
|
+
readAttributionFromUrl = true,
|
|
134
|
+
className,
|
|
135
|
+
}) => {
|
|
136
|
+
const checkout = useCheckoutContext()
|
|
137
|
+
const ticketsQuery = hooks.useTicketsWithMeta(eventId)
|
|
138
|
+
const promoMeta = ticketsQuery.data?.promo
|
|
139
|
+
const showWaitingList = ticketsQuery.data?.showWaitingList ?? false
|
|
140
|
+
|
|
141
|
+
const [qty, setQty] = useState<Record<string, number>>({})
|
|
142
|
+
const [slotDate, setSlotDate] = useState('')
|
|
143
|
+
|
|
144
|
+
// Time-slot / calendar events: pick a date, then buy from that session's slots.
|
|
145
|
+
const eventInfo = hooks.useEvent(eventId).data
|
|
146
|
+
const isTimeSlot = Boolean(timeSlotDates?.length || eventInfo?.isTimeSlotEvent)
|
|
147
|
+
const dates = timeSlotDates ?? eventInfo?.availableDates ?? []
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (isTimeSlot && !slotDate && dates.length) setSlotDate(dates[0])
|
|
150
|
+
}, [isTimeSlot, slotDate, dates])
|
|
151
|
+
const slotQuery = hooks.useTimeSlotTickets(eventId, isTimeSlot ? slotDate : undefined)
|
|
152
|
+
|
|
153
|
+
const tickets = isTimeSlot ? (slotQuery.data ?? []) : (ticketsQuery.data?.tickets ?? [])
|
|
154
|
+
const [error, setError] = useState('')
|
|
155
|
+
const [code, setCode] = useState('')
|
|
156
|
+
const [codeState, setCodeState] = useState<'idle' | 'busy'>('idle')
|
|
157
|
+
const [promoOpen, setPromoOpen] = useState(false)
|
|
158
|
+
const [wlOpen, setWlOpen] = useState<Record<string, boolean>>({})
|
|
159
|
+
const [visibleDescription, setVisibleDescription] = useState<string | null>(null)
|
|
160
|
+
const attributionEvent = useRef<string | null>(null)
|
|
161
|
+
|
|
162
|
+
// Match hosted links: attribute referral visits and apply a carried promo
|
|
163
|
+
// once per event. Explicit props win; URL support can be disabled by hosts
|
|
164
|
+
// that manage routing/attribution themselves.
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
if (attributionEvent.current === eventId) return
|
|
167
|
+
attributionEvent.current = eventId
|
|
168
|
+
|
|
169
|
+
let promo = initialPromoCode?.trim() ?? ''
|
|
170
|
+
let referral: string | number | undefined = referrer
|
|
171
|
+
if (readAttributionFromUrl && typeof window !== 'undefined') {
|
|
172
|
+
const params = new URLSearchParams(window.location.search)
|
|
173
|
+
promo ||= params.get('promo')?.trim() || params.get('promo_code')?.trim() || ''
|
|
174
|
+
referral ??= params.get('ttf_r') || params.get('referrer_id') || undefined
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (referral !== undefined && String(referral).trim()) {
|
|
178
|
+
checkout.attributeReferrer(eventId, referral).catch(() => undefined)
|
|
179
|
+
}
|
|
180
|
+
if (promo) {
|
|
181
|
+
setCode(promo)
|
|
182
|
+
setPromoOpen(true)
|
|
183
|
+
setCodeState('busy')
|
|
184
|
+
checkout
|
|
185
|
+
.applyPromoCode(eventId, promo)
|
|
186
|
+
.catch(() => undefined)
|
|
187
|
+
.finally(() => {
|
|
188
|
+
ticketsQuery.refetch().finally(() => setCodeState('idle'))
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
// Checkout actions and query functions are stable; this effect is scoped to
|
|
192
|
+
// one attribution pass per event rather than every render.
|
|
193
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
194
|
+
}, [eventId, initialPromoCode, referrer, readAttributionFromUrl])
|
|
195
|
+
|
|
196
|
+
// Seed the currency state once so a multi-currency event can offer a switcher
|
|
197
|
+
// on the ticket screen (before the cart is primed). No-op for single-currency.
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
checkout.syncCurrency(eventId, undefined, { seed: true }).catch(() => undefined)
|
|
200
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
201
|
+
}, [eventId])
|
|
202
|
+
|
|
203
|
+
const changeCurrency = (code: string) => {
|
|
204
|
+
checkout
|
|
205
|
+
.syncCurrency(eventId, code)
|
|
206
|
+
.then((res) => {
|
|
207
|
+
if (res.requiresCatalogRefresh) {
|
|
208
|
+
setQty({})
|
|
209
|
+
ticketsQuery.refetch()
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
.catch(() => undefined)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Remember each type's first-seen (pre-promo) price so a discount can strike it.
|
|
216
|
+
const originals = useRef<Record<string, number>>({})
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
for (const t of tickets)
|
|
219
|
+
if (originals.current[t.id] == null) originals.current[t.id] = t.price
|
|
220
|
+
}, [tickets])
|
|
221
|
+
|
|
222
|
+
const selected = tickets.filter((t) => (qty[t.id] ?? 0) > 0)
|
|
223
|
+
// The current selection's kind — drives the CTA label and the mutual-exclusion
|
|
224
|
+
// rule below (a table order and a ticket order can't be combined).
|
|
225
|
+
const selectionIsTable = selected.some((t) => t.isTable)
|
|
226
|
+
const allowMultiple = eventInfo?.allowMultipleTicketTypePurchases === true
|
|
227
|
+
|
|
228
|
+
// Ported from the old checkout's `handleTicketSelect`: unless the event opts
|
|
229
|
+
// into multiple types (`allowMultipleTicketTypePurchases`), a new selection
|
|
230
|
+
// REPLACES the previous one — one ticket type per order. Even when multiple
|
|
231
|
+
// are allowed, switching between a table and a regular ticket clears the rest.
|
|
232
|
+
const selectQty = (t: TicketType, value: number) =>
|
|
233
|
+
setQty((prev) => {
|
|
234
|
+
const activeIds = Object.keys(prev).filter((k) => (prev[k] ?? 0) > 0)
|
|
235
|
+
const prevIsTable = activeIds.length
|
|
236
|
+
? Boolean(tickets.find((x) => x.id === activeIds[0])?.isTable)
|
|
237
|
+
: t.isTable
|
|
238
|
+
const switchingKind = activeIds.length > 0 && prevIsTable !== t.isTable
|
|
239
|
+
|
|
240
|
+
if (!allowMultiple) return value > 0 ? { [t.id]: value } : {}
|
|
241
|
+
if (switchingKind && value > 0) return { [t.id]: value }
|
|
242
|
+
const next = { ...prev }
|
|
243
|
+
if (value > 0) next[t.id] = value
|
|
244
|
+
else delete next[t.id]
|
|
245
|
+
return next
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
const money = (sym: string, n: number) => `${sym} ${Number(n).toFixed(2)}`
|
|
249
|
+
|
|
250
|
+
// Seated events: the buyer picks on a seat map, so seat-map ticket types show
|
|
251
|
+
// read-only (no quantity dropdown) and the CTA becomes "Select seats". A type
|
|
252
|
+
// with `allowDirectPurchase` opts out and keeps its dropdown.
|
|
253
|
+
const isSeated = eventInfo?.isSeatedEvent ?? false
|
|
254
|
+
const seatMapRow = (t: TicketType) => isSeated && !t.allowDirectPurchase
|
|
255
|
+
const hasSeatMapTickets = tickets.some(seatMapRow)
|
|
256
|
+
// Types that can still be bought with a quantity dropdown (all of them for a
|
|
257
|
+
// non-seated event). When empty on a seated event, only "Select seats" shows.
|
|
258
|
+
const directPurchasable = tickets.filter((t) => !seatMapRow(t))
|
|
259
|
+
const seatCtaLabel = eventInfo?.tableMapEnabled ? 'Select on map' : 'Select seats'
|
|
260
|
+
|
|
261
|
+
// A "Tables" divider before the first table type — only when regular tickets
|
|
262
|
+
// actually precede it (a tables-first list gets no stray divider).
|
|
263
|
+
const firstTableIndex = tickets.findIndex((t) => t.isTable)
|
|
264
|
+
const firstTableId =
|
|
265
|
+
firstTableIndex > 0 && tickets.slice(0, firstTableIndex).some((t) => !t.isTable)
|
|
266
|
+
? tickets[firstTableIndex].id
|
|
267
|
+
: undefined
|
|
268
|
+
|
|
269
|
+
const prime = () => {
|
|
270
|
+
setError('')
|
|
271
|
+
checkout
|
|
272
|
+
.setTickets(
|
|
273
|
+
eventId,
|
|
274
|
+
selected.map((t) => ({ ...t, quantity: qty[t.id] }))
|
|
275
|
+
)
|
|
276
|
+
.then(() => onContinue?.())
|
|
277
|
+
.catch((e) => setError(errorMessage(e)))
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const applyCode = () => {
|
|
281
|
+
if (!code.trim()) return
|
|
282
|
+
setCodeState('busy')
|
|
283
|
+
checkout
|
|
284
|
+
.applyPromoCode(eventId, code.trim())
|
|
285
|
+
.catch(() => undefined)
|
|
286
|
+
.finally(() => {
|
|
287
|
+
ticketsQuery.refetch().finally(() => setCodeState('idle'))
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const isAccess = promoMeta?.isAccessCodeEnabled
|
|
292
|
+
const showCodeInput = promoMeta?.isPromotionsEnabled || isAccess
|
|
293
|
+
const listQuery = isTimeSlot ? slotQuery : ticketsQuery
|
|
294
|
+
|
|
295
|
+
const renderRow = (t: TicketType) => {
|
|
296
|
+
const notStarted = !t.salesStarted
|
|
297
|
+
const unavailable = t.soldOut || t.salesEnded || notStarted
|
|
298
|
+
const original = originals.current[t.id]
|
|
299
|
+
const discounted = original != null && original > t.price
|
|
300
|
+
const canWaitlist =
|
|
301
|
+
t.soldOut && (t.waitingListEnabled || showWaitingList) && !t.salesEnded
|
|
302
|
+
const isFree = Number(t.price) === 0
|
|
303
|
+
const sym = t.priceSymbol || t.currency
|
|
304
|
+
const range = ticketQuantityRange(t)
|
|
305
|
+
const ticketIndex = tickets.findIndex((candidate) => candidate.id === t.id)
|
|
306
|
+
const previousTicket = ticketIndex > 0 ? tickets[ticketIndex - 1] : undefined
|
|
307
|
+
const startsNamedGroup =
|
|
308
|
+
Boolean(t.groupName) && t.groupName !== previousTicket?.groupName
|
|
309
|
+
return (
|
|
310
|
+
<Fragment key={t.id}>
|
|
311
|
+
{startsNamedGroup ? (
|
|
312
|
+
<div className="tf-checkout-tickets__group">{t.groupName}</div>
|
|
313
|
+
) : (
|
|
314
|
+
t.id === firstTableId && (
|
|
315
|
+
<div className="tf-checkout-tickets__group">Reserve tables</div>
|
|
316
|
+
)
|
|
317
|
+
)}
|
|
318
|
+
<div className="tf-checkout-tickets__row-wrap">
|
|
319
|
+
<div className="tf-checkout-tickets__row">
|
|
320
|
+
<div className="tf-checkout-tickets__info">
|
|
321
|
+
<div className="tf-checkout-tickets__name">
|
|
322
|
+
<span>{t.name}</span>
|
|
323
|
+
{t.descriptionRich && (
|
|
324
|
+
<button
|
|
325
|
+
type="button"
|
|
326
|
+
className="tf-checkout-tickets__description-toggle"
|
|
327
|
+
aria-expanded={visibleDescription === t.id}
|
|
328
|
+
aria-controls={`ticket-description-${t.id}`}
|
|
329
|
+
onClick={() =>
|
|
330
|
+
setVisibleDescription((current) => (current === t.id ? null : t.id))
|
|
331
|
+
}
|
|
332
|
+
>
|
|
333
|
+
{visibleDescription === t.id ? 'Hide info' : 'View info'}
|
|
334
|
+
</button>
|
|
335
|
+
)}
|
|
336
|
+
</div>
|
|
337
|
+
<div className="tf-checkout-tickets__price">
|
|
338
|
+
{discounted && (
|
|
339
|
+
<span className="tf-checkout-tickets__old">
|
|
340
|
+
{money(sym, original!)}
|
|
341
|
+
</span>
|
|
342
|
+
)}
|
|
343
|
+
<span
|
|
344
|
+
className={cx(
|
|
345
|
+
'tf-checkout-tickets__amount',
|
|
346
|
+
isFree && 'tf-checkout-tickets__amount--free'
|
|
347
|
+
)}
|
|
348
|
+
>
|
|
349
|
+
{isFree ? 'FREE' : money(sym, t.price)}
|
|
350
|
+
</span>
|
|
351
|
+
{/* Fees sub-line (the "(… with fees)" the old checkout shows) —
|
|
352
|
+
omitted for free/sold-out types. */}
|
|
353
|
+
{!isFree && !t.soldOut && (
|
|
354
|
+
<span className="tf-checkout-tickets__fees">
|
|
355
|
+
({money(sym, t.priceWithFees)} with fees)
|
|
356
|
+
</span>
|
|
357
|
+
)}
|
|
358
|
+
{t.depositPercent != null && (
|
|
359
|
+
<span className="tf-checkout-tickets__deposit">
|
|
360
|
+
{t.depositPercent.toFixed(2)}% DEPOSIT
|
|
361
|
+
</span>
|
|
362
|
+
)}
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
{/* Seat-map types are read-only here — no quantity control; the buyer
|
|
366
|
+
picks them on the map via "Select seats". */}
|
|
367
|
+
{seatMapRow(t) ? null : unavailable ? (
|
|
368
|
+
<span className="tf-checkout-tickets__soldout">
|
|
369
|
+
{t.soldOut
|
|
370
|
+
? 'Sold out'
|
|
371
|
+
: notStarted
|
|
372
|
+
? 'Sales not started'
|
|
373
|
+
: 'Sales Ended'}
|
|
374
|
+
</span>
|
|
375
|
+
) : (
|
|
376
|
+
<div className="tf-checkout-tickets__qty">
|
|
377
|
+
{/* Tables pick a number of GUESTS (bounded by minGuests/maxGuests),
|
|
378
|
+
not a count of tickets — the label makes that explicit, matching
|
|
379
|
+
the old checkout's "GUESTS" affordance. */}
|
|
380
|
+
{t.isTable && <span className="tf-checkout-tickets__guests">Guests</span>}
|
|
381
|
+
<QuantitySelect
|
|
382
|
+
value={qty[t.id] ?? 0}
|
|
383
|
+
min={range.min}
|
|
384
|
+
max={range.max}
|
|
385
|
+
step={range.step}
|
|
386
|
+
onChange={(v) => selectQty(t, v)}
|
|
387
|
+
/>
|
|
388
|
+
</div>
|
|
389
|
+
)}
|
|
390
|
+
</div>
|
|
391
|
+
{t.descriptionRich && visibleDescription === t.id && (
|
|
392
|
+
<div
|
|
393
|
+
id={`ticket-description-${t.id}`}
|
|
394
|
+
className="tf-checkout-tickets__description"
|
|
395
|
+
dangerouslySetInnerHTML={{ __html: t.descriptionRich }}
|
|
396
|
+
/>
|
|
397
|
+
)}
|
|
398
|
+
{canWaitlist &&
|
|
399
|
+
(wlOpen[t.id] ? (
|
|
400
|
+
<WaitingListForm
|
|
401
|
+
ticket={t}
|
|
402
|
+
onJoin={(entry) => checkout.joinWaitingList(eventId, entry)}
|
|
403
|
+
/>
|
|
404
|
+
) : (
|
|
405
|
+
<button
|
|
406
|
+
type="button"
|
|
407
|
+
className="tf-checkout-tickets__wl-toggle"
|
|
408
|
+
onClick={() => setWlOpen((w) => ({ ...w, [t.id]: true }))}
|
|
409
|
+
>
|
|
410
|
+
Join the waiting list
|
|
411
|
+
</button>
|
|
412
|
+
))}
|
|
413
|
+
</div>
|
|
414
|
+
</Fragment>
|
|
415
|
+
)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Time-slot layout groups the date's tickets under their time heading.
|
|
419
|
+
const timeGroups: { time: string; items: TicketType[] }[] = []
|
|
420
|
+
if (isTimeSlot)
|
|
421
|
+
for (const t of tickets) {
|
|
422
|
+
const time = t.timeSlot?.time ?? ''
|
|
423
|
+
const g = timeGroups.find((x) => x.time === time)
|
|
424
|
+
if (g) g.items.push(t)
|
|
425
|
+
else timeGroups.push({ time, items: [t] })
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return (
|
|
429
|
+
<Card className={cx('tf-checkout-tickets', className)}>
|
|
430
|
+
{(title !== false || step != null) && (
|
|
431
|
+
<SectionHeader
|
|
432
|
+
step={step}
|
|
433
|
+
title={title || ''}
|
|
434
|
+
pills={listQuery.isFetching && !listQuery.isLoading ? <Loader /> : undefined}
|
|
435
|
+
/>
|
|
436
|
+
)}
|
|
437
|
+
|
|
438
|
+
{listQuery.isLoading && (
|
|
439
|
+
<div className="tf-checkout-tickets__loading">
|
|
440
|
+
<Loader className="tf-checkout-tickets__loading-spinner" />
|
|
441
|
+
</div>
|
|
442
|
+
)}
|
|
443
|
+
|
|
444
|
+
{listQuery.error && (
|
|
445
|
+
<p className="tf-checkout-error-text">{(listQuery.error as Error).message}</p>
|
|
446
|
+
)}
|
|
447
|
+
|
|
448
|
+
{isTimeSlot && dates.length > 0 && (
|
|
449
|
+
<div className="tf-checkout-tickets__currency">
|
|
450
|
+
<span className="tf-checkout-tickets__currency-label">Date</span>
|
|
451
|
+
<select
|
|
452
|
+
className="tf-checkout-select"
|
|
453
|
+
value={slotDate}
|
|
454
|
+
onChange={(e) => {
|
|
455
|
+
setSlotDate(e.target.value)
|
|
456
|
+
setQty({})
|
|
457
|
+
}}
|
|
458
|
+
>
|
|
459
|
+
{dates.map((d) => (
|
|
460
|
+
<option key={d} value={d}>
|
|
461
|
+
{d}
|
|
462
|
+
</option>
|
|
463
|
+
))}
|
|
464
|
+
</select>
|
|
465
|
+
</div>
|
|
466
|
+
)}
|
|
467
|
+
|
|
468
|
+
{checkout.currency && checkout.currency.available.length > 1 && (
|
|
469
|
+
<div className="tf-checkout-tickets__currency">
|
|
470
|
+
<span className="tf-checkout-tickets__currency-label">Currency</span>
|
|
471
|
+
<select
|
|
472
|
+
className="tf-checkout-select"
|
|
473
|
+
value={checkout.currency.currency}
|
|
474
|
+
onChange={(e) => changeCurrency(e.target.value)}
|
|
475
|
+
>
|
|
476
|
+
{checkout.currency.available.map((c) => (
|
|
477
|
+
<option key={c.code} value={c.code}>
|
|
478
|
+
{c.name} ({c.code})
|
|
479
|
+
</option>
|
|
480
|
+
))}
|
|
481
|
+
</select>
|
|
482
|
+
</div>
|
|
483
|
+
)}
|
|
484
|
+
|
|
485
|
+
{isTimeSlot && !slotQuery.isLoading && tickets.length === 0 && slotDate && (
|
|
486
|
+
<p className="tf-checkout-note">No sessions available on this date.</p>
|
|
487
|
+
)}
|
|
488
|
+
|
|
489
|
+
{isTimeSlot
|
|
490
|
+
? timeGroups.map((g) => (
|
|
491
|
+
<Fragment key={g.time}>
|
|
492
|
+
{g.time && <div className="tf-checkout-tickets__slot-time">{g.time}</div>}
|
|
493
|
+
{g.items.map(renderRow)}
|
|
494
|
+
</Fragment>
|
|
495
|
+
))
|
|
496
|
+
: tickets.map(renderRow)}
|
|
497
|
+
|
|
498
|
+
{/* Promo / access code */}
|
|
499
|
+
{showCodeInput && (
|
|
500
|
+
<div className="tf-checkout-tickets__promo">
|
|
501
|
+
{!isAccess && !promoOpen ? (
|
|
502
|
+
<button
|
|
503
|
+
type="button"
|
|
504
|
+
className="tf-checkout-tickets__promo-toggle"
|
|
505
|
+
onClick={() => setPromoOpen(true)}
|
|
506
|
+
>
|
|
507
|
+
Got a promo code? Click here
|
|
508
|
+
</button>
|
|
509
|
+
) : (
|
|
510
|
+
<>
|
|
511
|
+
<FieldRow>
|
|
512
|
+
<Field>
|
|
513
|
+
<Input
|
|
514
|
+
placeholder={isAccess ? 'Access code' : 'Promo code'}
|
|
515
|
+
value={code}
|
|
516
|
+
onChange={(e) => setCode(e.target.value)}
|
|
517
|
+
onKeyDown={(e) => e.key === 'Enter' && applyCode()}
|
|
518
|
+
/>
|
|
519
|
+
</Field>
|
|
520
|
+
<Button
|
|
521
|
+
variant="secondary"
|
|
522
|
+
onClick={applyCode}
|
|
523
|
+
loading={codeState === 'busy'}
|
|
524
|
+
disabled={codeState === 'busy' || !code.trim()}
|
|
525
|
+
>
|
|
526
|
+
{isAccess ? 'ENTER' : 'APPLY'}
|
|
527
|
+
</Button>
|
|
528
|
+
</FieldRow>
|
|
529
|
+
{promoMeta?.promoCodeMessage && (
|
|
530
|
+
<p
|
|
531
|
+
className={cx(
|
|
532
|
+
'tf-checkout-note',
|
|
533
|
+
promoMeta.promoCodeValid === false && 'tf-checkout-error-text'
|
|
534
|
+
)}
|
|
535
|
+
>
|
|
536
|
+
{promoMeta.promoCodeMessage}
|
|
537
|
+
</p>
|
|
538
|
+
)}
|
|
539
|
+
</>
|
|
540
|
+
)}
|
|
541
|
+
</div>
|
|
542
|
+
)}
|
|
543
|
+
|
|
544
|
+
{/* Direct-purchase CTA — hidden on a fully-seated event (nothing to buy by
|
|
545
|
+
quantity; the seat map is the only path). */}
|
|
546
|
+
{directPurchasable.length > 0 && (
|
|
547
|
+
<Button
|
|
548
|
+
block
|
|
549
|
+
onClick={prime}
|
|
550
|
+
loading={checkout.isBusy}
|
|
551
|
+
disabled={checkout.isBusy || selected.length === 0}
|
|
552
|
+
>
|
|
553
|
+
{checkout.isBusy
|
|
554
|
+
? 'Reserving…'
|
|
555
|
+
: selectionIsTable
|
|
556
|
+
? 'Reserve tables'
|
|
557
|
+
: buttonLabel}
|
|
558
|
+
</Button>
|
|
559
|
+
)}
|
|
560
|
+
|
|
561
|
+
{/* Seated events: hand off to the seat map instead of quantity selection. */}
|
|
562
|
+
{hasSeatMapTickets && (
|
|
563
|
+
<Button block onClick={() => onSelectSeats?.()}>
|
|
564
|
+
{seatCtaLabel}
|
|
565
|
+
</Button>
|
|
566
|
+
)}
|
|
567
|
+
|
|
568
|
+
{(error || checkout.error) && (
|
|
569
|
+
<p className="tf-checkout-error-text">{error || checkout.error}</p>
|
|
570
|
+
)}
|
|
571
|
+
</Card>
|
|
572
|
+
)
|
|
573
|
+
}
|