tf-checkout-react 1.0.77 → 1.0.81
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/dist/api/index.d.ts +1 -0
- package/dist/components/billing-info-container/index.d.ts +1 -1
- package/dist/components/common/FormikPhoneNumberField.d.ts +1 -1
- package/dist/components/countdown/index.d.ts +11 -0
- package/dist/components/orderDetailsContainer/ticketsTable.d.ts +13 -1
- package/dist/components/paymentContainer/index.d.ts +5 -2
- package/dist/components/ticketsContainer/PromoCodeSection.d.ts +2 -1
- package/dist/components/ticketsContainer/index.d.ts +10 -1
- package/dist/components/waitingList/index.d.ts +1 -2
- package/dist/hooks/usePrevious.d.ts +1 -0
- package/dist/tf-checkout-react.cjs.development.js +458 -156
- 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 +460 -158
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/dist/tf-checkout-styles.css +1 -1
- package/dist/utils/downloadPDF.d.ts +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +2 -1
- package/src/api/index.ts +9 -0
- package/src/components/billing-info-container/index.tsx +19 -6
- package/src/components/common/CheckboxField.tsx +13 -9
- package/src/components/common/FormikPhoneNumberField.tsx +2 -1
- package/src/components/countdown/index.tsx +89 -0
- package/src/components/countdown/style.css +10 -0
- package/src/components/loginModal/index.tsx +2 -0
- package/src/components/orderDetailsContainer/ticketsTable.tsx +66 -60
- package/src/components/paymentContainer/index.tsx +6 -3
- package/src/components/stripePayment/index.tsx +3 -3
- package/src/components/ticketsContainer/PromoCodeSection.tsx +46 -32
- package/src/components/ticketsContainer/TicketsSection.tsx +10 -6
- package/src/components/ticketsContainer/index.tsx +191 -70
- package/src/components/ticketsContainer/style.css +7 -0
- package/src/components/waitingList/index.tsx +3 -9
- package/src/components/waitingList/style.css +4 -2
- package/src/hooks/usePrevious.tsx +9 -0
- package/src/utils/downloadPDF.tsx +30 -0
- package/src/utils/index.ts +2 -1
|
@@ -9,7 +9,7 @@ export interface IPromoCodeSectionProps {
|
|
|
9
9
|
showPromoInput: boolean;
|
|
10
10
|
isPromotionsEnabled: boolean;
|
|
11
11
|
isAllTicketsSoldOut: boolean;
|
|
12
|
-
|
|
12
|
+
isAccessCodeEnabled?: boolean;
|
|
13
13
|
setPromoCode: (value: string) => void;
|
|
14
14
|
setPromoCodeUpdated: (value: string) => void;
|
|
15
15
|
setShowPromoInput: (value: boolean) => void;
|
|
@@ -20,11 +20,49 @@ export const PromoCodeSection = ({
|
|
|
20
20
|
promoCodeIsApplied,
|
|
21
21
|
showPromoInput,
|
|
22
22
|
isPromotionsEnabled,
|
|
23
|
-
isAllTicketsSoldOut,
|
|
24
23
|
setPromoCode,
|
|
25
24
|
setPromoCodeUpdated,
|
|
26
25
|
setShowPromoInput,
|
|
26
|
+
isAccessCodeEnabled,
|
|
27
27
|
}: IPromoCodeSectionProps) => {
|
|
28
|
+
const isPromoCodeHasValue = !!promoCode.trim()
|
|
29
|
+
|
|
30
|
+
const renderInputField = () => {
|
|
31
|
+
return (
|
|
32
|
+
<div className="promo-code-block">
|
|
33
|
+
<div className="promo-code-block">
|
|
34
|
+
<p className="promo-code-text">
|
|
35
|
+
{ isAccessCodeEnabled ? 'Access code required' : 'Promo code'}
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
</div>
|
|
39
|
+
<input
|
|
40
|
+
className="promo-code-input"
|
|
41
|
+
placeholder=""
|
|
42
|
+
onChange={e => {
|
|
43
|
+
setPromoCode(e.target.value)
|
|
44
|
+
}}
|
|
45
|
+
onKeyPress={event => {
|
|
46
|
+
if (event.key === 'Enter' && isPromoCodeHasValue) {
|
|
47
|
+
setPromoCodeUpdated(promoCode)
|
|
48
|
+
setShowPromoInput(false)
|
|
49
|
+
}
|
|
50
|
+
}}
|
|
51
|
+
/>
|
|
52
|
+
<Button
|
|
53
|
+
className="promo-submit-button"
|
|
54
|
+
onClick={() => {
|
|
55
|
+
if (isPromoCodeHasValue) {
|
|
56
|
+
setPromoCodeUpdated(promoCode)
|
|
57
|
+
setShowPromoInput(false)
|
|
58
|
+
}
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
{isAccessCodeEnabled ? 'ENTER' : 'APPLY'}
|
|
62
|
+
</Button>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
28
66
|
|
|
29
67
|
return (
|
|
30
68
|
<div >
|
|
@@ -34,39 +72,13 @@ export const PromoCodeSection = ({
|
|
|
34
72
|
src={getImage('done.svg')}
|
|
35
73
|
preProcessor={(code) => code.replace(/fill=".*?"/g, 'fill="currentColor"')}
|
|
36
74
|
/>
|
|
37
|
-
<p>PROMO CODE APPLIED SUCCESSFULLY</p>
|
|
75
|
+
<p className="promo-code-success">PROMO CODE APPLIED SUCCESSFULLY</p>
|
|
38
76
|
</div>
|
|
39
77
|
) : null}
|
|
40
78
|
{showPromoInput && (
|
|
41
|
-
|
|
42
|
-
<input
|
|
43
|
-
placeholder="Promo Code"
|
|
44
|
-
onChange={e => {
|
|
45
|
-
setPromoCode(e.target.value)
|
|
46
|
-
}}
|
|
47
|
-
onKeyPress={event => {
|
|
48
|
-
if (event.key === 'Enter') {
|
|
49
|
-
setPromoCodeUpdated(promoCode)
|
|
50
|
-
}
|
|
51
|
-
}}
|
|
52
|
-
/>
|
|
53
|
-
<Button
|
|
54
|
-
className="promo-apply-button"
|
|
55
|
-
placeholder="Promo Code"
|
|
56
|
-
onClick={() => {
|
|
57
|
-
setPromoCodeUpdated(promoCode)
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
Apply
|
|
61
|
-
</Button>
|
|
62
|
-
</div>
|
|
79
|
+
renderInputField()
|
|
63
80
|
)}
|
|
64
|
-
{isPromotionsEnabled && !showPromoInput &&
|
|
65
|
-
<p className="promo-code-text">
|
|
66
|
-
Access code needed
|
|
67
|
-
</p>
|
|
68
|
-
)}
|
|
69
|
-
{isPromotionsEnabled && !showPromoInput ? (
|
|
81
|
+
{isPromotionsEnabled && !showPromoInput && !isAccessCodeEnabled ? (
|
|
70
82
|
<Button
|
|
71
83
|
className="promo-code-button"
|
|
72
84
|
placeholder="Promo Codes"
|
|
@@ -76,7 +88,9 @@ export const PromoCodeSection = ({
|
|
|
76
88
|
>
|
|
77
89
|
Got a promo code? Click here
|
|
78
90
|
</Button>
|
|
79
|
-
) :
|
|
91
|
+
) : !isPromotionsEnabled && !showPromoInput && isAccessCodeEnabled && !promoCodeIsApplied ? renderInputField() :
|
|
92
|
+
null
|
|
93
|
+
}
|
|
80
94
|
</div>
|
|
81
95
|
)
|
|
82
96
|
}
|
|
@@ -66,12 +66,16 @@ export const TicketsSection = ({
|
|
|
66
66
|
className="event-detail__tier-state"
|
|
67
67
|
style={{ minWidth: 55 }}
|
|
68
68
|
>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
{ticket.salesStarted ? (
|
|
70
|
+
<TicketRow
|
|
71
|
+
ticketTier={ticket}
|
|
72
|
+
prevTicketTier={arr[i - 1]}
|
|
73
|
+
selectedTickets={selectedTickets}
|
|
74
|
+
handleTicketSelect={ticketSelect}
|
|
75
|
+
/>
|
|
76
|
+
) : (
|
|
77
|
+
<p className='ticket-not-started-message'>Sales not started</p>
|
|
78
|
+
)}
|
|
75
79
|
</div>
|
|
76
80
|
</div>
|
|
77
81
|
</div>
|
|
@@ -4,6 +4,7 @@ import './style.css'
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
getTickets,
|
|
7
|
+
getEvent,
|
|
7
8
|
addToCart,
|
|
8
9
|
setCustomHeader,
|
|
9
10
|
postOnCheckout,
|
|
@@ -18,7 +19,12 @@ import jwt_decode from 'jwt-decode'
|
|
|
18
19
|
import { TicketsSection } from './TicketsSection'
|
|
19
20
|
import WaitingList from '../waitingList'
|
|
20
21
|
import { PromoCodeSection } from './PromoCodeSection'
|
|
22
|
+
import { LoginModal } from '../loginModal'
|
|
23
|
+
import Countdown from '../countdown'
|
|
21
24
|
import { createCheckoutDataBodyWithDefaultHolder } from '../../utils'
|
|
25
|
+
import { ThemeProvider } from '@mui/private-theming'
|
|
26
|
+
import { createTheme, ThemeOptions } from '@mui/material'
|
|
27
|
+
import { CSSProperties } from '@mui/styles'
|
|
22
28
|
|
|
23
29
|
function Loader() {
|
|
24
30
|
return (
|
|
@@ -44,10 +50,14 @@ export interface IGetTickets {
|
|
|
44
50
|
onAddToCartError: (e: AxiosError) => void;
|
|
45
51
|
onGetTicketsSuccess: (response: any) => void;
|
|
46
52
|
onGetTicketsError: (e: AxiosError) => void;
|
|
53
|
+
onLoginSuccess: () => void;
|
|
47
54
|
|
|
48
55
|
theme?: 'light' | 'dark';
|
|
49
56
|
queryPromoCode?: string;
|
|
50
57
|
isPromotionsEnabled?: boolean;
|
|
58
|
+
themeOptions?: ThemeOptions & { input?: CSSProperties; checkbox?: CSSProperties }
|
|
59
|
+
isAccessCodeEnabled?: boolean;
|
|
60
|
+
hideSessionButtons?: boolean;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
export interface ITicket {
|
|
@@ -60,6 +70,7 @@ export interface ISelectedTickets {
|
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
export const TicketsContainer = ({
|
|
73
|
+
onLoginSuccess,
|
|
63
74
|
getTicketsLabel,
|
|
64
75
|
eventId,
|
|
65
76
|
onAddToCartSuccess,
|
|
@@ -70,11 +81,20 @@ export const TicketsContainer = ({
|
|
|
70
81
|
theme = 'light',
|
|
71
82
|
queryPromoCode = '',
|
|
72
83
|
isPromotionsEnabled = true,
|
|
84
|
+
themeOptions,
|
|
85
|
+
isAccessCodeEnabled = false,
|
|
86
|
+
hideSessionButtons = false
|
|
73
87
|
}: IGetTickets) => {
|
|
74
88
|
const [selectedTickets, setSelectedTickets] = useState(
|
|
75
89
|
{} as ISelectedTickets
|
|
76
90
|
)
|
|
91
|
+
const isWindowDefined = typeof window !== 'undefined'
|
|
92
|
+
const [isLogged, setIsLogged] = useState(
|
|
93
|
+
isWindowDefined ? !!window.localStorage.getItem('access_token') : false
|
|
94
|
+
)
|
|
95
|
+
const [showLoginModal, setShowLoginModal] = React.useState(false)
|
|
77
96
|
const [tickets, setTickets] = useState([] as ITicket[])
|
|
97
|
+
const [event, setEvent] = useState<any>(null)
|
|
78
98
|
const [showWaitingList, setShowWaitingList] = useState(false)
|
|
79
99
|
const [isLoading, setIsLoading] = useState(false)
|
|
80
100
|
const [handleBookIsLoading, setHandleBookIsLoading] = useState(false)
|
|
@@ -97,29 +117,60 @@ export const TicketsContainer = ({
|
|
|
97
117
|
}, [])
|
|
98
118
|
|
|
99
119
|
useEffect(() => {
|
|
100
|
-
async function getTicketsApi() {
|
|
101
|
-
try {
|
|
102
|
-
setIsLoading(true)
|
|
103
|
-
const response = await getTickets(eventId, promoCodeUpdated)
|
|
104
|
-
if (response.data.success) {
|
|
105
|
-
setCustomHeader(response)
|
|
106
|
-
const attributes = _get(response, 'data.data.attributes')
|
|
107
|
-
setPromoCodeIsApplied(attributes.ValidPromoCode)
|
|
108
|
-
setTickets(_get(attributes, 'tickets'))
|
|
109
|
-
setShowWaitingList(attributes.showWaitingList)
|
|
110
|
-
onGetTicketsSuccess(response.data)
|
|
111
|
-
}
|
|
112
|
-
} catch (e) {
|
|
113
|
-
if (axios.isAxiosError(e)) {
|
|
114
|
-
onGetTicketsError(e)
|
|
115
|
-
}
|
|
116
|
-
} finally {
|
|
117
|
-
setIsLoading(false)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
120
|
getTicketsApi()
|
|
121
121
|
}, [eventId, promoCodeUpdated])
|
|
122
122
|
|
|
123
|
+
const handleLogout = () => {
|
|
124
|
+
if (isWindowDefined) {
|
|
125
|
+
window.localStorage.removeItem('access_token')
|
|
126
|
+
window.localStorage.removeItem('user_data')
|
|
127
|
+
setIsLogged(false)
|
|
128
|
+
const event = new window.CustomEvent('tf-logout')
|
|
129
|
+
window.document.dispatchEvent(event)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const handleExternalLogin = () => {
|
|
134
|
+
setIsLogged(true)
|
|
135
|
+
}
|
|
136
|
+
const handleOnClose = () => {
|
|
137
|
+
setShowLoginModal(false)
|
|
138
|
+
}
|
|
139
|
+
const handleOnLogin = () => {
|
|
140
|
+
setShowLoginModal(false)
|
|
141
|
+
setIsLogged(true)
|
|
142
|
+
if (onLoginSuccess) {
|
|
143
|
+
onLoginSuccess()
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function getTicketsApi() {
|
|
148
|
+
try {
|
|
149
|
+
setIsLoading(true)
|
|
150
|
+
const response = await getTickets(eventId, promoCodeUpdated)
|
|
151
|
+
const eventResponse = await getEvent(eventId)
|
|
152
|
+
if (response.data.success) {
|
|
153
|
+
setCustomHeader(response)
|
|
154
|
+
const attributes = _get(response, 'data.data.attributes')
|
|
155
|
+
setPromoCodeIsApplied(attributes.ValidPromoCode)
|
|
156
|
+
setTickets(_get(attributes, 'tickets'))
|
|
157
|
+
setShowWaitingList(attributes.showWaitingList)
|
|
158
|
+
onGetTicketsSuccess(response.data)
|
|
159
|
+
setPromoCode('')
|
|
160
|
+
}
|
|
161
|
+
if (eventResponse.data.success) {
|
|
162
|
+
const event = _get(eventResponse, 'data.data.attributes')
|
|
163
|
+
setEvent(event)
|
|
164
|
+
}
|
|
165
|
+
} catch (e) {
|
|
166
|
+
if (axios.isAxiosError(e)) {
|
|
167
|
+
onGetTicketsError(e)
|
|
168
|
+
}
|
|
169
|
+
} finally {
|
|
170
|
+
setIsLoading(false)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
123
174
|
const handleTicketSelect = (key: string, value: number | string) => {
|
|
124
175
|
setSelectedTickets(prevState => {
|
|
125
176
|
if (Object.keys(prevState)[0] !== key && !value) {
|
|
@@ -131,6 +182,12 @@ export const TicketsContainer = ({
|
|
|
131
182
|
})
|
|
132
183
|
}
|
|
133
184
|
|
|
185
|
+
const handleOrdersClick = () => {
|
|
186
|
+
if (isWindowDefined) {
|
|
187
|
+
window.location.href = '/orders'
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
134
191
|
const handleBook = async () => {
|
|
135
192
|
setHandleBookIsLoading(true)
|
|
136
193
|
const ticket =
|
|
@@ -218,63 +275,127 @@ export const TicketsContainer = ({
|
|
|
218
275
|
}
|
|
219
276
|
}
|
|
220
277
|
|
|
278
|
+
const updateTickets = () => {
|
|
279
|
+
getTicketsApi()
|
|
280
|
+
}
|
|
281
|
+
|
|
221
282
|
const isAllTicketsSoldOut = !_some(
|
|
222
283
|
tickets,
|
|
223
284
|
item => !(item.sold_out || item.soldOut)
|
|
224
285
|
)
|
|
225
286
|
|
|
287
|
+
const themeMui = createTheme(themeOptions)
|
|
288
|
+
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
isWindowDefined &&
|
|
291
|
+
window.document.addEventListener('custom-logout', handleLogout)
|
|
292
|
+
return () => {
|
|
293
|
+
isWindowDefined &&
|
|
294
|
+
window.document.removeEventListener('custom-logout', handleLogout)
|
|
295
|
+
}
|
|
296
|
+
}, [])
|
|
297
|
+
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
isWindowDefined &&
|
|
300
|
+
window.document.addEventListener('custom-login', handleExternalLogin)
|
|
301
|
+
return () => {
|
|
302
|
+
isWindowDefined &&
|
|
303
|
+
window.document.removeEventListener(
|
|
304
|
+
'custom-login',
|
|
305
|
+
handleExternalLogin
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
}, [])
|
|
309
|
+
|
|
226
310
|
return (
|
|
227
|
-
<
|
|
228
|
-
{
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
311
|
+
<ThemeProvider theme={themeMui}>
|
|
312
|
+
<div className={`get-tickets-page ${theme}`} style={contentStyle}>
|
|
313
|
+
{isLoading ? (
|
|
314
|
+
<Loader />
|
|
315
|
+
) : (
|
|
316
|
+
<div>
|
|
317
|
+
<TicketsSection
|
|
318
|
+
ticketsList={tickets}
|
|
319
|
+
selectedTickets={selectedTickets}
|
|
320
|
+
handleTicketSelect={handleTicketSelect}
|
|
321
|
+
promoCodeIsApplied={promoCodeIsApplied}
|
|
322
|
+
/>
|
|
323
|
+
{event?.salesEnded ? (
|
|
324
|
+
<p>Sales for this event are closed.</p>
|
|
325
|
+
) : event?.salesStart ? (
|
|
326
|
+
<Countdown
|
|
327
|
+
startDate={event.salesStart}
|
|
328
|
+
timezone={event.timezone}
|
|
329
|
+
title="Sales start in:"
|
|
330
|
+
message="No tickets are currently available for this event."
|
|
331
|
+
callback={updateTickets}
|
|
332
|
+
/>
|
|
333
|
+
) : null}
|
|
334
|
+
{showWaitingList && event.salesStarted && (
|
|
335
|
+
<WaitingList tickets={tickets} eventId={eventId} />
|
|
336
|
+
)}
|
|
337
|
+
<PromoCodeSection
|
|
338
|
+
promoCode={promoCode}
|
|
339
|
+
promoCodeIsApplied={promoCodeIsApplied}
|
|
340
|
+
showPromoInput={showPromoInput}
|
|
341
|
+
setPromoCode={setPromoCode}
|
|
342
|
+
setPromoCodeUpdated={setPromoCodeUpdated}
|
|
343
|
+
setShowPromoInput={setShowPromoInput}
|
|
242
344
|
isPromotionsEnabled={isPromotionsEnabled}
|
|
345
|
+
isAccessCodeEnabled={isAccessCodeEnabled}
|
|
346
|
+
isAllTicketsSoldOut={isAllTicketsSoldOut}
|
|
243
347
|
/>
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
348
|
+
{!isAllTicketsSoldOut && (
|
|
349
|
+
<Button
|
|
350
|
+
aria-hidden={true}
|
|
351
|
+
className={`book-button ${
|
|
352
|
+
handleBookIsLoading ||
|
|
353
|
+
_isEmpty(selectedTickets) ||
|
|
354
|
+
Object.values(selectedTickets)[0] === 0
|
|
355
|
+
? 'disabled'
|
|
356
|
+
: ''
|
|
357
|
+
}`}
|
|
358
|
+
onClick={
|
|
359
|
+
!handleBookIsLoading &&
|
|
360
|
+
!_isEmpty(selectedTickets) &&
|
|
361
|
+
Object.values(selectedTickets)[0] > 0
|
|
362
|
+
? handleBook
|
|
363
|
+
: () => {}
|
|
364
|
+
}
|
|
365
|
+
>
|
|
366
|
+
{getTicketsLabel || 'GET TICKETS'}
|
|
367
|
+
</Button>
|
|
368
|
+
)}
|
|
369
|
+
{isLogged && !hideSessionButtons ? (
|
|
370
|
+
<div className="session-wrapper">
|
|
371
|
+
<span className="session-container">
|
|
372
|
+
<Button
|
|
373
|
+
variant="outline-light"
|
|
374
|
+
className="session-buttons"
|
|
375
|
+
onClick={handleOrdersClick}
|
|
376
|
+
>
|
|
377
|
+
My Orders
|
|
378
|
+
</Button>
|
|
379
|
+
</span>
|
|
380
|
+
<span className="session-container">
|
|
381
|
+
<Button
|
|
382
|
+
variant="outline-light"
|
|
383
|
+
className="session-buttons"
|
|
384
|
+
onClick={handleLogout}
|
|
385
|
+
>
|
|
386
|
+
Log out
|
|
387
|
+
</Button>
|
|
388
|
+
</span>
|
|
389
|
+
</div>
|
|
390
|
+
) : (
|
|
391
|
+
''
|
|
392
|
+
)}
|
|
393
|
+
</div>
|
|
394
|
+
)}
|
|
395
|
+
{showLoginModal ? (
|
|
396
|
+
<LoginModal onClose={handleOnClose} onLogin={handleOnLogin} />
|
|
397
|
+
) : null}
|
|
398
|
+
</div>
|
|
399
|
+
</ThemeProvider>
|
|
279
400
|
)
|
|
280
401
|
}
|
|
@@ -108,6 +108,13 @@ body {
|
|
|
108
108
|
text-transform: uppercase;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
.event-detail__tier-state .ticket-not-started-message {
|
|
112
|
+
color: #000000;
|
|
113
|
+
text-transform: initial;
|
|
114
|
+
width: 50px;
|
|
115
|
+
text-align: left;
|
|
116
|
+
}
|
|
117
|
+
|
|
111
118
|
.promo-code-block input {
|
|
112
119
|
font-size: 14px;
|
|
113
120
|
padding: 1px 8px;
|
|
@@ -16,7 +16,6 @@ import './style.css'
|
|
|
16
16
|
interface WaitingListProps {
|
|
17
17
|
tickets: any;
|
|
18
18
|
eventId: number;
|
|
19
|
-
isPromotionsEnabled: boolean;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
interface WaitingListFields {
|
|
@@ -35,7 +34,7 @@ const generateQuantity = (n: number) => {
|
|
|
35
34
|
return quantityList
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
const WaitingList = ({ tickets = {}, eventId
|
|
37
|
+
const WaitingList = ({ tickets = {}, eventId }: WaitingListProps) => {
|
|
39
38
|
const [showSuccessMessage, setShowSuccessMessage] = useState(false)
|
|
40
39
|
const [loading, setLoading] = useState(false)
|
|
41
40
|
const ticketTypesList = Object.values(tickets).map((d: any) => ({
|
|
@@ -68,16 +67,11 @@ const WaitingList = ({ tickets = {}, eventId, isPromotionsEnabled }: WaitingList
|
|
|
68
67
|
<div className="waiting-list">
|
|
69
68
|
{showSuccessMessage ? (
|
|
70
69
|
<div className="success-message">
|
|
71
|
-
<p className="added-success-message">
|
|
72
|
-
<p>
|
|
70
|
+
<p className="added-success-message">You've been added to the waiting list!</p>
|
|
71
|
+
<p>You'll be notified if tickets become available.</p>
|
|
73
72
|
</div>
|
|
74
73
|
) : (
|
|
75
74
|
<>
|
|
76
|
-
{!isPromotionsEnabled && (
|
|
77
|
-
<p className="no-tickets-text">
|
|
78
|
-
No tickets are currently available for this event.
|
|
79
|
-
</p>
|
|
80
|
-
)}
|
|
81
75
|
<h2>WAITING LIST</h2>
|
|
82
76
|
<Formik
|
|
83
77
|
initialValues={{
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
.waiting-list .waiting-list-button:hover {
|
|
11
11
|
background-color: #505050;
|
|
12
12
|
}
|
|
13
|
-
.waiting-list .success-message
|
|
14
|
-
|
|
13
|
+
.waiting-list .success-message {
|
|
14
|
+
text-align: center;
|
|
15
|
+
margin-bottom: 15px;
|
|
15
16
|
}
|
|
16
17
|
.waiting-list .success-message p {
|
|
17
18
|
margin: 0;
|
|
@@ -22,4 +23,5 @@
|
|
|
22
23
|
}
|
|
23
24
|
.waiting-list .added-success-message {
|
|
24
25
|
font-size: 22px;
|
|
26
|
+
margin-bottom: 10px;
|
|
25
27
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const downloadPDF = (pdfUrl: string) => {
|
|
2
|
+
if (typeof window === 'undefined') return
|
|
3
|
+
|
|
4
|
+
const accessToken: string | null = localStorage.getItem('access_token')
|
|
5
|
+
|
|
6
|
+
if (!accessToken) return
|
|
7
|
+
|
|
8
|
+
fetch(pdfUrl, {
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: `Bearer ${accessToken}`,
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
.then(async response => {
|
|
14
|
+
const blobValue = await response.blob()
|
|
15
|
+
const fileNameHeader = response.headers.get("content-disposition") || ''
|
|
16
|
+
const fileName = fileNameHeader.split('"')[1]
|
|
17
|
+
return { blobValue, fileName }
|
|
18
|
+
})
|
|
19
|
+
.then(({ blobValue, fileName }) => {
|
|
20
|
+
if (!fileName) return
|
|
21
|
+
const file = new Blob([blobValue], { type: 'application/pdf' })
|
|
22
|
+
const fileURL = URL.createObjectURL(file)
|
|
23
|
+
const link = document.createElement('a')
|
|
24
|
+
link.href = fileURL
|
|
25
|
+
link.setAttribute('download', fileName)
|
|
26
|
+
document.body.appendChild(link)
|
|
27
|
+
link.click()
|
|
28
|
+
document.body.removeChild(link)
|
|
29
|
+
})
|
|
30
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { setConfigs, CONFIGS } from './setConfigs'
|
|
2
2
|
export { getQueryVariable } from './getQueryVariable'
|
|
3
3
|
export { ErrorFocus } from './formikErrorFocus'
|
|
4
|
-
export {
|
|
4
|
+
export { downloadPDF } from './downloadPDF'
|
|
5
|
+
export { createCheckoutDataBodyWithDefaultHolder } from './createCheckoutDataBodyWithDefaultHolder'
|