tf-checkout-react 1.3.50 → 1.4.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/dist/api/index.d.ts +6 -1
- package/dist/components/common/Loader.d.ts +1 -1
- package/dist/components/idVerificationContainer/constants.d.ts +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/seatMapContainer/SeatMapComponent.d.ts +8 -0
- package/dist/components/seatMapContainer/TicketsSection.d.ts +9 -0
- package/dist/components/seatMapContainer/addToCart.d.ts +21 -0
- package/dist/components/seatMapContainer/index.d.ts +2 -0
- package/dist/components/seatMapContainer/utils.d.ts +14 -0
- package/dist/components/stripePayment/index.d.ts +2 -2
- package/dist/components/ticketsContainer/TicketRow.d.ts +3 -1
- package/dist/components/ticketsContainer/TicketsSection.d.ts +5 -1
- package/dist/components/ticketsContainer/index.d.ts +6 -2
- package/dist/index.d.ts +1 -0
- package/dist/tf-checkout-react.cjs.development.js +1441 -130
- 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 +1442 -132
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/dist/tf-checkout-styles.css +1 -1
- package/dist/types/order-data.d.ts +3 -0
- package/dist/utils/createCheckoutDataBodyWithDefaultHolder.d.ts +9 -2
- package/package.json +12 -4
- package/src/.d.ts +4 -3
- package/src/api/index.ts +89 -6
- package/src/components/billing-info-container/index.tsx +115 -103
- package/src/components/billing-info-container/utils.ts +1 -2
- package/src/components/common/Loader.tsx +6 -8
- package/src/components/confirmationContainer/index.tsx +11 -9
- package/src/components/idVerificationContainer/constants.ts +2 -0
- package/src/components/idVerificationContainer/index.tsx +54 -13
- package/src/components/index.ts +2 -1
- package/src/components/orderDetailsContainer/index.tsx +54 -23
- package/src/components/paymentContainer/index.tsx +167 -33
- package/src/components/seatMapContainer/SeatMapComponent.tsx +73 -0
- package/src/components/seatMapContainer/TicketsSection.tsx +254 -0
- package/src/components/seatMapContainer/addToCart.ts +82 -0
- package/src/components/seatMapContainer/index.tsx +408 -0
- package/src/components/seatMapContainer/utils.ts +138 -0
- package/src/components/stripePayment/index.tsx +23 -18
- package/src/components/ticketsContainer/TicketRow.tsx +28 -13
- package/src/components/ticketsContainer/TicketsSection.tsx +85 -2
- package/src/components/ticketsContainer/index.tsx +57 -12
- package/src/components/ticketsContainer/style.css +0 -3
- package/src/hooks/usePixel.ts +35 -1
- package/src/index.ts +2 -1
- package/src/types/order-data.ts +3 -0
- package/src/types/seatMap.d.ts +154 -0
- package/src/utils/createCheckoutDataBodyWithDefaultHolder.ts +6 -2
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { Alert } from '@mui/material'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
import { identity } from 'lodash'
|
|
4
|
+
import _find from 'lodash/find'
|
|
5
|
+
import _forEach from 'lodash/forEach'
|
|
6
|
+
import _get from 'lodash/get'
|
|
7
|
+
import _isEmpty from 'lodash/isEmpty'
|
|
8
|
+
import _keys from 'lodash/keys'
|
|
9
|
+
import _map from 'lodash/map'
|
|
10
|
+
import _values from 'lodash/values'
|
|
11
|
+
import moment from 'moment'
|
|
12
|
+
import React, { useCallback, useEffect, useRef,useState } from 'react'
|
|
13
|
+
import Countdown from 'react-countdown'
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
getSeatMapData,
|
|
17
|
+
getSeatMapStatuses,
|
|
18
|
+
removeSeatReserve,
|
|
19
|
+
reserveSeat,
|
|
20
|
+
} from '../../api'
|
|
21
|
+
import { showZero } from '../../utils/showZero'
|
|
22
|
+
import { addToCartFunc } from './addToCart'
|
|
23
|
+
import { SeatMapComponent } from './SeatMapComponent'
|
|
24
|
+
import { TicketsSection } from './TicketsSection'
|
|
25
|
+
import {
|
|
26
|
+
getAddToCartRequestData,
|
|
27
|
+
getOwnReservationsBasedOnStatuses,
|
|
28
|
+
getTicketDropdownData,
|
|
29
|
+
getTierIdBasedOnSeatId,
|
|
30
|
+
} from './utils'
|
|
31
|
+
|
|
32
|
+
interface IGuestCounts {
|
|
33
|
+
[key: string]: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
37
|
+
const {
|
|
38
|
+
event: {
|
|
39
|
+
id: eventId,
|
|
40
|
+
currency: { symbol },
|
|
41
|
+
tableMapEnabled,
|
|
42
|
+
country,
|
|
43
|
+
},
|
|
44
|
+
mapContainerId,
|
|
45
|
+
timerMessage = '',
|
|
46
|
+
onAddToCartSuccess = identity,
|
|
47
|
+
onCountdownFinish = identity,
|
|
48
|
+
ticketDeleteButtonContent,
|
|
49
|
+
} = props
|
|
50
|
+
|
|
51
|
+
const [seatMapData, setSeatMapData] = useState({
|
|
52
|
+
seatMap: '',
|
|
53
|
+
} as {
|
|
54
|
+
seatMap: string;
|
|
55
|
+
seatReservationTime: number;
|
|
56
|
+
seatMapType: string | null;
|
|
57
|
+
tierPrices: any;
|
|
58
|
+
predefinedSeats: any;
|
|
59
|
+
})
|
|
60
|
+
const eventSeatsRef = useRef([] as EventSeat[])
|
|
61
|
+
const ticketTypeTierRelationsRef = useRef({} as TicketTypeTierRelations)
|
|
62
|
+
const [selectedTickets, setSelectedTickets] = useState<{
|
|
63
|
+
[seatId: string]: string;
|
|
64
|
+
}>({})
|
|
65
|
+
const [seatMapStatuses, setSeatMapStatuses] = useState('')
|
|
66
|
+
const [reservedSeats, setReservedSeats] = useState<
|
|
67
|
+
Array<SeatReservationData>
|
|
68
|
+
>([])
|
|
69
|
+
const [isReserving, setIsReserving] = useState(false)
|
|
70
|
+
const [isAddingToCart, setIsAddingToCart] = useState(false)
|
|
71
|
+
const [error, setError] = useState<string | null>(null)
|
|
72
|
+
const [showTimer, setShowTimer] = useState(
|
|
73
|
+
Date.now() <= Number(localStorage.getItem(`reservationStart-${eventId}`))
|
|
74
|
+
)
|
|
75
|
+
const [guestCounts, setGuestCounts] = useState<IGuestCounts>(
|
|
76
|
+
{} as IGuestCounts
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const updateGuestCounts = (data: any) => {
|
|
80
|
+
_forEach(data, (item: any) => {
|
|
81
|
+
const tierTickets = ticketTypeTierRelationsRef.current[item.tierId]
|
|
82
|
+
const seatTicketsArray = _values(tierTickets)
|
|
83
|
+
|
|
84
|
+
setGuestCounts((prevState: any) => ({
|
|
85
|
+
...prevState,
|
|
86
|
+
[item.seatId]: Number(
|
|
87
|
+
seatTicketsArray[0].ticket_type_min_number_of_guests
|
|
88
|
+
),
|
|
89
|
+
}))
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const fetchSeatMapData = useCallback(async () => {
|
|
94
|
+
try {
|
|
95
|
+
const seatMapDataResponse = await getSeatMapData(eventId)
|
|
96
|
+
const {
|
|
97
|
+
data: {
|
|
98
|
+
attributes: {
|
|
99
|
+
seatData,
|
|
100
|
+
ticketTypeTierRelations,
|
|
101
|
+
eventSeats,
|
|
102
|
+
seatReservationTime,
|
|
103
|
+
seatMapType,
|
|
104
|
+
tierPrices,
|
|
105
|
+
predefinedSeats,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
} = seatMapDataResponse
|
|
109
|
+
eventSeatsRef.current = eventSeats
|
|
110
|
+
ticketTypeTierRelationsRef.current = ticketTypeTierRelations
|
|
111
|
+
setSeatMapData({
|
|
112
|
+
seatMap: JSON.parse(seatData),
|
|
113
|
+
seatReservationTime,
|
|
114
|
+
seatMapType,
|
|
115
|
+
tierPrices,
|
|
116
|
+
predefinedSeats,
|
|
117
|
+
})
|
|
118
|
+
} catch (error) {
|
|
119
|
+
setError('Something went wrong')
|
|
120
|
+
}
|
|
121
|
+
}, [eventId])
|
|
122
|
+
|
|
123
|
+
const fetchSeatMapReservations = useCallback(async () => {
|
|
124
|
+
try {
|
|
125
|
+
const statusesResponse = await getSeatMapStatuses(eventId)
|
|
126
|
+
const statuses = _get(statusesResponse, 'data.attributes') || {}
|
|
127
|
+
const reservationData: Array<SeatReservationData> = []
|
|
128
|
+
const ownReservations: string[] = getOwnReservationsBasedOnStatuses(
|
|
129
|
+
statuses
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
_forEach(ownReservations, reservation => {
|
|
133
|
+
const tierIdOfReservation = getTierIdBasedOnSeatId(
|
|
134
|
+
reservation,
|
|
135
|
+
eventSeatsRef.current,
|
|
136
|
+
) as string
|
|
137
|
+
reservationData.push({
|
|
138
|
+
seatId: reservation,
|
|
139
|
+
tierId: tierIdOfReservation,
|
|
140
|
+
type: 'reserve',
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
localStorage.setItem('reservationData', JSON.stringify(reservationData))
|
|
145
|
+
setSeatMapStatuses(statusesResponse.data.attributes)
|
|
146
|
+
setReservedSeats(reservationData)
|
|
147
|
+
// automatically set ticket/table type if it's the only one
|
|
148
|
+
if (ticketTypeTierRelationsRef.current) {
|
|
149
|
+
_forEach(reservationData, (item: any) => {
|
|
150
|
+
const tierTickets = ticketTypeTierRelationsRef.current[item.tierId]
|
|
151
|
+
const seatTicketsArray = _values(tierTickets)
|
|
152
|
+
|
|
153
|
+
setSelectedTickets((prevState: any) => ({
|
|
154
|
+
...prevState,
|
|
155
|
+
[item.seatId]:
|
|
156
|
+
seatTicketsArray.length === 1
|
|
157
|
+
? seatTicketsArray[0].ticket_type_id
|
|
158
|
+
: '',
|
|
159
|
+
}))
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
if (_isEmpty(reservationData)) {
|
|
163
|
+
setGuestCounts({})
|
|
164
|
+
setSelectedTickets({})
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
setError('Something went wrong')
|
|
169
|
+
}
|
|
170
|
+
}, [eventId])
|
|
171
|
+
|
|
172
|
+
const startTimer = useCallback((duration: number) => {
|
|
173
|
+
setShowTimer(true)
|
|
174
|
+
|
|
175
|
+
if (!localStorage.getItem(`reservationStart-${eventId}`)) {
|
|
176
|
+
localStorage.setItem(
|
|
177
|
+
`reservationStart-${eventId}`,
|
|
178
|
+
String(Date.now() + duration)
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
}, [])
|
|
182
|
+
|
|
183
|
+
const endTimer = useCallback(() => {
|
|
184
|
+
localStorage.removeItem(`reservationStart-${eventId}`)
|
|
185
|
+
setShowTimer(false)
|
|
186
|
+
}, [])
|
|
187
|
+
|
|
188
|
+
const handleSeatReservation = async (
|
|
189
|
+
eventId: string,
|
|
190
|
+
tierId: string,
|
|
191
|
+
seatId: string
|
|
192
|
+
) => {
|
|
193
|
+
setIsReserving(true)
|
|
194
|
+
try {
|
|
195
|
+
await reserveSeat(eventId, tierId, seatId)
|
|
196
|
+
await fetchSeatMapReservations()
|
|
197
|
+
|
|
198
|
+
startTimer(seatMapData.seatReservationTime * 60000)
|
|
199
|
+
const reservationData = JSON.parse(
|
|
200
|
+
localStorage.getItem('reservationData') || ''
|
|
201
|
+
)
|
|
202
|
+
setReservedSeats(reservationData)
|
|
203
|
+
updateGuestCounts(reservationData)
|
|
204
|
+
|
|
205
|
+
// automatically set ticket/table type if it's the only one
|
|
206
|
+
const relations = _keys(ticketTypeTierRelationsRef.current[tierId])
|
|
207
|
+
const [firstItem] = _keys(ticketTypeTierRelationsRef.current[tierId])
|
|
208
|
+
handleTicketSelect(relations.length === 1 ? firstItem : '', seatId)
|
|
209
|
+
} catch (error) {
|
|
210
|
+
setError('Something went wrong')
|
|
211
|
+
} finally {
|
|
212
|
+
setIsReserving(false)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const handleCancelSeatReservtion = async (
|
|
217
|
+
eventId: string,
|
|
218
|
+
tierId: string,
|
|
219
|
+
seatId: string
|
|
220
|
+
) => {
|
|
221
|
+
setIsReserving(true)
|
|
222
|
+
try {
|
|
223
|
+
await removeSeatReserve(eventId, tierId, [seatId])
|
|
224
|
+
await fetchSeatMapReservations()
|
|
225
|
+
if (
|
|
226
|
+
_isEmpty(JSON.parse(localStorage.getItem('reservationData') as string))
|
|
227
|
+
) {
|
|
228
|
+
endTimer()
|
|
229
|
+
}
|
|
230
|
+
const reservationData = JSON.parse(
|
|
231
|
+
localStorage.getItem('reservationData') || ''
|
|
232
|
+
)
|
|
233
|
+
const currentSelectedTickets = { ...selectedTickets }
|
|
234
|
+
delete currentSelectedTickets[seatId]
|
|
235
|
+
setReservedSeats(reservationData)
|
|
236
|
+
setSelectedTickets(currentSelectedTickets)
|
|
237
|
+
} catch (error) {
|
|
238
|
+
setError('Something went wrong')
|
|
239
|
+
} finally {
|
|
240
|
+
setIsReserving(false)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const onSeatClick = async (seatInfo: any) => {
|
|
245
|
+
const {
|
|
246
|
+
seat: { tierId, seatId, status },
|
|
247
|
+
} = seatInfo
|
|
248
|
+
|
|
249
|
+
const reservationData = JSON.parse(
|
|
250
|
+
localStorage.getItem('reservationData') || '[]'
|
|
251
|
+
)
|
|
252
|
+
if (status === 'B' || status === 'R' || status === 'BLOCKED' || status === 'RE') return
|
|
253
|
+
if (_find(reservationData, data => data.seatId === seatId)) {
|
|
254
|
+
handleCancelSeatReservtion(eventId, tierId, seatId)
|
|
255
|
+
} else if (reservationData.length >= 10) {
|
|
256
|
+
setError('Limit exceeded')
|
|
257
|
+
} else {
|
|
258
|
+
handleSeatReservation(eventId, tierId, seatId)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const handleTicketSelect = (ticketId: string, seatId: string) => {
|
|
263
|
+
const currentSelectedTickets = { ...selectedTickets }
|
|
264
|
+
currentSelectedTickets[seatId] = ticketId
|
|
265
|
+
setSelectedTickets(currentSelectedTickets)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const handleGetTicketBtnClick = async () => {
|
|
269
|
+
setIsAddingToCart(true)
|
|
270
|
+
const ticketsDropdownsData = getTicketDropdownData(
|
|
271
|
+
reservedSeats,
|
|
272
|
+
ticketTypeTierRelationsRef.current
|
|
273
|
+
)
|
|
274
|
+
let selectedSeats = {}
|
|
275
|
+
_forEach(ticketsDropdownsData, ticketData => {
|
|
276
|
+
selectedSeats = {
|
|
277
|
+
...selectedSeats,
|
|
278
|
+
[ticketData.seatId]: ticketData.ticketsData,
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
const addToCartData = getAddToCartRequestData({
|
|
282
|
+
eventId,
|
|
283
|
+
reservations: _map(reservedSeats, seat => seat.seatId),
|
|
284
|
+
selectedSeats,
|
|
285
|
+
selectedTickets,
|
|
286
|
+
guestCounts,
|
|
287
|
+
})
|
|
288
|
+
try {
|
|
289
|
+
const response = await addToCartFunc({
|
|
290
|
+
eventId,
|
|
291
|
+
data: addToCartData,
|
|
292
|
+
ticketQuantity: addToCartData?.attributes?.product_cart_quantity,
|
|
293
|
+
})
|
|
294
|
+
localStorage.removeItem('reservationData')
|
|
295
|
+
onAddToCartSuccess(response)
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (axios.isAxiosError(error)) {
|
|
298
|
+
const message = _get(error, 'response.data.message', '')
|
|
299
|
+
setError(message)
|
|
300
|
+
}
|
|
301
|
+
} finally {
|
|
302
|
+
setIsAddingToCart(false)
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
useEffect(() => {
|
|
307
|
+
if (
|
|
308
|
+
Date.now() > Number(localStorage.getItem(`reservationStart-${eventId}`))
|
|
309
|
+
) {
|
|
310
|
+
setSelectedTickets({})
|
|
311
|
+
setReservedSeats([])
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const makeRequests = async () => {
|
|
315
|
+
try {
|
|
316
|
+
await fetchSeatMapData()
|
|
317
|
+
fetchSeatMapReservations()
|
|
318
|
+
} catch (error) {
|
|
319
|
+
setError('Something went wrong')
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
makeRequests()
|
|
324
|
+
|
|
325
|
+
if (country) {
|
|
326
|
+
localStorage.setItem('eventCountry', country)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const intervalId = setInterval(() => {
|
|
330
|
+
fetchSeatMapReservations()
|
|
331
|
+
}, 3000)
|
|
332
|
+
|
|
333
|
+
return () => {
|
|
334
|
+
clearInterval(intervalId)
|
|
335
|
+
}
|
|
336
|
+
}, [fetchSeatMapData, fetchSeatMapReservations])
|
|
337
|
+
|
|
338
|
+
return (
|
|
339
|
+
<>
|
|
340
|
+
{error && (
|
|
341
|
+
<Alert
|
|
342
|
+
severity="error"
|
|
343
|
+
onClose={() => {
|
|
344
|
+
setError(null)
|
|
345
|
+
}}
|
|
346
|
+
variant="filled"
|
|
347
|
+
style={{ width: '350px' }}
|
|
348
|
+
>
|
|
349
|
+
{error}
|
|
350
|
+
</Alert>
|
|
351
|
+
)}
|
|
352
|
+
{showTimer && (
|
|
353
|
+
<Countdown
|
|
354
|
+
date={moment(
|
|
355
|
+
Number(localStorage.getItem(`reservationStart-${eventId}`))
|
|
356
|
+
).valueOf()}
|
|
357
|
+
renderer={(props: any) => (
|
|
358
|
+
<div className="reservation-countdown">
|
|
359
|
+
<span className="reservation-message">{timerMessage}</span>
|
|
360
|
+
<span className="reservation-timer">
|
|
361
|
+
{showZero(props.minutes)}:{showZero(props.seconds)}
|
|
362
|
+
</span>
|
|
363
|
+
</div>
|
|
364
|
+
)}
|
|
365
|
+
onComplete={() => {
|
|
366
|
+
endTimer()
|
|
367
|
+
setSelectedTickets({})
|
|
368
|
+
setReservedSeats([])
|
|
369
|
+
if (onCountdownFinish) {
|
|
370
|
+
onCountdownFinish()
|
|
371
|
+
}
|
|
372
|
+
}}
|
|
373
|
+
/>
|
|
374
|
+
)}
|
|
375
|
+
<TicketsSection
|
|
376
|
+
selectedTickets={selectedTickets}
|
|
377
|
+
handleTicketSelect={handleTicketSelect}
|
|
378
|
+
handleCancelReservation={(seatId: string, tireId: string) =>
|
|
379
|
+
handleCancelSeatReservtion(eventId, tireId, seatId)
|
|
380
|
+
}
|
|
381
|
+
handleGetTicketClick={handleGetTicketBtnClick}
|
|
382
|
+
isAddingToCart={isAddingToCart}
|
|
383
|
+
reservedSeats={reservedSeats}
|
|
384
|
+
ticketDeleteButtonContent={ticketDeleteButtonContent}
|
|
385
|
+
ticketTypeTierRelations={ticketTypeTierRelationsRef.current}
|
|
386
|
+
currencySymbol={symbol}
|
|
387
|
+
tableMapEnabled={Boolean(tableMapEnabled)}
|
|
388
|
+
guestCounts={guestCounts}
|
|
389
|
+
setGuestCounts={setGuestCounts}
|
|
390
|
+
/>
|
|
391
|
+
{seatMapData.seatMap && seatMapStatuses && (
|
|
392
|
+
<SeatMapComponent
|
|
393
|
+
seatMapProps={{
|
|
394
|
+
seatData: seatMapData.seatMap,
|
|
395
|
+
statuses: seatMapStatuses,
|
|
396
|
+
tierPrices: seatMapData.tierPrices,
|
|
397
|
+
seatMapType: seatMapData.seatMapType,
|
|
398
|
+
ticketTypeTierRelations: ticketTypeTierRelationsRef.current,
|
|
399
|
+
seatMapEvents: { onSeatClick },
|
|
400
|
+
isReserving,
|
|
401
|
+
predefinedSeats: seatMapData.predefinedSeats,
|
|
402
|
+
}}
|
|
403
|
+
mapContainerId={mapContainerId}
|
|
404
|
+
/>
|
|
405
|
+
)}
|
|
406
|
+
</>
|
|
407
|
+
)
|
|
408
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import _find from 'lodash/find'
|
|
2
|
+
import _forEach from 'lodash/forEach'
|
|
3
|
+
import _isEmpty from 'lodash/isEmpty'
|
|
4
|
+
import _values from 'lodash/values'
|
|
5
|
+
|
|
6
|
+
export const getTierIdBasedOnSeatId = (
|
|
7
|
+
seatId: string,
|
|
8
|
+
eventSeats: Array<EventSeat>
|
|
9
|
+
) => {
|
|
10
|
+
let tierId: number | string = ''
|
|
11
|
+
|
|
12
|
+
_forEach(eventSeats, group => {
|
|
13
|
+
_forEach(group.seats, (seatsCount, rowId) => {
|
|
14
|
+
const [row_id, seat_id] = seatId.split(':')
|
|
15
|
+
if (row_id === rowId && seat_id <= seatsCount) {
|
|
16
|
+
tierId = Number(group.tier_id)
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
return true
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return tierId
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const getButtonLabel = (count: number, tableMapEnabled: boolean) => {
|
|
27
|
+
if (!count) {
|
|
28
|
+
return tableMapEnabled ? `GET TABLES` : `GET TICKETS`
|
|
29
|
+
} else if (count === 1) {
|
|
30
|
+
return tableMapEnabled ? `GET ${count} TABLE` : `GET ${count} TICKET`
|
|
31
|
+
}
|
|
32
|
+
return tableMapEnabled ? `GET ${count} TABLES` : `GET ${count} TICKETS`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const getOwnReservationsBasedOnStatuses = (statuses: any) => {
|
|
36
|
+
const ownReservations: string[] = []
|
|
37
|
+
Object.keys(statuses).forEach((groupRowId: string) =>
|
|
38
|
+
Object.keys(statuses[groupRowId]).forEach((seatIndex: string | number) => {
|
|
39
|
+
if (statuses[groupRowId][seatIndex] === 'OR') {
|
|
40
|
+
ownReservations.push(`${groupRowId}:${seatIndex}`)
|
|
41
|
+
} else if (statuses[groupRowId][seatIndex] === 'H') {
|
|
42
|
+
statuses[groupRowId][seatIndex] = 'BLOCKED'
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
)
|
|
46
|
+
return ownReservations
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const getTicketDropdownData = (
|
|
50
|
+
reservationData: Array<SeatReservationData>,
|
|
51
|
+
tierReleations: TicketTypeTierRelations
|
|
52
|
+
) => {
|
|
53
|
+
const ticketsDropdownsData: Array<ITicketsDropdownsData> = []
|
|
54
|
+
_forEach(reservationData, reservation => {
|
|
55
|
+
if (tierReleations[reservation.tierId]) {
|
|
56
|
+
const ticketsData = _values(tierReleations[reservation.tierId])
|
|
57
|
+
ticketsDropdownsData.push({
|
|
58
|
+
seatId: reservation.seatId,
|
|
59
|
+
tierId: reservation.tierId,
|
|
60
|
+
ticketsData,
|
|
61
|
+
})
|
|
62
|
+
} else {
|
|
63
|
+
ticketsDropdownsData.push({
|
|
64
|
+
seatId: reservation.seatId,
|
|
65
|
+
tierId: reservation.tierId,
|
|
66
|
+
ticketsData: [
|
|
67
|
+
{
|
|
68
|
+
ticket_type_tier_id: reservation.tierId,
|
|
69
|
+
ticket_type_name: 'Please select Ticket Type',
|
|
70
|
+
ticket_type_price: '',
|
|
71
|
+
ticket_type_id: 'default',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
return ticketsDropdownsData
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const getAddToCartRequestData = ({
|
|
81
|
+
eventId,
|
|
82
|
+
reservations = [],
|
|
83
|
+
selectedSeats = [],
|
|
84
|
+
selectedTickets = [],
|
|
85
|
+
guestCounts = {},
|
|
86
|
+
}: any) => {
|
|
87
|
+
const hasGuests = !_isEmpty(guestCounts)
|
|
88
|
+
|
|
89
|
+
const addToCartData = {
|
|
90
|
+
attributes: {
|
|
91
|
+
alternative_view_id: null,
|
|
92
|
+
product_cart_quantity: reservations.length,
|
|
93
|
+
product_options: {},
|
|
94
|
+
product_id: eventId,
|
|
95
|
+
ticket_types: {},
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const productOptions = {} as any
|
|
100
|
+
const ticketTypes = {} as any
|
|
101
|
+
|
|
102
|
+
_forEach(reservations, (item, index) => {
|
|
103
|
+
const ticket = _find(
|
|
104
|
+
selectedSeats[item],
|
|
105
|
+
sitem => sitem.ticket_type_id === selectedTickets[item]
|
|
106
|
+
)
|
|
107
|
+
productOptions[ticket.ticket_type_option] = ticket.ticket_type_id
|
|
108
|
+
|
|
109
|
+
const ticketTypesKey = hasGuests ? index : ticket.ticket_type_id
|
|
110
|
+
const quantity = hasGuests
|
|
111
|
+
? guestCounts[item]
|
|
112
|
+
: (ticketTypes[ticket.ticket_type_id]?.quantity || 0) + 1
|
|
113
|
+
|
|
114
|
+
ticketTypes[ticketTypesKey] = {
|
|
115
|
+
quantity,
|
|
116
|
+
product_options: {
|
|
117
|
+
[ticket.ticket_type_option]: ticket.ticket_type_id,
|
|
118
|
+
ticket_price: ticket.ticket_type_price,
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
addToCartData.attributes.product_options = productOptions
|
|
124
|
+
addToCartData.attributes.ticket_types = ticketTypes
|
|
125
|
+
|
|
126
|
+
return addToCartData
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const getTierRelationsArray = (
|
|
130
|
+
data: Array<TicketTypeTierRelationsData>
|
|
131
|
+
) => {
|
|
132
|
+
const ticketTypeTireRelationsArray: Array<string | number> = []
|
|
133
|
+
_forEach(data, (item: TicketTypeTierRelationsData) => {
|
|
134
|
+
ticketTypeTireRelationsArray.push(..._values(item))
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return ticketTypeTireRelationsArray
|
|
138
|
+
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import './style.css'
|
|
2
|
+
|
|
3
|
+
import CircularProgress from '@mui/material/CircularProgress'
|
|
2
4
|
import {
|
|
3
|
-
useStripe,
|
|
4
|
-
useElements,
|
|
5
|
-
CardNumberElement,
|
|
6
|
-
CardExpiryElement,
|
|
7
5
|
CardCvcElement,
|
|
6
|
+
CardExpiryElement,
|
|
7
|
+
CardNumberElement,
|
|
8
|
+
useElements,
|
|
9
|
+
useStripe,
|
|
8
10
|
} from '@stripe/react-stripe-js'
|
|
9
11
|
import { StripeCardNumberElementOptions } from '@stripe/stripe-js'
|
|
10
|
-
import _identity from 'lodash/identity'
|
|
11
12
|
import _get from 'lodash/get'
|
|
12
|
-
import
|
|
13
|
+
import _identity from 'lodash/identity'
|
|
14
|
+
import React, { useEffect, useState } from 'react'
|
|
13
15
|
|
|
14
|
-
import './style.css'
|
|
15
16
|
import { getCurrencySymbolByCurrency } from '../../normalizers'
|
|
16
|
-
import
|
|
17
|
+
import { CheckboxField } from '../common/index'
|
|
17
18
|
|
|
18
19
|
const options: StripeCardNumberElementOptions = {
|
|
19
20
|
style: {
|
|
@@ -66,10 +67,10 @@ const CheckoutForm = ({
|
|
|
66
67
|
currency,
|
|
67
68
|
billing_info,
|
|
68
69
|
isLoading = false,
|
|
69
|
-
handleSetLoading = () => {
|
|
70
|
+
handleSetLoading = () => {},
|
|
70
71
|
conditions = [],
|
|
71
72
|
disableZipSection,
|
|
72
|
-
paymentButtonText
|
|
73
|
+
paymentButtonText,
|
|
73
74
|
}: ICheckoutForm) => {
|
|
74
75
|
const stripe = useStripe()
|
|
75
76
|
const elements = useElements()
|
|
@@ -173,9 +174,7 @@ const CheckoutForm = ({
|
|
|
173
174
|
|
|
174
175
|
useEffect(() => {
|
|
175
176
|
if (checkboxes.length) {
|
|
176
|
-
const allChecked = checkboxes.every(
|
|
177
|
-
(item: any) => item?.checked === true
|
|
178
|
-
)
|
|
177
|
+
const allChecked = checkboxes.every((item: any) => item?.checked === true)
|
|
179
178
|
setAllowSubmit(allChecked)
|
|
180
179
|
} else {
|
|
181
180
|
setAllowSubmit(true)
|
|
@@ -194,7 +193,7 @@ const CheckoutForm = ({
|
|
|
194
193
|
<div className="card_number_element">
|
|
195
194
|
<span className="card_label_text">Card number</span>
|
|
196
195
|
<CardNumberElement
|
|
197
|
-
options={{ ...options, ...stripeCardOptions
|
|
196
|
+
options={{ ...options, ...stripeCardOptions }}
|
|
198
197
|
onReady={_identity}
|
|
199
198
|
onChange={_identity}
|
|
200
199
|
onBlur={_identity}
|
|
@@ -204,7 +203,9 @@ const CheckoutForm = ({
|
|
|
204
203
|
<div className="elements">
|
|
205
204
|
<div className="expiration_element">
|
|
206
205
|
<span className="card_label_text">Expiration date</span>
|
|
207
|
-
<CardExpiryElement
|
|
206
|
+
<CardExpiryElement
|
|
207
|
+
options={{ ...options, ...stripeCardOptions }}
|
|
208
|
+
/>
|
|
208
209
|
</div>
|
|
209
210
|
<div className="cvc_element">
|
|
210
211
|
<span className="card_label_text">CVC</span>
|
|
@@ -240,13 +241,17 @@ const CheckoutForm = ({
|
|
|
240
241
|
</div>
|
|
241
242
|
))}
|
|
242
243
|
<div
|
|
243
|
-
className={`payment_button ${
|
|
244
|
+
className={`payment_button ${
|
|
245
|
+
buttonIsDiabled ? 'disabled-payment-button' : ''
|
|
246
|
+
}`}
|
|
244
247
|
>
|
|
245
248
|
<button disabled={buttonIsDiabled} type="submit">
|
|
246
249
|
{isLoading ? (
|
|
247
250
|
<CircularProgress size={26} />
|
|
248
251
|
) : (
|
|
249
|
-
`${
|
|
252
|
+
`${
|
|
253
|
+
paymentButtonText ? paymentButtonText : 'Pay'
|
|
254
|
+
} ${getCurrencySymbolByCurrency(currency)}${total}`
|
|
250
255
|
)}
|
|
251
256
|
</button>
|
|
252
257
|
</div>
|