tf-checkout-react 1.3.51 → 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.
Files changed (50) hide show
  1. package/dist/api/index.d.ts +6 -1
  2. package/dist/components/common/Loader.d.ts +1 -1
  3. package/dist/components/idVerificationContainer/constants.d.ts +2 -0
  4. package/dist/components/index.d.ts +1 -0
  5. package/dist/components/seatMapContainer/SeatMapComponent.d.ts +8 -0
  6. package/dist/components/seatMapContainer/TicketsSection.d.ts +9 -0
  7. package/dist/components/seatMapContainer/addToCart.d.ts +21 -0
  8. package/dist/components/seatMapContainer/index.d.ts +2 -0
  9. package/dist/components/seatMapContainer/utils.d.ts +14 -0
  10. package/dist/components/stripePayment/index.d.ts +2 -2
  11. package/dist/components/ticketsContainer/TicketRow.d.ts +3 -1
  12. package/dist/components/ticketsContainer/TicketsSection.d.ts +5 -1
  13. package/dist/components/ticketsContainer/index.d.ts +6 -2
  14. package/dist/index.d.ts +1 -0
  15. package/dist/tf-checkout-react.cjs.development.js +1435 -128
  16. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  17. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  18. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  19. package/dist/tf-checkout-react.esm.js +1436 -130
  20. package/dist/tf-checkout-react.esm.js.map +1 -1
  21. package/dist/tf-checkout-styles.css +1 -1
  22. package/dist/types/order-data.d.ts +3 -0
  23. package/dist/utils/createCheckoutDataBodyWithDefaultHolder.d.ts +9 -2
  24. package/package.json +12 -4
  25. package/src/.d.ts +4 -3
  26. package/src/api/index.ts +89 -6
  27. package/src/components/billing-info-container/index.tsx +111 -102
  28. package/src/components/common/Loader.tsx +6 -8
  29. package/src/components/common/dist/PhoneNumberField.js +96 -0
  30. package/src/components/confirmationContainer/index.tsx +11 -9
  31. package/src/components/idVerificationContainer/constants.ts +2 -0
  32. package/src/components/idVerificationContainer/index.tsx +54 -13
  33. package/src/components/index.ts +2 -1
  34. package/src/components/orderDetailsContainer/index.tsx +54 -23
  35. package/src/components/paymentContainer/index.tsx +167 -33
  36. package/src/components/seatMapContainer/SeatMapComponent.tsx +73 -0
  37. package/src/components/seatMapContainer/TicketsSection.tsx +254 -0
  38. package/src/components/seatMapContainer/addToCart.ts +82 -0
  39. package/src/components/seatMapContainer/index.tsx +408 -0
  40. package/src/components/seatMapContainer/utils.ts +138 -0
  41. package/src/components/stripePayment/index.tsx +23 -18
  42. package/src/components/ticketsContainer/TicketRow.tsx +28 -13
  43. package/src/components/ticketsContainer/TicketsSection.tsx +85 -2
  44. package/src/components/ticketsContainer/index.tsx +57 -12
  45. package/src/components/ticketsContainer/style.css +0 -3
  46. package/src/hooks/usePixel.ts +35 -1
  47. package/src/index.ts +2 -1
  48. package/src/types/order-data.ts +3 -0
  49. package/src/types/seatMap.d.ts +154 -0
  50. package/src/utils/createCheckoutDataBodyWithDefaultHolder.ts +6 -2
@@ -56,7 +56,6 @@ const getStripePromise = (reviewData: any) => {
56
56
 
57
57
  return loadStripe(stripePublishableKey, options)
58
58
  }
59
-
60
59
  export interface IPaymentPage {
61
60
  paymentFields: IPaymentField[];
62
61
  handlePayment: any;
@@ -83,14 +82,18 @@ export interface IPaymentPage {
83
82
  }
84
83
 
85
84
  const initialOrderValues: IOrderData = {
85
+ id: '',
86
86
  product_name: '',
87
87
  ticketType: '',
88
88
  quantity: '',
89
89
  price: '',
90
90
  total: '',
91
91
  currency: '',
92
+ guest_count: '',
93
+ pay_now: '',
92
94
  add_ons: [] as IAddOn[],
93
95
  }
96
+
94
97
  const initialReviewValues = {
95
98
  order_details: {
96
99
  order_hash: '',
@@ -138,7 +141,8 @@ export const PaymentContainer = ({
138
141
  const eventId =
139
142
  getQueryVariable('event_id') || _get(reviewData, 'cart[0].product_id') || ''
140
143
  const { hash, total } = checkoutData
141
- const isFreeTickets = !Number(total) && !Number(orderData.total)
144
+ const isFreeTickets =
145
+ (!Number(total) && !Number(orderData.total)) || !Number(orderData.pay_now)
142
146
 
143
147
  const pageUrl = isBrowser ? window.location.href.split('?')[0] : ''
144
148
  usePixel(eventId, { page: 'review', pageUrl })
@@ -154,7 +158,18 @@ export const PaymentContainer = ({
154
158
  const {
155
159
  tickets: [ticket],
156
160
  } = order_details
161
+
162
+ const orderDataArray = _map(order_details.tickets, item => ({
163
+ product_name: cart[0]?.product_name,
164
+ ticketType: item?.name,
165
+ quantity: item?.guest_count,
166
+ price: item?.price,
167
+ id: item.id,
168
+ count: item?.quantity,
169
+ }))
170
+
157
171
  const orderData = {
172
+ id: order_details?.id,
158
173
  product_name: cart[0]?.product_name,
159
174
  ticketType: ticket?.name,
160
175
  quantity: ticket?.quantity,
@@ -162,6 +177,10 @@ export const PaymentContainer = ({
162
177
  total: order_details?.total,
163
178
  currency: order_details?.currency,
164
179
  add_ons: order_details?.add_ons || [],
180
+ pay_now: order_details?.pay_now || '',
181
+ guest_count: order_details?.guest_count || null,
182
+ debt: order_details?.debt || null,
183
+ tableTypes: orderDataArray,
165
184
  }
166
185
  setOrderData(orderData)
167
186
  onGetPaymentDataSuccess(response.data)
@@ -213,6 +232,22 @@ export const PaymentContainer = ({
213
232
  if (paymentSuccessResponse.status === 200) {
214
233
  handlePayment(paymentSuccessResponse)
215
234
  setPaymentIsLoading(false)
235
+
236
+ // clear seat-map related data from localStorage
237
+ localStorage.removeItem('reservationData')
238
+ localStorage.removeItem(`reservationStart-${eventId}`)
239
+ localStorage.removeItem('ownReservations')
240
+ localStorage.removeItem('tierId')
241
+
242
+ const isWindowDefined = typeof window !== "undefined"
243
+ if (isWindowDefined) {
244
+ (window as any)?.dataLayer.push({
245
+ 'event': 'Purchase',
246
+ 'orderValue': orderData.total,
247
+ 'orderCurrency': orderData.currency,
248
+ 'orderId': orderData.id
249
+ })
250
+ }
216
251
  }
217
252
  } catch (e) {
218
253
  setError(_get(e, 'response.data.message'))
@@ -222,7 +257,47 @@ export const PaymentContainer = ({
222
257
  }
223
258
 
224
259
  const themeMui = createTheme(themeOptions)
225
-
260
+ const hasTableTypes = Boolean(Number(orderData.guest_count))
261
+ const paymentFieldsData = hasTableTypes
262
+ ? [
263
+ {
264
+ label: 'Event',
265
+ id: 'product_name',
266
+ },
267
+ {
268
+ label: '',
269
+ id: 'tableTypes',
270
+ },
271
+ {
272
+ label: 'Total (incl. fees, card processing and taxes)',
273
+ id: 'total',
274
+ normalizer: (value: string, currency: any) =>
275
+ currencyNormalizerCreator(
276
+ createFixedFloatNormalizer(2)(parseFloat(value)),
277
+ currency
278
+ ),
279
+ },
280
+ {
281
+ label: 'Pay Now',
282
+ id: 'pay_now',
283
+ normalizer: (value: string, currency: any) =>
284
+ currencyNormalizerCreator(
285
+ createFixedFloatNormalizer(2)(parseFloat(value)),
286
+ currency
287
+ ),
288
+ },
289
+ {
290
+ label: 'Pay On Check-in',
291
+ id: 'debt',
292
+ normalizer: (value: string, currency: any) =>
293
+ currencyNormalizerCreator(
294
+ createFixedFloatNormalizer(2)(parseFloat(value)),
295
+ currency
296
+ ),
297
+ },
298
+ ]
299
+ : paymentFields
300
+ const isTable = orderData?.guest_count
226
301
  return (
227
302
  <ThemeProvider theme={themeMui}>
228
303
  <div className="payment_page">
@@ -241,10 +316,15 @@ export const PaymentContainer = ({
241
316
  {paymentDataIsLoading && <Loader />}
242
317
  {!paymentDataIsLoading && (
243
318
  <Container maxWidth="md">
244
- {showFormTitle && <h1>{formTitle}</h1>}
319
+ {showFormTitle && (
320
+ <h1>{isTable ? 'Get Your Tables' : formTitle}</h1>
321
+ )}
245
322
  <div className="order_info_text">{orderInfoLabel}</div>
246
- <div className="order_info_section">
247
- {_map(paymentFields, field => {
323
+ <div
324
+ className="order_info_section"
325
+ style={{ display: hasTableTypes ? 'block' : 'grid' }}
326
+ >
327
+ {_map(paymentFieldsData, field => {
248
328
  const {
249
329
  id,
250
330
  label,
@@ -253,39 +333,89 @@ export const PaymentContainer = ({
253
333
  } = field
254
334
  const { currency } = orderData
255
335
  const value = orderData[id as keyof IOrderData]
336
+ let component = null
256
337
 
257
338
  if (field.id === 'add_ons' && _isEmpty(value)) {
258
339
  return false
259
340
  }
260
341
 
261
- return (
262
- <div key={id} className="order_info_block">
263
- <div className="order_info_title">{label}</div>
264
- <div className={`${className} order_info_text`}>
265
- {typeof value === 'string'
266
- ? normalizer(value, currency)
267
- : _map(value, item => (
268
- <div key={item.id} className="add-on-container">
269
- <span>{item.quantity}</span>
270
- <span className="add-on-x">{' x '}</span>
271
- <span>
272
- {item.groupName ? item.groupName + ' - ' : ''}
273
- </span>
274
- <span>{item.name}</span>
275
- <span>{' - '}</span>
276
- <span>
277
- {currencyNormalizerCreator(
278
- createFixedFloatNormalizer(2)(
279
- parseFloat(item.price)
280
- ),
281
- currency
282
- )}
283
- </span>
284
- <span className="add-on-each">{' each'}</span>
342
+ if (field.id === 'tableTypes') {
343
+ const valueArray = value as Array<any>
344
+
345
+ component = (
346
+ <div
347
+ key={id}
348
+ className="order_info_block"
349
+ style={{
350
+ display: 'flex',
351
+ flexDirection: 'column',
352
+ }}
353
+ >
354
+ {_map(valueArray, tableTypeItem => (
355
+ <div
356
+ key={tableTypeItem.id}
357
+ style={{
358
+ display: 'grid',
359
+ gridTemplateColumns: '33% 33% 33%',
360
+ gridColumnGap: '10%',
361
+ }}
362
+ >
363
+ <div className="order_info_block">
364
+ <div className="order_info_title">Table Type</div>
365
+ <div className={`${className} order_info_text`}>
366
+ {tableTypeItem.ticketType}
367
+ </div>
368
+ </div>
369
+ <div className="order_info_block">
370
+ <div className="order_info_title">
371
+ Number of Tables
372
+ </div>
373
+ <div className={`${className} order_info_text`}>
374
+ {tableTypeItem.count}
375
+ </div>
376
+ </div>
377
+ <div className="order_info_block">
378
+ <div className="order_info_title">Guest Count</div>
379
+ <div className={`${className} order_info_text`}>
380
+ {tableTypeItem.quantity}
285
381
  </div>
286
- ))}
382
+ </div>
383
+ </div>
384
+ ))}
385
+ </div>
386
+ )
387
+ }
388
+
389
+ return (
390
+ component || (
391
+ <div key={id} className="order_info_block">
392
+ <div className="order_info_title">{label}</div>
393
+ <div className={`${className} order_info_text`}>
394
+ {typeof value === 'string'
395
+ ? normalizer(value, currency)
396
+ : _map(value, item => (
397
+ <div key={item.id} className="add-on-container">
398
+ <span>{item.quantity}</span>
399
+ <span className="add-on-x">{' x '}</span>
400
+ <span>
401
+ {item.groupName ? item.groupName + ' - ' : ''}
402
+ </span>
403
+ <span>{item.name}</span>
404
+ <span>{' - '}</span>
405
+ <span>
406
+ {currencyNormalizerCreator(
407
+ createFixedFloatNormalizer(2)(
408
+ parseFloat(item.price)
409
+ ),
410
+ currency
411
+ )}
412
+ </span>
413
+ <span className="add-on-each">{' each'}</span>
414
+ </div>
415
+ ))}
416
+ </div>
287
417
  </div>
288
- </div>
418
+ )
289
419
  )
290
420
  })}
291
421
  </div>
@@ -354,7 +484,11 @@ export const PaymentContainer = ({
354
484
  reviewData,
355
485
  'payment_method.stripe_client_secret'
356
486
  )}
357
- total={orderData.total}
487
+ total={
488
+ orderData.guest_count
489
+ ? orderData.pay_now
490
+ : orderData.total
491
+ }
358
492
  onSubmit={handlePaymentMiddleWare}
359
493
  error={error}
360
494
  currency={orderData.currency}
@@ -0,0 +1,73 @@
1
+ import 'tf-seat-map-view/dist/index.css'
2
+
3
+ import React, { useEffect } from 'react'
4
+ import ReactDom from 'react-dom'
5
+ import SeatMapView from 'tf-seat-map-view'
6
+
7
+ import { getTierRelationsArray } from './utils'
8
+
9
+ const CONTAINER_DEFAULT_ID = 'seat_map_default_container'
10
+
11
+ // Temp solution
12
+ declare global {
13
+ interface Window {
14
+ tierPrices: any;
15
+ }
16
+ }
17
+
18
+ export const SeatMapComponent = (props: ISeatMapContainerProps) => {
19
+ const { seatMapProps, mapContainerId } = props
20
+ const {
21
+ seatData,
22
+ statuses,
23
+ seatMapType = null,
24
+ seatMapEvents = {},
25
+ ticketTypeTierRelations = {},
26
+ tierPrices,
27
+ isReserving,
28
+ predefinedSeats,
29
+ } = seatMapProps
30
+
31
+ useEffect(() => {
32
+ const parentElement = document.getElementById(
33
+ mapContainerId || CONTAINER_DEFAULT_ID
34
+ )
35
+
36
+ // Temp solution
37
+ window.tierPrices = tierPrices
38
+
39
+ if (Boolean(parentElement)) {
40
+ const mapComponent = (
41
+ <SeatMapView
42
+ disabled={isReserving}
43
+ loading={isReserving}
44
+ events={seatMapEvents}
45
+ isSelectionOn={false}
46
+ seatData={seatData}
47
+ statuses={statuses}
48
+ ticketTypeTireRelationsArray={getTierRelationsArray(
49
+ ticketTypeTierRelations
50
+ )}
51
+ width={Math.min(parentElement?.clientWidth || 800, 800)}
52
+ height={Math.min(parentElement?.clientWidth || 800, 800)}
53
+ isBlockMap={seatMapType === 'block'}
54
+ isTableMap={seatMapType === 'table'}
55
+ predefinedSeats={predefinedSeats}
56
+ />
57
+ )
58
+
59
+ ReactDom.render(mapComponent, parentElement)
60
+ }
61
+ }, [
62
+ isReserving,
63
+ mapContainerId,
64
+ seatData,
65
+ seatMapEvents,
66
+ seatMapType,
67
+ tierPrices,
68
+ statuses,
69
+ ticketTypeTierRelations,
70
+ ])
71
+
72
+ return <div id={CONTAINER_DEFAULT_ID} />
73
+ }
@@ -0,0 +1,254 @@
1
+ import { CSSProperties } from '@emotion/serialize'
2
+ import { createTheme, Select, SelectChangeEvent,ThemeOptions } from '@mui/material'
3
+ import CircularProgress from '@mui/material/CircularProgress'
4
+ import FormControl from '@mui/material/FormControl'
5
+ import InputLabel from '@mui/material/InputLabel'
6
+ import MenuItem from '@mui/material/MenuItem'
7
+ import { ThemeProvider } from '@mui/private-theming'
8
+ import _find from 'lodash/find'
9
+ import _identity from 'lodash/identity'
10
+ import _isEmpty from 'lodash/isEmpty'
11
+ import _keys from 'lodash/keys'
12
+ import _map from 'lodash/map'
13
+ import _some from 'lodash/some'
14
+ import React from 'react'
15
+ import { Button } from 'react-bootstrap'
16
+
17
+ import { createFixedFloatNormalizer } from '../../normalizers'
18
+ import { getButtonLabel, getTicketDropdownData } from './utils'
19
+
20
+ export const TicketsSection = (
21
+ props: ITicketsSectionProps & {
22
+ themeOptions?: ThemeOptions & {
23
+ input?: CSSProperties;
24
+ checkbox?: CSSProperties;
25
+ };
26
+ }
27
+ ) => {
28
+ const {
29
+ ticketTypeTierRelations,
30
+ reservedSeats,
31
+ theme = 'light',
32
+ getTicketsBtnLabel,
33
+ contentStyle = {},
34
+ isButtonScrollable = false,
35
+ themeOptions,
36
+ handleGetTicketClick,
37
+ handleCancelReservation,
38
+ ticketDeleteButtonContent = 'Delete',
39
+ selectedTickets,
40
+ handleTicketSelect,
41
+ currencySymbol,
42
+ tableMapEnabled = false,
43
+ guestCounts,
44
+ setGuestCounts,
45
+ isAddingToCart,
46
+ } = props
47
+
48
+ const bookButtonIsDisabled =
49
+ _some(selectedTickets, item => !item) ||
50
+ _isEmpty(reservedSeats) ||
51
+ reservedSeats.length !== _keys(selectedTickets).length
52
+ const themeMui = createTheme(themeOptions)
53
+
54
+ const ticketsDropdownsData = getTicketDropdownData(
55
+ reservedSeats,
56
+ ticketTypeTierRelations
57
+ )
58
+ const handleTicketChange = (event: SelectChangeEvent<string>, seatId: string) => {
59
+ const {
60
+ target: { value },
61
+ } = event
62
+
63
+ if (value !== 'default') {
64
+ handleTicketSelect(value, seatId)
65
+ }
66
+ }
67
+
68
+ return (
69
+ <ThemeProvider theme={themeMui}>
70
+ <div className={`get-tickets-page ${theme}`} style={contentStyle}>
71
+ <div className="tickets-section">
72
+ {_map(selectedTickets, (ticketItem: string, key: string) => {
73
+ const dropdownData =
74
+ _find(ticketsDropdownsData, item => item.seatId === key) ||
75
+ ({} as ITicketsDropdownsData)
76
+
77
+ const selectedTicketData = _find(
78
+ dropdownData.ticketsData,
79
+ ticket => ticket.ticket_type_id === ticketItem
80
+ ) as TicketTypeTierRelationsData
81
+
82
+ // guest count dropdown options
83
+ const startNum = Number(
84
+ selectedTicketData?.ticket_type_min_number_of_guests
85
+ )
86
+ const endNum = Number(
87
+ selectedTicketData?.ticket_type_max_number_of_guests
88
+ )
89
+ const numLength = endNum - startNum + 1
90
+ const showGuestCountDropdown = Boolean(startNum && endNum)
91
+
92
+ // prices
93
+ const guestPrice =
94
+ (guestCounts[dropdownData.seatId] - startNum) *
95
+ Number(selectedTicketData?.guest_price)
96
+
97
+ const finalPrice = createFixedFloatNormalizer(2)(
98
+ selectedTicketData?.ticket_type_price + guestPrice
99
+ )
100
+
101
+ return (
102
+ <div className="ticket" key={key}>
103
+ <div className="ticketsDropdowns">
104
+ <Select
105
+ value={ticketItem || 'default'}
106
+ onChange={event =>
107
+ handleTicketChange(event, dropdownData.seatId)
108
+ }
109
+ inputProps={{ 'aria-label': 'Without label' }}
110
+ MenuProps={{
111
+ PaperProps: {
112
+ sx: { maxHeight: 150 },
113
+ className: 'get-tickets-paper',
114
+ },
115
+ }}
116
+ displayEmpty
117
+ sx={{ borderRadius: 0 }}
118
+ >
119
+ <MenuItem value={'default'}>
120
+ {`Please select ${
121
+ tableMapEnabled ? 'Table Type' : 'Ticket Type'
122
+ }`}
123
+ </MenuItem>
124
+ {_map(dropdownData.ticketsData, (option, index) => {
125
+ if (option.ticket_type_id !== 'default') {
126
+ return (
127
+ <MenuItem value={option.ticket_type_id} key={index}>
128
+ {option.ticket_type_name}
129
+ </MenuItem>
130
+ )
131
+ }
132
+ return null
133
+ })}
134
+ </Select>
135
+ <Button
136
+ className="ticket-delete"
137
+ onClick={() => {
138
+ handleCancelReservation(
139
+ dropdownData.seatId,
140
+ dropdownData.tierId
141
+ )
142
+ }}
143
+ >
144
+ {ticketDeleteButtonContent}
145
+ </Button>
146
+ </div>
147
+ {selectedTicketData && (
148
+ <div style={{ display: 'flex', flexDirection: 'row' }}>
149
+ <div
150
+ style={{
151
+ width: '100%',
152
+ display: 'flex',
153
+ flexDirection: 'column',
154
+ justifyContent: 'center',
155
+ }}
156
+ >
157
+ <div className="ticketPrice">
158
+ Price:
159
+ <span className="ticketPrice-value">
160
+ {`${currencySymbol} ${finalPrice}`}
161
+ </span>
162
+ </div>
163
+ {!_isEmpty(selectedTicketData.ticket_type_deposit) && (
164
+ <div className="ticketDeposit">
165
+ Deposit:
166
+ <span className="ticketPrice-value">
167
+ {` ${selectedTicketData?.ticket_type_deposit}%`}
168
+ </span>
169
+ </div>
170
+ )}
171
+ </div>
172
+ {showGuestCountDropdown && (
173
+ <div
174
+ style={{
175
+ width: '100%',
176
+ display: 'flex',
177
+ justifyContent: 'end',
178
+ marginRight: 16,
179
+ }}
180
+ >
181
+ <FormControl
182
+ variant="outlined"
183
+ sx={{ m: 1, minWidth: 80 }}
184
+ >
185
+ <InputLabel
186
+ id="demo-simple-select-standard-label"
187
+ shrink
188
+ >
189
+ GUESTS
190
+ </InputLabel>
191
+ <Select
192
+ label="GUESTS"
193
+ labelId="demo-simple-select-standard-label"
194
+ value={guestCounts[dropdownData.seatId] || startNum}
195
+ onChange={event => {
196
+ setGuestCounts({
197
+ ...guestCounts,
198
+ [dropdownData.seatId]: Number(
199
+ event.target.value
200
+ ),
201
+ })
202
+ }}
203
+ inputProps={{ 'aria-label': 'Without label' }}
204
+ MenuProps={{
205
+ PaperProps: {
206
+ sx: { maxHeight: 150 },
207
+ className: 'get-tickets-paper',
208
+ },
209
+ }}
210
+ displayEmpty
211
+ sx={{ borderRadius: 0 }}
212
+ >
213
+ {_map(
214
+ Array.from(
215
+ { length: numLength },
216
+ (_, i) => startNum + i
217
+ ),
218
+ (option, index) => (
219
+ <MenuItem value={option} key={index}>
220
+ {option}
221
+ </MenuItem>
222
+ )
223
+ )}
224
+ </Select>
225
+ </FormControl>
226
+ </div>
227
+ )}
228
+ </div>
229
+ )}
230
+ </div>
231
+ )
232
+ })}
233
+ </div>
234
+ <div>
235
+ <Button
236
+ className={`book-button
237
+ ${bookButtonIsDisabled ? 'disabled' : ''}
238
+ ${isButtonScrollable ? 'is-scrollable' : ''}
239
+ `}
240
+ onClick={!bookButtonIsDisabled ? handleGetTicketClick : _identity}
241
+ disabled={isAddingToCart}
242
+ >
243
+ {isAddingToCart ? (
244
+ <CircularProgress size={20} style={{ marginLeft: 10 }} />
245
+ ) : (
246
+ getTicketsBtnLabel ||
247
+ getButtonLabel(reservedSeats.length, tableMapEnabled)
248
+ )}
249
+ </Button>
250
+ </div>
251
+ </div>
252
+ </ThemeProvider>
253
+ )
254
+ }
@@ -0,0 +1,82 @@
1
+ import _get from 'lodash/get'
2
+
3
+ import { addToCart, getCheckoutPageConfigs, postOnCheckout } from '../../api'
4
+ import { createCheckoutDataBodyWithDefaultHolder } from '../../utils'
5
+
6
+ interface IAddToCartFuncProps {
7
+ eventId: string | number;
8
+ data: any;
9
+ ticketQuantity: number;
10
+ enableBillingInfoAutoCreate?: boolean;
11
+ }
12
+
13
+ export const addToCartFunc = async ({
14
+ eventId,
15
+ data,
16
+ ticketQuantity,
17
+ enableBillingInfoAutoCreate = true,
18
+ }: IAddToCartFuncProps) => {
19
+ const isWindowDefined = typeof window !== 'undefined'
20
+
21
+ const result = await addToCart(eventId, data)
22
+ const pageConfigsDataResponse = await getCheckoutPageConfigs()
23
+
24
+ if (result.status === 200 && pageConfigsDataResponse.status === 200) {
25
+ const pageConfigsData =
26
+ _get(pageConfigsDataResponse, 'data.attributes') || {}
27
+
28
+ const {
29
+ skip_billing_page: skipBillingPage = false,
30
+ names_required: nameIsRequired = false,
31
+ age_required: ageIsRequired = false,
32
+ phone_required: phoneIsRequired = false,
33
+ hide_phone_field: hidePhoneField = false,
34
+ has_add_on: hasAddOn = false,
35
+ free_ticket: freeTicket = false,
36
+ collect_optional_wallet_address: collectOptionalWalletAddress = false,
37
+ collect_mandatory_wallet_address: collectMandatoryWalletAddress = false,
38
+ } = pageConfigsData
39
+
40
+ let hash = ''
41
+ let total = ''
42
+
43
+ isWindowDefined && window.localStorage.removeItem('add_ons')
44
+
45
+ if (skipBillingPage && !hasAddOn) {
46
+ // Get user data for checkout data
47
+ const userData =
48
+ isWindowDefined && window.localStorage.getItem('user_data')
49
+ ? JSON.parse(window.localStorage.getItem('user_data') || '')
50
+ : {}
51
+
52
+ const checkoutBody = createCheckoutDataBodyWithDefaultHolder(
53
+ ticketQuantity,
54
+ userData
55
+ )
56
+
57
+ const checkoutResult = enableBillingInfoAutoCreate
58
+ ? await postOnCheckout(checkoutBody, undefined, freeTicket)
59
+ : null
60
+
61
+ hash = _get(checkoutResult, 'data.data.attributes.hash') || ''
62
+ total = _get(checkoutResult, 'data.data.attributes.total') || ''
63
+ }
64
+
65
+ return {
66
+ skip_billing_page: skipBillingPage,
67
+ names_required: nameIsRequired,
68
+ phone_required: phoneIsRequired,
69
+ age_required: ageIsRequired,
70
+ hide_phone_field: hidePhoneField,
71
+ free_ticket: freeTicket,
72
+ collect_optional_wallet_address: collectOptionalWalletAddress,
73
+ collect_mandatory_wallet_address: collectMandatoryWalletAddress,
74
+ event_id: String(eventId),
75
+ hash,
76
+ total,
77
+ hasAddOn,
78
+ }
79
+ }
80
+
81
+ return null
82
+ }