tf-checkout-react 1.6.6 → 1.7.2
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/README.md +401 -59
- package/dist/adapters/customFields.d.ts +1 -0
- package/dist/api/checkout.d.ts +2 -0
- package/dist/api/common.d.ts +1 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/preRegistrationComplete.d.ts +1 -1
- package/dist/components/addonsContainer/AddonComponent.d.ts +6 -1
- package/dist/components/addonsContainer/SimpleAddonsContainer.d.ts +17 -0
- package/dist/components/addonsContainer/index.d.ts +6 -1
- package/dist/components/billing-info-container/hooks/index.d.ts +3 -0
- package/dist/components/billing-info-container/hooks/usePaymentContext.d.ts +5 -0
- package/dist/components/billing-info-container/hooks/usePaymentRedirect.d.ts +14 -0
- package/dist/components/billing-info-container/hooks/useStripePayment.d.ts +18 -0
- package/dist/components/billing-info-container/index.d.ts +13 -2
- package/dist/components/billing-info-container/utils.d.ts +26 -1
- package/dist/components/common/DatePickerField.d.ts +7 -1
- package/dist/components/common/PhoneNumberField.d.ts +1 -1
- package/dist/components/confirmationContainer/index.d.ts +4 -1
- package/dist/components/countdown/index.d.ts +1 -1
- package/dist/components/forgotPasswordModal/index.d.ts +2 -1
- package/dist/components/myTicketsContainer/index.d.ts +3 -2
- package/dist/components/orderDetailsContainer/index.d.ts +8 -1
- package/dist/components/paymentContainer/OrderDetails.d.ts +9 -0
- package/dist/components/paymentContainer/handlePayment.d.ts +15 -0
- package/dist/components/paymentContainer/index.d.ts +12 -6
- package/dist/components/preRegistration/FieldsSection.d.ts +7 -1
- package/dist/components/preRegistration/PreRegistrationComplete.d.ts +8 -0
- package/dist/components/preRegistration/constants.d.ts +2 -2
- package/dist/components/preRegistration/index.d.ts +6 -0
- package/dist/components/resetPasswordContainer/index.d.ts +2 -2
- package/dist/components/ticketsContainer/InfoIcon.d.ts +5 -0
- package/dist/components/ticketsContainer/TicketsSection.d.ts +3 -2
- package/dist/components/ticketsContainer/TimeSlotsSection.d.ts +25 -0
- package/dist/components/ticketsContainer/index.d.ts +29 -5
- package/dist/components/timerWidget/index.d.ts +2 -1
- package/dist/constants/index.d.ts +5 -0
- package/dist/index.d.ts +4 -1
- package/dist/tf-checkout-react.cjs.development.js +11284 -9565
- package/dist/tf-checkout-react.cjs.development.js.map +1 -1
- package/dist/tf-checkout-react.cjs.production.min.js +1 -1
- package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
- package/dist/tf-checkout-react.esm.js +11293 -9577
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/dist/tf-checkout-styles.css +1 -1
- package/dist/types/add_on.d.ts +1 -0
- package/dist/types/checkoutPageConfigs.d.ts +1 -1
- package/dist/types/order-data.d.ts +3 -1
- package/dist/utils/auth.d.ts +8 -0
- package/dist/utils/createCheckoutDataBodyWithDefaultHolder.d.ts +1 -0
- package/dist/utils/customFields.d.ts +11 -0
- package/dist/utils/getDomain.d.ts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/setConfigs.d.ts +1 -0
- package/package.json +14 -8
- package/src/adapters/customFields.ts +7 -1
- package/src/api/auth.ts +2 -1
- package/src/api/checkout.ts +9 -4
- package/src/api/common.ts +49 -2
- package/src/api/index.ts +1 -0
- package/src/api/interceptors.ts +7 -23
- package/src/api/preRegistrationComplete.ts +1 -1
- package/src/api/publicRequest.ts +10 -0
- package/src/components/addonsContainer/AddonComponent.tsx +96 -11
- package/src/components/addonsContainer/SimpleAddonsContainer.tsx +420 -0
- package/src/components/addonsContainer/index.tsx +198 -47
- package/src/components/billing-info-container/hooks/index.ts +3 -0
- package/src/components/billing-info-container/hooks/usePaymentContext.ts +22 -0
- package/src/components/billing-info-container/hooks/usePaymentRedirect.ts +147 -0
- package/src/components/billing-info-container/hooks/useStripePayment.ts +121 -0
- package/src/components/billing-info-container/index.tsx +859 -418
- package/src/components/billing-info-container/{utils.ts → utils.tsx} +124 -1
- package/src/components/common/CheckboxField/index.tsx +1 -1
- package/src/components/common/CustomField.tsx +39 -3
- package/src/components/common/DatePickerField.tsx +25 -10
- package/src/components/common/PhoneNumberField.tsx +4 -2
- package/src/components/common/SnackbarAlert.tsx +32 -34
- package/src/components/confirmationContainer/config.ts +3 -3
- package/src/components/confirmationContainer/index.tsx +20 -1
- package/src/components/confirmationContainer/social-buttons.tsx +5 -3
- package/src/components/confirmationContainer/style.css +9 -5
- package/src/components/countdown/index.tsx +22 -22
- package/src/components/delegationsContainer/IssueComponent.tsx +2 -1
- package/src/components/forgotPasswordModal/index.tsx +44 -13
- package/src/components/loginForm/index.tsx +1 -1
- package/src/components/loginModal/index.tsx +19 -27
- package/src/components/loginModal/style.css +3 -1
- package/src/components/myTicketsContainer/index.tsx +13 -9
- package/src/components/orderDetailsContainer/index.tsx +206 -174
- package/src/components/paymentContainer/OrderDetails.tsx +257 -0
- package/src/components/paymentContainer/handlePayment.ts +86 -0
- package/src/components/paymentContainer/index.tsx +299 -259
- package/src/components/paymentContainer/style.css +141 -0
- package/src/components/preRegistration/FieldsSection.tsx +8 -0
- package/src/components/preRegistration/PreRegistrationComplete.tsx +138 -118
- package/src/components/preRegistration/PreRegistrationInformations.tsx +21 -15
- package/src/components/preRegistration/constants.tsx +10 -4
- package/src/components/preRegistration/index.tsx +233 -179
- package/src/components/preRegistration/style.css +3 -0
- package/src/components/registerForm/constants.tsx +3 -1
- package/src/components/registerForm/index.tsx +3 -3
- package/src/components/registerModal/index.tsx +47 -72
- package/src/components/resetPasswordContainer/index.tsx +20 -14
- package/src/components/seatMapContainer/TicketsSection.tsx +2 -2
- package/src/components/signupModal/index.tsx +13 -6
- package/src/components/ticketResale/index.tsx +7 -0
- package/src/components/ticketsContainer/InfoIcon.tsx +35 -0
- package/src/components/ticketsContainer/PromoCodeSection.tsx +34 -28
- package/src/components/ticketsContainer/TicketRow.tsx +1 -1
- package/src/components/ticketsContainer/TicketsSection.tsx +189 -57
- package/src/components/ticketsContainer/TimeSlotsSection.tsx +120 -0
- package/src/components/ticketsContainer/index.tsx +268 -106
- package/src/components/timerWidget/index.tsx +15 -3
- package/src/components/timerWidget/style.css +2 -1
- package/src/constants/index.ts +2 -0
- package/src/env.ts +14 -6
- package/src/hoc/CustomFields/index.tsx +9 -1
- package/src/index.ts +7 -2
- package/src/types/add_on.ts +1 -0
- package/src/types/api/cart.d.ts +8 -0
- package/src/types/api/checkout.d.ts +58 -7
- package/src/types/api/common.d.ts +30 -0
- package/src/types/api/orders.d.ts +19 -3
- package/src/types/api/payment.d.ts +6 -2
- package/src/types/api/preRegistrationComplete.d.ts +2 -2
- package/src/types/checkoutPageConfigs.ts +1 -1
- package/src/types/order-data.ts +3 -1
- package/src/types/pre-registration-complete.d.ts +6 -1
- package/src/utils/auth.ts +32 -0
- package/src/utils/cookies.ts +42 -11
- package/src/utils/createCheckoutDataBodyWithDefaultHolder.ts +3 -1
- package/src/utils/customFields.ts +22 -0
- package/src/utils/getDomain.ts +10 -4
- package/src/utils/index.ts +1 -1
- package/src/utils/setConfigs.ts +3 -1
- package/dist/components/stripePayment/index.d.ts +0 -24
- package/src/components/stripePayment/index.tsx +0 -281
- package/src/components/stripePayment/style.css +0 -60
package/README.md
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
<details open>
|
|
6
|
-
<summary
|
|
6
|
+
<summary>
|
|
7
|
+
<strong>Table of Contents</strong>
|
|
8
|
+
</summary>
|
|
7
9
|
|
|
8
10
|
- [tf-checkout-react](#tf-checkout-react)
|
|
11
|
+
- [Code style and formatting](#code-style-and-formatting)
|
|
9
12
|
- [Introduction](#introduction)
|
|
10
13
|
- [Intergrations](#intergrations)
|
|
11
14
|
- [WebFlow](#webflow)
|
|
@@ -21,11 +24,11 @@
|
|
|
21
24
|
- [Register](#register)
|
|
22
25
|
- [Forgot Password](#forgot-password)
|
|
23
26
|
- [Promo Code](#promo-code)
|
|
24
|
-
- [
|
|
27
|
+
- [**Note that package automatically calls component in `TicketsContainer`**](#note-that-package-automatically-calls-component-in-ticketscontainer)
|
|
25
28
|
- [Access Code](#access-code)
|
|
26
|
-
- [
|
|
29
|
+
- [**Note that package automatically calls component in `TicketsContainer`**](#note-that-package-automatically-calls-component-in-ticketscontainer-1)
|
|
27
30
|
- [Waiting List](#waiting-list)
|
|
28
|
-
- [
|
|
31
|
+
- [**Note that package automatically calls component in `TicketsContainer`**](#note-that-package-automatically-calls-component-in-ticketscontainer-2)
|
|
29
32
|
- [Pixel Usage](#pixel-usage)
|
|
30
33
|
- [Components](#components)
|
|
31
34
|
- [`TicketsContainer`](#ticketscontainer)
|
|
@@ -38,33 +41,53 @@
|
|
|
38
41
|
- [Order Details Container](#order-details-container)
|
|
39
42
|
- [Ticket Resale Container](#ticket-resale-container)
|
|
40
43
|
- [Commands](#commands)
|
|
41
|
-
|
|
42
|
-
- [
|
|
43
|
-
|
|
44
|
+
- [Rollup](#rollup)
|
|
45
|
+
- [Optimizations](#optimizations)
|
|
46
|
+
- [TypeScript](#typescript)
|
|
47
|
+
- [GitHub Actions](#github-actions)
|
|
44
48
|
|
|
45
49
|
</details>
|
|
46
50
|
|
|
51
|
+
## Code style and formatting
|
|
52
|
+
|
|
53
|
+
1. **Install Prettier ESLint extension (v5.1.0)**
|
|
54
|
+
- VSCode: <https://marketplace.visualstudio.com/items?itemName=rvest.vs-code-prettier-eslint>
|
|
55
|
+
- JetBrains' products: <https://blog.jetbrains.com/webstorm/2016/08/using-external-tools/>
|
|
56
|
+
Notes:
|
|
57
|
+
- The Prettier extension is not required.
|
|
58
|
+
- The ESLint extension is not required. However, it is needed to have lint errors show while editing your file.
|
|
59
|
+
2. **Set Prettier ESLint default formatter**
|
|
60
|
+
|
|
61
|
+
- VSCode: Open commands (CMD/Win + Stift + P) -> Format document with -> Configure default formatter
|
|
62
|
+
- JetBrains' products: <https://blog.jetbrains.com/webstorm/2016/08/using-external-tools/>
|
|
63
|
+
|
|
64
|
+
3. **Enable format on save**
|
|
65
|
+
|
|
66
|
+
- VSCode: Open settings (CMD + ,) -> Search "Format On Save"
|
|
67
|
+
- JetBrains' products: <https://blog.jetbrains.com/webstorm/2016/08/using-external-tools/>
|
|
68
|
+
|
|
47
69
|
|
|
70
|
+
|
|
48
71
|
# Introduction
|
|
49
72
|
|
|
50
|
-
This package includes TicketFairy's checkout functionality, as well as various related functionalities. These functionalities include login/register, order management, resale, referrals, and more.
|
|
73
|
+
This package includes TicketFairy's checkout functionality, as well as various related functionalities. These functionalities include login/register, order management, resale, referrals, and more.
|
|
51
74
|
|
|
52
75
|
This package provides a set of components and functionalities designed to manage various aspects of the TicketFairy event experience. These include:
|
|
53
76
|
|
|
54
77
|
- `AccountSettings`: A component for managing user account settings, such as email address and password.
|
|
55
78
|
- `AddonsContainter`: A component for displaying a list of available add-ons and allowing the user to purchase them.
|
|
56
|
-
- `BillingInfoContainer`: A component for managing billing information, such as addresses and ticket holders.
|
|
79
|
+
- `BillingInfoContainer`: A component for managing billing information, such as addresses and ticket holders. Features enhanced field rendering, improved validation, and better user experience.
|
|
57
80
|
- `ConfirmationContainer`: A component for displaying a confirmation page after a purchase is made.
|
|
58
81
|
- `IDVerification`: A component for verifying the identity of the user during the checkout process.
|
|
59
82
|
- `MyTicketsContainer`: A component for displaying a list of purchased orders.
|
|
60
83
|
- `OrderDetailsContainer`: A component for displaying detailed information about a purchase, such as the ticket types, add-ons and pricing.
|
|
61
|
-
- `PaymentContainer`: A component for managing payment processing during the checkout process.
|
|
84
|
+
- `PaymentContainer`: A component for managing payment processing during the checkout process. Includes enhanced Stripe integration, improved payment validation, and better error handling.
|
|
62
85
|
- `ResetPasswordContainer`: A component for resetting a user's password.
|
|
63
86
|
- `SeatMapContainer`: A component for displaying and selecting seats on a venue map.
|
|
64
87
|
- `TicketResaleContainer`: A component for managing the resale of tickets or add-ons by the user.
|
|
65
|
-
- `TicketsContainer`: A component for displaying a list of available tickets and allowing the user to purchase them.
|
|
88
|
+
- `TicketsContainer`: A component for displaying a list of available tickets and allowing the user to purchase them. Features optimized API calls, better state management, and enhanced user interactions.
|
|
66
89
|
|
|
67
|
-
Together, these components and functionalities provide a comprehensive set of tools to manage the checkout process and related activities for a TicketFairy-powered event.
|
|
90
|
+
Together, these components and functionalities provide a comprehensive set of tools to manage the checkout process and related activities for a TicketFairy-powered event.
|
|
68
91
|
|
|
69
92
|
|
|
70
93
|
|
|
@@ -74,7 +97,6 @@ Together, these components and functionalities provide a comprehensive set of to
|
|
|
74
97
|
|
|
75
98
|
|
|
76
99
|
|
|
77
|
-
|
|
78
100
|
# Prerequisites
|
|
79
101
|
|
|
80
102
|
- node >= v16.19.0
|
|
@@ -82,13 +104,13 @@ Together, these components and functionalities provide a comprehensive set of to
|
|
|
82
104
|
|
|
83
105
|
# Installation
|
|
84
106
|
|
|
85
|
-
```
|
|
107
|
+
```bash
|
|
86
108
|
npm i tf-checkout-react
|
|
87
109
|
```
|
|
88
110
|
|
|
89
111
|
or
|
|
90
112
|
|
|
91
|
-
```
|
|
113
|
+
```bash
|
|
92
114
|
yarn add tf-checkout-react
|
|
93
115
|
```
|
|
94
116
|
|
|
@@ -107,11 +129,13 @@ Project will run under `localhost:3002`. Port can be changed from `package.json`
|
|
|
107
129
|
|
|
108
130
|
## Set configuration
|
|
109
131
|
|
|
110
|
-
In order to make this package work properly, you need to set some configurations, otherwise the default configurations will be used.
|
|
132
|
+
In order to make this package work properly, you need to set some configurations, otherwise the default configurations will be used.
|
|
133
|
+
Currently only configuration which is needed for production, is `BASE_URL`.
|
|
134
|
+
Other configurations written below are only for development/test environments.
|
|
111
135
|
|
|
112
136
|
Import `setConfigs` function from the package.
|
|
113
137
|
|
|
114
|
-
```
|
|
138
|
+
```js
|
|
115
139
|
import { setConfigs } from 'tf-checkout-react'
|
|
116
140
|
```
|
|
117
141
|
|
|
@@ -130,21 +154,298 @@ Call it in the root and pass neccesary options. Here are available options:
|
|
|
130
154
|
|
|
131
155
|
|
|
132
156
|
|
|
157
|
+
# Single Page Checkout Implementation
|
|
158
|
+
|
|
159
|
+
## Overview
|
|
160
|
+
|
|
161
|
+
While the default implementation uses separate pages for each checkout step (`TicketsContainer` → `BillingInfoContainer` → `PaymentContainer` → `ConfirmationContainer`), the package also supports a **single page checkout flow** where all components are rendered on the same page with conditional visibility and state management.
|
|
162
|
+
|
|
163
|
+
## Key Differences from Default Flow
|
|
164
|
+
|
|
165
|
+
### **Default Multi-Page Flow:**
|
|
166
|
+
|
|
167
|
+
- Each component handles its own routing and navigation
|
|
168
|
+
- State is managed through URL parameters and localStorage
|
|
169
|
+
- Components are mounted/unmounted as user navigates
|
|
170
|
+
- Each step is a separate page/route
|
|
171
|
+
|
|
172
|
+
### **Single Page Flow:**
|
|
173
|
+
|
|
174
|
+
- All components are conditionally rendered on the same page
|
|
175
|
+
- State management requires careful coordination between components
|
|
176
|
+
- Components remain mounted but visibility is controlled
|
|
177
|
+
- Navigation is handled through state changes rather than routing
|
|
178
|
+
|
|
179
|
+
## Implementation Patterns
|
|
180
|
+
|
|
181
|
+
### **1. State Management**
|
|
182
|
+
|
|
183
|
+
```jsx
|
|
184
|
+
import React, { useState } from 'react'
|
|
185
|
+
import {
|
|
186
|
+
TicketsContainer,
|
|
187
|
+
BillingInfoContainer,
|
|
188
|
+
PaymentContainer,
|
|
189
|
+
ConfirmationContainer
|
|
190
|
+
} from 'tf-checkout-react'
|
|
191
|
+
|
|
192
|
+
const SinglePageCheckout = () => {
|
|
193
|
+
const [currentStep, setCurrentStep] = useState('tickets')
|
|
194
|
+
const [checkoutData, setCheckoutData] = useState({})
|
|
195
|
+
const [cartData, setCartData] = useState(null)
|
|
196
|
+
|
|
197
|
+
const handleTicketsSuccess = (data) => {
|
|
198
|
+
setCartData(data)
|
|
199
|
+
setCurrentStep('billing')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const handleBillingSuccess = (data) => {
|
|
203
|
+
setCheckoutData(prev => ({ ...prev, billing: data }))
|
|
204
|
+
setCurrentStep('payment')
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const handlePaymentSuccess = (data) => {
|
|
208
|
+
setCheckoutData(prev => ({ ...prev, payment: data }))
|
|
209
|
+
setCurrentStep('confirmation')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<div className="single-page-checkout">
|
|
214
|
+
{currentStep === 'tickets' && (
|
|
215
|
+
<TicketsContainer
|
|
216
|
+
eventId={eventId}
|
|
217
|
+
onAddToCartSuccess={handleTicketsSuccess}
|
|
218
|
+
// Disable auto-navigation
|
|
219
|
+
enableBillingInfoAutoCreate={false}
|
|
220
|
+
/>
|
|
221
|
+
)}
|
|
222
|
+
|
|
223
|
+
{currentStep === 'billing' && (
|
|
224
|
+
<BillingInfoContainer
|
|
225
|
+
handleSubmit={handleBillingSuccess}
|
|
226
|
+
// Skip automatic payment redirect
|
|
227
|
+
skipPage={false}
|
|
228
|
+
/>
|
|
229
|
+
)}
|
|
230
|
+
|
|
231
|
+
{currentStep === 'payment' && (
|
|
232
|
+
<PaymentContainer
|
|
233
|
+
checkoutData={checkoutData}
|
|
234
|
+
handlePayment={handlePaymentSuccess}
|
|
235
|
+
/>
|
|
236
|
+
)}
|
|
237
|
+
|
|
238
|
+
{currentStep === 'confirmation' && (
|
|
239
|
+
<ConfirmationContainer
|
|
240
|
+
orderHash={checkoutData.payment?.orderHash}
|
|
241
|
+
/>
|
|
242
|
+
)}
|
|
243
|
+
</div>
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### **2. Progressive Enhancement Pattern**
|
|
249
|
+
|
|
250
|
+
```jsx
|
|
251
|
+
const ProgressiveCheckout = () => {
|
|
252
|
+
const [completedSteps, setCompletedSteps] = useState(new Set())
|
|
253
|
+
const [activeStep, setActiveStep] = useState('tickets')
|
|
254
|
+
|
|
255
|
+
const markStepComplete = (step) => {
|
|
256
|
+
setCompletedSteps(prev => new Set([...prev, step]))
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const isStepAccessible = (step) => {
|
|
260
|
+
const stepOrder = ['tickets', 'billing', 'payment', 'confirmation']
|
|
261
|
+
const stepIndex = stepOrder.indexOf(step)
|
|
262
|
+
const prevStep = stepOrder[stepIndex - 1]
|
|
263
|
+
return stepIndex === 0 || completedSteps.has(prevStep)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<div className="progressive-checkout">
|
|
268
|
+
{/* Step Navigation */}
|
|
269
|
+
<div className="checkout-steps">
|
|
270
|
+
{['tickets', 'billing', 'payment', 'confirmation'].map(step => (
|
|
271
|
+
<button
|
|
272
|
+
key={step}
|
|
273
|
+
disabled={!isStepAccessible(step)}
|
|
274
|
+
className={`step ${activeStep === step ? 'active' : ''} ${completedSteps.has(step) ? 'completed' : ''}`}
|
|
275
|
+
onClick={() => setActiveStep(step)}
|
|
276
|
+
>
|
|
277
|
+
{step.charAt(0).toUpperCase() + step.slice(1)}
|
|
278
|
+
</button>
|
|
279
|
+
))}
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
{/* Component Rendering */}
|
|
283
|
+
<div className="checkout-content">
|
|
284
|
+
{activeStep === 'tickets' && (
|
|
285
|
+
<TicketsContainer
|
|
286
|
+
onAddToCartSuccess={(data) => {
|
|
287
|
+
markStepComplete('tickets')
|
|
288
|
+
setActiveStep('billing')
|
|
289
|
+
}}
|
|
290
|
+
/>
|
|
291
|
+
)}
|
|
292
|
+
{/* ... other components */}
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### **3. Accordion/Collapsible Pattern**
|
|
300
|
+
|
|
301
|
+
```jsx
|
|
302
|
+
const AccordionCheckout = () => {
|
|
303
|
+
const [openSections, setOpenSections] = useState(new Set(['tickets']))
|
|
304
|
+
const [completedSections, setCompletedSections] = useState(new Set())
|
|
305
|
+
|
|
306
|
+
const toggleSection = (section) => {
|
|
307
|
+
setOpenSections(prev => {
|
|
308
|
+
const newSet = new Set(prev)
|
|
309
|
+
if (newSet.has(section)) {
|
|
310
|
+
newSet.delete(section)
|
|
311
|
+
} else {
|
|
312
|
+
newSet.add(section)
|
|
313
|
+
}
|
|
314
|
+
return newSet
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return (
|
|
319
|
+
<div className="accordion-checkout">
|
|
320
|
+
<div className="checkout-section">
|
|
321
|
+
<div
|
|
322
|
+
className="section-header"
|
|
323
|
+
onClick={() => toggleSection('tickets')}
|
|
324
|
+
>
|
|
325
|
+
<h3>Select Tickets</h3>
|
|
326
|
+
{completedSections.has('tickets') && <span>✓</span>}
|
|
327
|
+
</div>
|
|
328
|
+
{openSections.has('tickets') && (
|
|
329
|
+
<TicketsContainer
|
|
330
|
+
onAddToCartSuccess={(data) => {
|
|
331
|
+
setCompletedSections(prev => new Set([...prev, 'tickets']))
|
|
332
|
+
setOpenSections(new Set(['billing']))
|
|
333
|
+
}}
|
|
334
|
+
/>
|
|
335
|
+
)}
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
<div className="checkout-section">
|
|
339
|
+
<div
|
|
340
|
+
className="section-header"
|
|
341
|
+
onClick={() => toggleSection('billing')}
|
|
342
|
+
>
|
|
343
|
+
<h3>Billing Information</h3>
|
|
344
|
+
{completedSections.has('billing') && <span>✓</span>}
|
|
345
|
+
</div>
|
|
346
|
+
{openSections.has('billing') && (
|
|
347
|
+
<BillingInfoContainer
|
|
348
|
+
handleSubmit={(values, helpers, eventId, res) => {
|
|
349
|
+
setCompletedSections(prev => new Set([...prev, 'billing']))
|
|
350
|
+
setOpenSections(new Set(['payment']))
|
|
351
|
+
}}
|
|
352
|
+
/>
|
|
353
|
+
)}
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
{/* ... other sections */}
|
|
357
|
+
</div>
|
|
358
|
+
)
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Important Considerations
|
|
363
|
+
|
|
364
|
+
### **Component Props Modifications**
|
|
365
|
+
|
|
366
|
+
- **`enableBillingInfoAutoCreate: false`** - Prevents automatic navigation to billing page
|
|
367
|
+
- **`skipPage: false`** - Controls whether billing page can be skipped
|
|
368
|
+
- **Custom callback handlers** - Override default navigation behavior
|
|
369
|
+
|
|
370
|
+
### **State Persistence**
|
|
371
|
+
|
|
372
|
+
```jsx
|
|
373
|
+
// Save state to localStorage for page refreshes
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
localStorage.setItem('checkoutState', JSON.stringify({
|
|
376
|
+
currentStep,
|
|
377
|
+
checkoutData,
|
|
378
|
+
cartData
|
|
379
|
+
}))
|
|
380
|
+
}, [currentStep, checkoutData, cartData])
|
|
381
|
+
|
|
382
|
+
// Restore state on component mount
|
|
383
|
+
useEffect(() => {
|
|
384
|
+
const savedState = localStorage.getItem('checkoutState')
|
|
385
|
+
if (savedState) {
|
|
386
|
+
const { currentStep, checkoutData, cartData } = JSON.parse(savedState)
|
|
387
|
+
setCurrentStep(currentStep)
|
|
388
|
+
setCheckoutData(checkoutData)
|
|
389
|
+
setCartData(cartData)
|
|
390
|
+
}
|
|
391
|
+
}, [])
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### **Error Handling**
|
|
395
|
+
|
|
396
|
+
```jsx
|
|
397
|
+
const [errors, setErrors] = useState({})
|
|
398
|
+
|
|
399
|
+
const handleStepError = (step, error) => {
|
|
400
|
+
setErrors(prev => ({ ...prev, [step]: error }))
|
|
401
|
+
// Optionally navigate back to error step
|
|
402
|
+
setCurrentStep(step)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Pass error handlers to each component
|
|
406
|
+
<BillingInfoContainer
|
|
407
|
+
onSubmitError={(error) => handleStepError('billing', error)}
|
|
408
|
+
handleSubmit={handleBillingSuccess}
|
|
409
|
+
/>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### **Timer Coordination**
|
|
413
|
+
|
|
414
|
+
When using timers across multiple components in single page flow:
|
|
415
|
+
|
|
416
|
+
```jsx
|
|
417
|
+
const [globalTimer, setGlobalTimer] = useState(null)
|
|
418
|
+
|
|
419
|
+
// Share timer state across components
|
|
420
|
+
<TicketsContainer enableTimer={false} />
|
|
421
|
+
<BillingInfoContainer enableTimer={false} />
|
|
422
|
+
<PaymentContainer enableTimer={true} onCountdownFinish={handleTimeout} />
|
|
423
|
+
|
|
424
|
+
// Or implement global timer
|
|
425
|
+
<TimerWidget
|
|
426
|
+
onCountdownFinish={handleGlobalTimeout}
|
|
427
|
+
className="global-timer"
|
|
428
|
+
/>
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
133
433
|
# Functionalities
|
|
134
434
|
|
|
135
435
|
## Login
|
|
136
436
|
|
|
437
|
+
The `LoginModal` component is designed to be used inside package to authenticate users. <br /> To use the `LoginModal`, simply include it in your React component and pass in the required **onLogin** and **onClose** callbacks as props.
|
|
137
438
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
You can authenticate users from the Billing page too, here you can either provide __onLogin__ callback as a prop to the [`BillingInfoContainer`](#billinginfocontainer) component so that you can open your custom component for authentication or you can ommit it and the package inside provided `LoginModal` component will be called and opened.
|
|
439
|
+
You can authenticate users from the Billing page too, here you can either provide **onLogin** callback as a prop to the [`BillingInfoContainer`](#billinginfocontainer) component so that you can open your custom component for authentication or
|
|
440
|
+
you can ommit it and the package inside provided `LoginModal` component will be called and opened.
|
|
141
441
|
|
|
142
|
-
Package can detect whether a user is logged in or not by checking for the presence of the
|
|
442
|
+
Package can detect whether a user is logged in or not by checking for the presence of the **X-TF-ECOMMERCE** cookie, which is automatically set by the system when the user successfully logs in.
|
|
443
|
+
If the **X-TF-ECOMMERCE** cookie is present, the package assumes that the user is logged in and displays the appropriate content.
|
|
143
444
|
|
|
144
|
-
The `LoginModal` component also is used in [`MyTicketsContainer`](#myticketscontainer) and
|
|
445
|
+
The `LoginModal` component also is used in [`MyTicketsContainer`](#myticketscontainer) and [`TicketsContainer`](#ticketscontainer).
|
|
145
446
|
|
|
146
|
-
To detect whether a user is logged in or not, you can use the
|
|
147
|
-
Here's an example of how to use the
|
|
447
|
+
To detect whether a user is logged in or not, you can use the **useCookieListener** hook provided by the package.
|
|
448
|
+
Here's an example of how to use the **useCookieListener** hook to automatically detect whether the user is logged in:
|
|
148
449
|
|
|
149
450
|
```jsx
|
|
150
451
|
import { useEffect, useRef, useState } from 'react'
|
|
@@ -154,7 +455,7 @@ const MyComponent = () => {
|
|
|
154
455
|
const [isLogged, setIsLogged] = useState(false)
|
|
155
456
|
|
|
156
457
|
// Listen for changes to the __X-TF-ECOMMERCE__ cookie
|
|
157
|
-
useCookieListener(
|
|
458
|
+
useCookieListener('X_TF_ECOMMERCE', value => setIsLogged(Boolean(value)))
|
|
158
459
|
|
|
159
460
|
// ... rest of component logic
|
|
160
461
|
}
|
|
@@ -187,9 +488,12 @@ const MyComponent = () => {
|
|
|
187
488
|
|
|
188
489
|
## Register
|
|
189
490
|
|
|
190
|
-
The `RegisterModal` component is designed to be used inside package to allows users to register for an account.
|
|
491
|
+
The `RegisterModal` component is designed to be used inside package to allows users to register for an account. <br />
|
|
191
492
|
|
|
192
|
-
When the user submits the form, the component calls the register API function to create the user's account.
|
|
493
|
+
When the user submits the form, the component calls the register API function to create the user's account.
|
|
494
|
+
If account creation is successful, the component then retrieves the user's profile data. The **onGetProfileDataSuccess** and **onGetProfileDataError** callbacks are then called depending on whether the profile data retrieval succeeds or fails.
|
|
495
|
+
If profile data retrieval succeeds, the component maps the profile data to a format used by the application and saves the resulting data to the browser's localStorage.
|
|
496
|
+
Finally, the **onClose** callback is called to close the modal.
|
|
193
497
|
|
|
194
498
|
<details open>
|
|
195
499
|
<summary><b>Register Modal Props Interface:</b></summary>
|
|
@@ -208,7 +512,9 @@ When the user submits the form, the component calls the register API function to
|
|
|
208
512
|
|
|
209
513
|
## Forgot Password
|
|
210
514
|
|
|
211
|
-
The `ForgotPasswordModal` component is a modal dialog for users to reset their passwords.
|
|
515
|
+
The `ForgotPasswordModal` component is a modal dialog for users to reset their passwords.
|
|
516
|
+
To use it, simply import the component, manage its open state, and provide callback functions for closing the modal, navigating back to the login page or component, handling successful password reset requests, and handling errors in password reset requests.
|
|
517
|
+
Optionally, you can also display a "Powered By" image within the modal by setting the **showPoweredByImage** prop to true.
|
|
212
518
|
|
|
213
519
|
<details open>
|
|
214
520
|
<summary><b>Forgot Password Modal Props Interface:</b></summary>
|
|
@@ -226,13 +532,14 @@ The `ForgotPasswordModal` component is a modal dialog for users to reset their p
|
|
|
226
532
|
|
|
227
533
|
## Promo Code
|
|
228
534
|
|
|
229
|
-
The `PromoCodeSection` is a React component for handling promo code input, validation, and displaying success or error messages.
|
|
535
|
+
The `PromoCodeSection` is a React component for handling promo code input, validation, and displaying success or error messages.
|
|
536
|
+
It accepts various props to control its appearance and behavior, such as the promo code value, validation status, input visibility, and callback functions for updating the state which you can see in the below provided table.
|
|
230
537
|
|
|
231
538
|
To use this component, simply import it and include it in your JSX with the required props, managing the component's state and callback functions in the parent component as needed.
|
|
232
539
|
|
|
233
|
-
###
|
|
234
|
-
<br />
|
|
540
|
+
### **Note that package automatically calls component in [`TicketsContainer`](#ticketscontainer)**
|
|
235
541
|
|
|
542
|
+
<br />
|
|
236
543
|
|
|
237
544
|
<details open>
|
|
238
545
|
<summary><b>Promo Code Props Interface:</b></summary>
|
|
@@ -257,11 +564,14 @@ To use this component, simply import it and include it in your JSX with the requ
|
|
|
257
564
|
|
|
258
565
|
## Access Code
|
|
259
566
|
|
|
260
|
-
The `AccessCodeSection` is a React component designed for handling access code input and submission.
|
|
567
|
+
The `AccessCodeSection` is a React component designed for handling access code input and submission.
|
|
568
|
+
It allows users to enter an access code and triggers an update to the ticket information based on the submitted access code.
|
|
569
|
+
The component accepts a set of props to manage the access code value and provide callback functions for updating the state which you can see in below table.
|
|
261
570
|
|
|
262
|
-
To integrate the `AccessCodeSection` component, import it into your JSX and provide the required props, such as the access code value, and callback functions for updating the state.
|
|
571
|
+
To integrate the `AccessCodeSection` component, import it into your JSX and provide the required props, such as the access code value, and callback functions for updating the state.
|
|
572
|
+
Make sure to manage the component's state and callback functions within the parent component as needed. <br />
|
|
263
573
|
|
|
264
|
-
###
|
|
574
|
+
### **Note that package automatically calls component in [`TicketsContainer`](#ticketscontainer)**
|
|
265
575
|
|
|
266
576
|
<br />
|
|
267
577
|
|
|
@@ -280,10 +590,11 @@ To integrate the `AccessCodeSection` component, import it into your JSX and prov
|
|
|
280
590
|
|
|
281
591
|
## Waiting List
|
|
282
592
|
|
|
283
|
-
The `WaitingList` component is a React component designed to handle user registration for a waiting list.
|
|
593
|
+
The `WaitingList` component is a React component designed to handle user registration for a waiting list.
|
|
594
|
+
It displays a form that allows users to input their information, including first name, last name, email, ticket type, and quantity.
|
|
595
|
+
Upon submission, the component adds the user to the waiting list and displays a success message.
|
|
284
596
|
|
|
285
|
-
|
|
286
|
-
### __Note that package automatically calls component in [`TicketsContainer`](#ticketscontainer)__
|
|
597
|
+
### **Note that package automatically calls component in [`TicketsContainer`](#ticketscontainer)**
|
|
287
598
|
|
|
288
599
|
<br />
|
|
289
600
|
|
|
@@ -317,33 +628,40 @@ Here is the list of pages where the `usePixel` function is automatically used:
|
|
|
317
628
|
|
|
318
629
|
# Components
|
|
319
630
|
|
|
320
|
-
|
|
321
631
|
## `TicketsContainer`
|
|
322
632
|
|
|
323
633
|
Tickets component will retrieve and show a list of tickets corresponding to selected event,
|
|
324
634
|
which allows the user to select the desired ticket type and quantity.
|
|
325
635
|
|
|
326
|
-
The
|
|
636
|
+
The **"Get Tickets"** button which name is also customizable, allows the user to add the selected tickets to their cart and proceed to the checkout process.<br />
|
|
327
637
|
Other buttons can be displayed to handle various actions, such as viewing the user's orders or logging out.
|
|
328
638
|
|
|
329
639
|
Tickets component provides a section for entering an [Access Code](#access-code) or [Promo Code](#promo-code) that applies a discount to the ticket price or hide/unhide some tickets via [Access Code](#access-code).<br />
|
|
330
|
-
It also
|
|
640
|
+
It also contains `WaitingList` that manages and displays waiting list functionality for the event.<br />
|
|
331
641
|
Props interface partially extends [Promo Code Props Interface](#promo-code), [Access Code Props Interface](#access-code), [Waiting List Props Interface](#waiting-list).
|
|
332
642
|
|
|
333
643
|
Tickets component displays a list of the top influencers who have promoted the event.
|
|
334
644
|
|
|
645
|
+
**Recent Improvements:**
|
|
646
|
+
|
|
647
|
+
- Fixed duplicate API calls issue by optimizing useEffect dependencies
|
|
648
|
+
- Enhanced error handling and loading states
|
|
649
|
+
- Improved time slot management for events
|
|
650
|
+
- Better integration with promo codes and access codes
|
|
651
|
+
- Optimized component re-rendering patterns
|
|
652
|
+
|
|
335
653
|
Tickets component is flexible and customizable, allowing for different layouts and behaviors depending on the event's requirements.
|
|
336
654
|
|
|
337
|
-
|
|
338
|
-
```jsx
|
|
655
|
+
**_Example of usage_**:
|
|
339
656
|
|
|
657
|
+
```jsx
|
|
340
658
|
import { TicketsContainer } from 'tf-checkout-react'
|
|
341
659
|
|
|
342
660
|
<TicketsContainer
|
|
343
661
|
theme="light"
|
|
344
662
|
eventId={event?.id}
|
|
345
|
-
handleNotInvitedModalClose={() => {
|
|
346
|
-
handleInvalidLinkModalClose={() => {
|
|
663
|
+
handleNotInvitedModalClose={() => {}}
|
|
664
|
+
handleInvalidLinkModalClose={() => {}}
|
|
347
665
|
onAddToCartSuccess={() => {}}
|
|
348
666
|
isPromotionsEnabled={event?.is_promotions_enabled}
|
|
349
667
|
isAccessCodeEnabled={event?.is_access_code}
|
|
@@ -351,7 +669,9 @@ import { TicketsContainer } from 'tf-checkout-react'
|
|
|
351
669
|
hideSessionButtons={true}
|
|
352
670
|
enableAddOns={false}
|
|
353
671
|
showGroupNameBlock={true}
|
|
354
|
-
tableTicketsHeaderComponent={
|
|
672
|
+
tableTicketsHeaderComponent={
|
|
673
|
+
<div className="tickets-container-header">RESERVE TABLES</div>
|
|
674
|
+
}
|
|
355
675
|
onPendingVerification={() => {}}
|
|
356
676
|
/>
|
|
357
677
|
```
|
|
@@ -431,9 +751,18 @@ Add-Ons component will retrieve and show a list of add-ons corresponding to sele
|
|
|
431
751
|
|
|
432
752
|
|
|
433
753
|
## `BillingInfoContainer`
|
|
434
|
-
The component is responsible for managing the billing information during the checkout process. It provides a form that allows users to enter their billing information, including addresses and ticket holders' information.
|
|
435
754
|
|
|
436
|
-
|
|
755
|
+
The component is responsible for managing the billing information during the checkout process. It provides a form that allows users to enter their billing information, including addresses and ticket holders' information.
|
|
756
|
+
|
|
757
|
+
Component includes phone field validation functionality provided by Twilio, which adds an additional layer of verification and security during the ticket purchase process.
|
|
758
|
+
|
|
759
|
+
**Recent Improvements:**
|
|
760
|
+
|
|
761
|
+
- Enhanced architecture with better separation of concerns
|
|
762
|
+
- Improved form validation and error handling
|
|
763
|
+
- Better TypeScript typing throughout the component
|
|
764
|
+
- Optimized API call patterns to prevent duplicate requests
|
|
765
|
+
- Enhanced field rendering system for better customization
|
|
437
766
|
|
|
438
767
|
Props interface extends [Login Modal Interface](#login), [Register Modal Interface](#register), [Forgot Password Modal Interface](#forgot-password).
|
|
439
768
|
|
|
@@ -480,7 +809,16 @@ Props interface extends [Login Modal Interface](#login), [Register Modal Interfa
|
|
|
480
809
|
|
|
481
810
|
|
|
482
811
|
## `PaymentContainer`
|
|
483
|
-
|
|
812
|
+
|
|
813
|
+
The component provides a form for users to enter their payment information and checkout. It accepts various props to customize the form and handle the checkout process.
|
|
814
|
+
|
|
815
|
+
**Recent Improvements:**
|
|
816
|
+
|
|
817
|
+
- Enhanced Stripe integration with better error handling
|
|
818
|
+
- Improved payment field validation and user feedback
|
|
819
|
+
- Better handling of payment method creation and confirmation
|
|
820
|
+
- Enhanced payment plan support with improved UI
|
|
821
|
+
- Optimized payment flow for better user experience
|
|
484
822
|
|
|
485
823
|
<details open>
|
|
486
824
|
|
|
@@ -512,7 +850,8 @@ The component provides a form for users to enter their payment information and c
|
|
|
512
850
|
|
|
513
851
|
|
|
514
852
|
## `ConfirmationContainer`
|
|
515
|
-
|
|
853
|
+
|
|
854
|
+
The component is responsible for displaying the confirmation page after a successful payment.
|
|
516
855
|
|
|
517
856
|
<details open>
|
|
518
857
|
|
|
@@ -539,7 +878,8 @@ The component is responsible for displaying the confirmation page after a succes
|
|
|
539
878
|
|
|
540
879
|
|
|
541
880
|
## `MyTicketsContainer`
|
|
542
|
-
|
|
881
|
+
|
|
882
|
+
The component is responsible for rendering a list of orders with details and some customization options.
|
|
543
883
|
|
|
544
884
|
<details open>
|
|
545
885
|
|
|
@@ -636,8 +976,8 @@ Container renders information about accepting or declining of resold tickets. It
|
|
|
636
976
|
<details open>
|
|
637
977
|
<summary><small id="1">1. Share buttons</small></summary>
|
|
638
978
|
|
|
639
|
-
```
|
|
640
|
-
IShareButton {
|
|
979
|
+
```ts
|
|
980
|
+
interface IShareButton {
|
|
641
981
|
mainLabel: string;
|
|
642
982
|
subLabel: string;
|
|
643
983
|
platform: string;
|
|
@@ -645,7 +985,7 @@ IShareButton {
|
|
|
645
985
|
}
|
|
646
986
|
```
|
|
647
987
|
|
|
648
|
-
```
|
|
988
|
+
```yaml
|
|
649
989
|
Default share options if `showDefaultShareButtons` is true, are: "Share on Facebook", "Tweet to your Followers", "Message friends on Facebook" and "Message friends on WhatsApp".
|
|
650
990
|
```
|
|
651
991
|
|
|
@@ -654,15 +994,15 @@ Default share options if `showDefaultShareButtons` is true, are: "Share on Faceb
|
|
|
654
994
|
<details open>
|
|
655
995
|
<summary><small id="2">2. Confirmation Labels</small></summary>
|
|
656
996
|
|
|
657
|
-
```
|
|
658
|
-
IConfirmationLabels {
|
|
997
|
+
```ts
|
|
998
|
+
interface IConfirmationLabels {
|
|
659
999
|
confirmationTitle?: string;
|
|
660
1000
|
confirmationMain?: string;
|
|
661
1001
|
confirmationHelper?: string
|
|
662
1002
|
}
|
|
663
1003
|
```
|
|
664
1004
|
|
|
665
|
-
```
|
|
1005
|
+
```js
|
|
666
1006
|
const defaultConfirmationLabels = {
|
|
667
1007
|
confirmationTitle = "Your Tickets are Confirmed!",
|
|
668
1008
|
confirmationMain = "Your tickets are available in My Tickets section",
|
|
@@ -675,7 +1015,7 @@ const defaultConfirmationLabels = {
|
|
|
675
1015
|
<details open>
|
|
676
1016
|
<summary><small id="3">3. Tickets table columns</small></summary>
|
|
677
1017
|
|
|
678
|
-
```
|
|
1018
|
+
```ts
|
|
679
1019
|
interface ITicketsTableColumns {
|
|
680
1020
|
id?: string | number;
|
|
681
1021
|
key: keyof ITicketTypes & keyof IActionColumns;
|
|
@@ -688,7 +1028,7 @@ interface IActionColumns {
|
|
|
688
1028
|
}
|
|
689
1029
|
```
|
|
690
1030
|
|
|
691
|
-
```
|
|
1031
|
+
```ts
|
|
692
1032
|
const defaultTicketsTableColumns = [
|
|
693
1033
|
{ key: 'ticket_type', label: 'Ticket Type' },
|
|
694
1034
|
{ key: 'holder_name', label: 'Ticket Holder' },
|
|
@@ -726,7 +1066,7 @@ To do a one-off build, use `npm run build` or `yarn build`.
|
|
|
726
1066
|
|
|
727
1067
|
|
|
728
1068
|
|
|
729
|
-
|
|
1069
|
+
## Rollup
|
|
730
1070
|
|
|
731
1071
|
TSDX uses [Rollup](https://rollupjs.org) as a bundler and generates multiple rollup configs for various module formats and build settings. See [Optimizations](#optimizations) for details.
|
|
732
1072
|
|
|
@@ -742,3 +1082,5 @@ Two actions are added by default:
|
|
|
742
1082
|
|
|
743
1083
|
- `main` which installs deps w/ cache, lints, tests, and builds on all pushes against a Node and OS matrix
|
|
744
1084
|
- `size` which comments cost comparison of your library on every pull request using [`size-limit`](https://github.com/ai/size-limit)
|
|
1085
|
+
|
|
1086
|
+
## Optimizations
|