tf-checkout-react 1.0.45 → 1.0.49

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 (41) hide show
  1. package/dist/api/index.d.ts +2 -0
  2. package/dist/components/billing-info-container/index.d.ts +1 -1
  3. package/dist/components/billing-info-container/utils.d.ts +1 -1
  4. package/dist/components/common/CheckboxField.d.ts +3 -3
  5. package/dist/components/common/CustomField.d.ts +2 -1
  6. package/dist/components/paymentContainer/index.d.ts +1 -1
  7. package/dist/components/stripePayment/index.d.ts +2 -1
  8. package/dist/components/ticketsContainer/TicketRow.d.ts +10 -0
  9. package/dist/components/ticketsContainer/TicketsSection.d.ts +10 -0
  10. package/dist/components/ticketsContainer/index.d.ts +3 -1
  11. package/dist/components/ticketsContainer/utils.d.ts +4 -0
  12. package/dist/components/waitingList/index.d.ts +7 -0
  13. package/dist/tf-checkout-react.cjs.development.css +4 -3
  14. package/dist/tf-checkout-react.cjs.development.js +486 -184
  15. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  16. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  17. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  18. package/dist/tf-checkout-react.esm.js +494 -189
  19. package/dist/tf-checkout-react.esm.js.map +1 -1
  20. package/dist/types/billing-info-data.d.ts +2 -2
  21. package/dist/utils/getQueryVariable.d.ts +1 -0
  22. package/dist/validators/index.d.ts +2 -1
  23. package/package.json +2 -1
  24. package/src/api/index.ts +5 -1
  25. package/src/components/billing-info-container/index.tsx +140 -133
  26. package/src/components/billing-info-container/utils.ts +3 -2
  27. package/src/components/common/CheckboxField.tsx +9 -3
  28. package/src/components/common/CustomField.tsx +17 -7
  29. package/src/components/paymentContainer/index.tsx +31 -3
  30. package/src/components/paymentContainer/style.css +8 -0
  31. package/src/components/stripePayment/index.tsx +48 -19
  32. package/src/components/stripePayment/style.css +6 -0
  33. package/src/components/ticketsContainer/TicketRow.tsx +86 -0
  34. package/src/components/ticketsContainer/TicketsSection.tsx +82 -0
  35. package/src/components/ticketsContainer/index.tsx +84 -208
  36. package/src/components/ticketsContainer/utils.ts +11 -0
  37. package/src/components/waitingList/index.tsx +172 -0
  38. package/src/components/waitingList/style.css +18 -0
  39. package/src/types/billing-info-data.ts +2 -2
  40. package/src/utils/getQueryVariable.ts +13 -0
  41. package/src/validators/index.ts +9 -3
@@ -9,6 +9,7 @@ import {
9
9
  import { StripeCardNumberElementOptions } from '@stripe/stripe-js'
10
10
  import _identity from 'lodash/identity'
11
11
  import _get from 'lodash/get'
12
+ import { CheckboxField } from '../common/CheckboxField'
12
13
 
13
14
  import './style.css'
14
15
  import { getCurrencySymbolByCurrency } from '../../normalizers'
@@ -17,6 +18,7 @@ import CircularProgress from '@mui/material/CircularProgress'
17
18
  const options: StripeCardNumberElementOptions = {
18
19
  style: {
19
20
  base: {
21
+ backgroundColor:'#232323',
20
22
  fontSize: '18px',
21
23
  color: '#ffffff',
22
24
  letterSpacing: '1px',
@@ -42,13 +44,14 @@ export interface ICheckoutForm {
42
44
  billing_info: { [key: string]: any };
43
45
  isLoading: any;
44
46
  handleSetLoading: (loading: any) => void;
47
+ conditions: any;
45
48
  }
46
49
 
47
50
  interface AddressTypes {
48
- city: string,
49
- line1: string,
50
- state: string,
51
- postal_code: string,
51
+ city: string;
52
+ line1: string;
53
+ state: string;
54
+ postal_code: string;
52
55
  }
53
56
 
54
57
  const CheckoutForm = ({
@@ -60,7 +63,8 @@ const CheckoutForm = ({
60
63
  currency,
61
64
  billing_info,
62
65
  isLoading = false,
63
- handleSetLoading = () => {}
66
+ handleSetLoading = () => {},
67
+ conditions = [],
64
68
  }: ICheckoutForm) => {
65
69
  const stripe = useStripe()
66
70
  const elements = useElements()
@@ -71,9 +75,9 @@ const CheckoutForm = ({
71
75
  handleSetLoading(true)
72
76
  try {
73
77
  event.preventDefault()
74
-
75
- if(!postalCode) {
76
- setStripeError("Please enter your zip code.")
78
+
79
+ if (!postalCode) {
80
+ setStripeError('Please enter your zip code.')
77
81
  handleSetLoading(false)
78
82
  return
79
83
  }
@@ -84,7 +88,7 @@ const CheckoutForm = ({
84
88
  handleSetLoading(false)
85
89
  return
86
90
  }
87
-
91
+
88
92
  const card = elements.getElement(CardNumberElement)
89
93
  const address: AddressTypes = {
90
94
  city: billing_info.city,
@@ -100,7 +104,7 @@ const CheckoutForm = ({
100
104
  address,
101
105
  },
102
106
  })
103
-
107
+
104
108
  if (paymentMethodReq.error) {
105
109
  setStripeError(paymentMethodReq.error.message || null)
106
110
  handleSetLoading(false)
@@ -108,7 +112,7 @@ const CheckoutForm = ({
108
112
  }
109
113
 
110
114
  const { error } = await stripe.confirmCardPayment(stripe_client_secret, {
111
- payment_method: paymentMethodReq.paymentMethod.id
115
+ payment_method: paymentMethodReq.paymentMethod.id,
112
116
  })
113
117
 
114
118
  if (error) {
@@ -116,26 +120,29 @@ const CheckoutForm = ({
116
120
  handleSetLoading(false)
117
121
  return
118
122
  }
119
-
120
- onSubmit(null)
121
123
 
122
- } catch(e) {
124
+ onSubmit(null)
125
+ } catch (e) {
123
126
  onSubmit(e)
124
127
  }
125
128
  }
126
129
 
127
130
  const onChangePostalCode = (e: any) => {
128
131
  setPostalCode(e.target.value)
129
- }
132
+ }
130
133
 
131
134
  useEffect(() => {
132
135
  if (typeof window !== 'undefined') {
133
- const userData = JSON.parse(window.localStorage.getItem('user_data') || '')
136
+ const userData = JSON.parse(
137
+ window.localStorage.getItem('user_data') || ''
138
+ )
134
139
  const zipCode = _get(userData, 'zip', '')
135
140
  zipCode && setPostalCode(zipCode)
136
141
  }
137
142
  }, [])
138
143
 
144
+ const buttonIsDiabled = !stripe || !!error || isLoading
145
+
139
146
  return (
140
147
  <div className="stripe_payment_container">
141
148
  {!!stripeError && (
@@ -171,9 +178,31 @@ const CheckoutForm = ({
171
178
  />
172
179
  </label>
173
180
  </div>
174
- <div className="payment_button">
175
- <button disabled={!stripe || !!error || isLoading} type="submit">
176
- {isLoading ? <CircularProgress /> : `Pay ${getCurrencySymbolByCurrency(currency)}${total}`}
181
+ {conditions?.map((checkbox: any) => (
182
+ <div
183
+ className={'billing-info-container__singleField'}
184
+ key={checkbox.id}
185
+ >
186
+ <div className="conditions-block">
187
+ <CheckboxField
188
+ name={checkbox.id}
189
+ label={checkbox.text}
190
+ required={true}
191
+ />
192
+ </div>
193
+ </div>
194
+ ))}
195
+ <div
196
+ className={`payment_button ${
197
+ buttonIsDiabled ? 'disabled-payment-button' : ''
198
+ }`}
199
+ >
200
+ <button disabled={buttonIsDiabled} type="submit">
201
+ {isLoading ? (
202
+ <CircularProgress />
203
+ ) : (
204
+ `Pay ${getCurrencySymbolByCurrency(currency)}${total}`
205
+ )}
177
206
  </button>
178
207
  </div>
179
208
  </form>
@@ -30,6 +30,12 @@
30
30
  opacity: 0.7;
31
31
  }
32
32
 
33
+ .disabled-payment-button button{
34
+ user-select: none;
35
+ pointer-events:none;
36
+ opacity: 0.3;
37
+ }
38
+
33
39
  .checkout_error_block {
34
40
  color: #e53935;
35
41
  padding: 15px 0;
@@ -0,0 +1,86 @@
1
+ import React from 'react'
2
+ import './style.css'
3
+ import _has from 'lodash/has'
4
+ import _get from 'lodash/get'
5
+ import Box from '@mui/material/Box'
6
+ import FormControl from '@mui/material/FormControl'
7
+ import MenuItem from '@mui/material/MenuItem'
8
+ import Select from '@mui/material/Select'
9
+
10
+ import { getTicketSelectOptions } from './utils'
11
+
12
+ interface ITicketRowProps {
13
+ ticketTier: any;
14
+ prevTicketTier: any;
15
+ selectedTickets: any;
16
+ handleTicketSelect: any;
17
+ }
18
+
19
+ export const TicketRow = ({
20
+ ticketTier,
21
+ prevTicketTier,
22
+ selectedTickets,
23
+ handleTicketSelect,
24
+ }: ITicketRowProps) => {
25
+ const soldOutMessage = ticketTier.soldOutMessage
26
+ ? `${ticketTier.soldOutMessage}`.toUpperCase()
27
+ : 'SOLD OUT'
28
+ const isSalesClosed =
29
+ !ticketTier.salesStarted ||
30
+ ticketTier.salesEnded ||
31
+ !_has(ticketTier, 'maxQuantity') ||
32
+ ticketTier.maxQuantity === 0
33
+ const options = getTicketSelectOptions(
34
+ ticketTier.maxQuantity,
35
+ ticketTier.minQuantity,
36
+ ticketTier.multiplier
37
+ )
38
+
39
+ const onSaleContent = isSalesClosed ? null : (
40
+ <div className="get-tickets">
41
+ <Box className="get-tickets__selectbox">
42
+ <FormControl fullWidth>
43
+ <Select
44
+ value={
45
+ selectedTickets[ticketTier.id]
46
+ ? selectedTickets[ticketTier.id]
47
+ : 0
48
+ }
49
+ onChange={handleTicketSelect}
50
+ displayEmpty
51
+ inputProps={{ 'aria-label': 'Without label' }}
52
+ MenuProps={{
53
+ PaperProps: {
54
+ sx: { maxHeight: 150 },
55
+ className: 'get-tickets-paper',
56
+ },
57
+ }}
58
+ >
59
+ {options.map((option, index) => (
60
+ <MenuItem key={index} value={option.value}>
61
+ {option.value}
62
+ </MenuItem>
63
+ ))}
64
+ </Select>
65
+ </FormControl>
66
+ </Box>
67
+ </div>
68
+ )
69
+
70
+ let returnValue: any = ''
71
+
72
+ if (ticketTier.sold_out || !ticketTier.displayTicket || ticketTier.soldOut) {
73
+ returnValue = soldOutMessage
74
+ }
75
+ if (!+ticketTier.cost && !+ticketTier.price) {
76
+ returnValue = 'FREE'
77
+ }
78
+ if (ticketTier.displayTicket) {
79
+ returnValue = onSaleContent
80
+ }
81
+ if (_get(prevTicketTier, 'in_stock')) {
82
+ returnValue = 'SOON'
83
+ }
84
+
85
+ return <>{returnValue} </>
86
+ }
@@ -0,0 +1,82 @@
1
+ import React from 'react'
2
+ import './style.css'
3
+
4
+ import _sortBy from 'lodash/sortBy'
5
+ import { TicketRow } from './TicketRow'
6
+
7
+ interface ITicketsSectionProps {
8
+ ticketsList: any;
9
+ selectedTickets: any;
10
+ handleTicketSelect: any;
11
+ promoCodeIsApplied: boolean;
12
+ }
13
+
14
+ export const TicketsSection = ({
15
+ ticketsList,
16
+ selectedTickets,
17
+ handleTicketSelect,
18
+ promoCodeIsApplied,
19
+ }: ITicketsSectionProps) => {
20
+ const sortedTicketsList = _sortBy(ticketsList, 'sortOrder')
21
+ return (
22
+ <>
23
+ {sortedTicketsList.map((ticket, i, arr) => {
24
+ const isSoldOut =
25
+ ticket.sold_out || !ticket.displayTicket || ticket.soldOut
26
+ const ticketSelect = (event: any) => {
27
+ const { value } = event.target
28
+ handleTicketSelect(ticket.id, value)
29
+ }
30
+
31
+ let ticketIsDiscounted = false
32
+ if (
33
+ ticket.oldPrice &&
34
+ promoCodeIsApplied &&
35
+ !isSoldOut &&
36
+ ticket.oldPrice !== ticket.price
37
+ ) {
38
+ ticketIsDiscounted = true
39
+ }
40
+
41
+ return (
42
+ <div
43
+ key={ticket.id || ticket.name}
44
+ className={`event-detail__tier ${isSoldOut ? 'disabled' : ''}`}
45
+ >
46
+ <div className="event-detail__tier-name">
47
+ {ticket.displayName || ticket.name}
48
+ </div>
49
+ <div className="event-tickets-container">
50
+ <div className="event-detail__tier-price">
51
+ {ticketIsDiscounted && (
52
+ <p className="old-price">$ {(+ticket.oldPrice).toFixed(2)}</p>
53
+ )}
54
+ <p>
55
+ {isSoldOut
56
+ ? 'SOLD OUT'
57
+ : `$ ${(+ticket.cost || +ticket.price).toFixed(2)}`}
58
+ </p>
59
+ {!isSoldOut && (
60
+ <p className="fees">
61
+ {ticket.taxesIncluded ? '(incl. Fees)' : '(excl. Fees)'}
62
+ </p>
63
+ )}
64
+ </div>
65
+ <div
66
+ className="event-detail__tier-state"
67
+ style={{ minWidth: 55 }}
68
+ >
69
+ <TicketRow
70
+ ticketTier={ticket}
71
+ prevTicketTier={arr[i - 1]}
72
+ selectedTickets={selectedTickets}
73
+ handleTicketSelect={ticketSelect}
74
+ />
75
+ </div>
76
+ </div>
77
+ </div>
78
+ )
79
+ })}
80
+ </>
81
+ )
82
+ }
@@ -3,150 +3,17 @@ import axios, { AxiosError } from 'axios'
3
3
  import './style.css'
4
4
 
5
5
  import { getTickets, addToCart, setCustomHeader } from '../../api'
6
- import _sortBy from 'lodash/sortBy'
7
6
  import _get from 'lodash/get'
8
- import _has from 'lodash/has'
9
7
  import _some from 'lodash/some'
10
8
  import _find from 'lodash/find'
11
9
  import _isEmpty from 'lodash/isEmpty'
12
10
  import _filter from 'lodash/filter'
13
11
  import _isObject from 'lodash/isObject'
14
- import Box from '@mui/material/Box'
15
- import FormControl from '@mui/material/FormControl'
16
- import MenuItem from '@mui/material/MenuItem'
17
- import Select from '@mui/material/Select'
18
12
  import CircularProgress from '@mui/material/CircularProgress'
19
13
  import Button from 'react-bootstrap/Button'
20
14
  import jwt_decode from 'jwt-decode'
21
-
22
- const getTicketSelectOptions = (
23
- maxCount: number = 10,
24
- minCount: number = 1,
25
- multiplier: number = 1
26
- ) => {
27
- const options = [{ label: 0, value: 0 }]
28
- for (let i = minCount; i <= Math.min(50, maxCount); i += multiplier) {
29
- options.push({ label: i, value: i })
30
- }
31
- return options
32
- }
33
-
34
- const computeTierStateLabel = (
35
- tier: any,
36
- prevTier: any,
37
- selectedTickets: any,
38
- handleTicketSelect: any
39
- ) => {
40
- const soldOutMessage = tier.soldOutMessage
41
- ? `${tier.soldOutMessage}`.toUpperCase()
42
- : 'SOLD OUT'
43
- const isSalesClosed =
44
- !tier.salesStarted ||
45
- tier.salesEnded ||
46
- !_has(tier, 'maxQuantity') ||
47
- tier.maxQuantity === 0
48
- const options = getTicketSelectOptions(
49
- tier.maxQuantity,
50
- tier.minQuantity,
51
- tier.multiplier
52
- )
53
-
54
- const onSaleContent = isSalesClosed ? null : (
55
- <div className="get-tickets">
56
- <Box className="get-tickets__selectbox">
57
- <FormControl fullWidth>
58
- <Select
59
- value={selectedTickets[tier.id] ? selectedTickets[tier.id] : 0}
60
- onChange={handleTicketSelect}
61
- displayEmpty
62
- inputProps={{ 'aria-label': 'Without label' }}
63
- MenuProps={{
64
- PaperProps: {
65
- sx: { maxHeight: 150 },
66
- className: 'get-tickets-paper',
67
- },
68
- }}
69
- >
70
- {options.map((option, index) => (
71
- <MenuItem key={index} value={option.value}>
72
- {option.value}
73
- </MenuItem>
74
- ))}
75
- </Select>
76
- </FormControl>
77
- </Box>
78
- </div>
79
- )
80
-
81
- if (tier.sold_out || !tier.displayTicket || tier.soldOut)
82
- return soldOutMessage
83
- if (!+tier.cost && !+tier.price) return 'FREE'
84
- if (tier.displayTicket) return onSaleContent
85
- if (prevTier.in_stock) return 'SOON'
86
-
87
- return ''
88
- }
89
-
90
- const renderTiers = (
91
- boxOffice: any,
92
- selectedTickets: any,
93
- handleTicketSelect: any,
94
- promoCodeIsApplied: boolean
95
- ) => {
96
- const sortedBoxOfiice = _sortBy(boxOffice, 'sortOrder')
97
- const primaryTiers = sortedBoxOfiice.map((tier, i, arr) => {
98
- const isSoldOut = tier.sold_out || !tier.displayTicket || tier.soldOut
99
- const ticketSelect = (event: any) => {
100
- const { value } = event.target
101
- handleTicketSelect(tier.id, value)
102
- }
103
-
104
- let ticketIsDiscounted = false
105
- if (
106
- tier.oldPrice &&
107
- promoCodeIsApplied &&
108
- !isSoldOut &&
109
- tier.oldPrice !== tier.price
110
- ) {
111
- ticketIsDiscounted = true
112
- }
113
-
114
- return (
115
- <div
116
- key={tier.id || tier.name}
117
- className={`event-detail__tier ${isSoldOut ? 'disabled' : ''}`}
118
- >
119
- <div className="event-detail__tier-name">
120
- {tier.displayName || tier.name}
121
- </div>
122
- <div className="event-tickets-container">
123
- <div className="event-detail__tier-price">
124
- {ticketIsDiscounted && (
125
- <p className="old-price">$ {(+tier.oldPrice).toFixed(2)}</p>
126
- )}
127
- <p>
128
- {isSoldOut
129
- ? 'SOLD OUT'
130
- : `$ ${(+tier.cost || +tier.price).toFixed(2)}`}
131
- </p>
132
- {!isSoldOut && (
133
- <p className='fees'>{tier.taxesIncluded ? '(incl. Fees)' : '(excl. Fees)'}</p>
134
- )}
135
- </div>
136
- <div className="event-detail__tier-state" style={{ minWidth: 55 }}>
137
- {computeTierStateLabel(
138
- tier,
139
- arr[i - 1],
140
- selectedTickets,
141
- ticketSelect
142
- )}
143
- </div>
144
- </div>
145
- </div>
146
- )
147
- })
148
- return primaryTiers
149
- }
15
+ import { TicketsSection } from './TicketsSection'
16
+ import WaitingList from '../waitingList'
150
17
 
151
18
  function Loader() {
152
19
  return (
@@ -160,6 +27,7 @@ interface CartSuccess {
160
27
  skip_billing_page: boolean;
161
28
  names_required: boolean;
162
29
  age_required: boolean;
30
+ event_id: string;
163
31
  }
164
32
 
165
33
  export interface IGetTickets {
@@ -170,6 +38,8 @@ export interface IGetTickets {
170
38
  onAddToCartError: (e: AxiosError) => void;
171
39
  onGetTicketsSuccess: (response: any) => void;
172
40
  onGetTicketsError: (e: AxiosError) => void;
41
+
42
+ theme?: 'light' | 'dark';
173
43
  }
174
44
 
175
45
  export interface ITicket {
@@ -189,11 +59,13 @@ export const TicketsContainer = ({
189
59
  onAddToCartError = () => {},
190
60
  onGetTicketsSuccess = () => {},
191
61
  onGetTicketsError = () => {},
62
+ theme = 'light',
192
63
  }: IGetTickets) => {
193
64
  const [selectedTickets, setSelectedTickets] = useState(
194
65
  {} as ISelectedTickets
195
66
  )
196
67
  const [tickets, setTickets] = useState([] as ITicket[])
68
+ const [showWaitingList, setShowWaitingList] = useState(false)
197
69
  const [isLoading, setIsLoading] = useState(false)
198
70
  const [handleBookIsLoading, setHandleBookIsLoading] = useState(false)
199
71
  const [promoCode, setPromoCode] = useState('')
@@ -223,11 +95,8 @@ export const TicketsContainer = ({
223
95
  setCustomHeader(response)
224
96
  const attributes = _get(response, 'data.data.attributes')
225
97
  setPromoCodeIsApplied(attributes.ValidPromoCode)
226
- const tickets = _filter(
227
- (Object.values(attributes) || []) as ITicket[],
228
- item => _isObject(item)
229
- )
230
- setTickets(tickets)
98
+ setTickets(_get(attributes, 'tickets'))
99
+ setShowWaitingList(attributes.showWaitingList)
231
100
  onGetTicketsSuccess(response.data)
232
101
  }
233
102
  } catch (e) {
@@ -290,6 +159,7 @@ export const TicketsContainer = ({
290
159
  names_required:
291
160
  result?.data?.data?.attributes?.names_required ?? false,
292
161
  age_required: result?.data?.data?.attributes?.age_required ?? false,
162
+ event_id: String(eventId)
293
163
  })
294
164
  }
295
165
  } catch (e) {
@@ -307,80 +177,86 @@ export const TicketsContainer = ({
307
177
  )
308
178
 
309
179
  return (
310
- <div className="get-tickets-page" style={contentStyle}>
180
+ <div className={`get-tickets-page ${theme}`} style={contentStyle}>
311
181
  {isLoading ? (
312
182
  <Loader />
313
183
  ) : (
314
- <div>
315
- {renderTiers(
316
- tickets,
317
- selectedTickets,
318
- handleTicketSelect,
319
- promoCodeIsApplied
320
- )}
321
- {promoCodeIsApplied ? (
322
- <div className="alert-info">
323
- Your promo code was applied successfully.
324
- </div>
325
- ) : null}
326
- {showPromoInput && (
327
- <div className="promo-code-block">
328
- <input
329
- placeholder="Promo Code"
330
- onChange={e => {
331
- setPromoCode(e.target.value)
332
- }}
333
- onKeyPress={event => {
334
- if (event.key === 'Enter') {
335
- setPromoCodeUpdated(promoCode)
336
- }
337
- }}
184
+ <>
185
+ {showWaitingList ? (
186
+ <WaitingList tickets={tickets} />
187
+ ) : (
188
+ <div>
189
+ <TicketsSection
190
+ ticketsList={tickets}
191
+ selectedTickets={selectedTickets}
192
+ handleTicketSelect={handleTicketSelect}
193
+ promoCodeIsApplied={promoCodeIsApplied}
338
194
  />
339
- <Button
340
- className="promo-apply-button"
341
- placeholder="Promo Code"
342
- onClick={() => {
343
- setPromoCodeUpdated(promoCode)
344
- }}
345
- >
346
- Apply
347
- </Button>
195
+ {promoCodeIsApplied ? (
196
+ <div className="alert-info">
197
+ Your promo code was applied successfully.
198
+ </div>
199
+ ) : null}
200
+ {showPromoInput && (
201
+ <div className="promo-code-block">
202
+ <input
203
+ placeholder="Promo Code"
204
+ onChange={e => {
205
+ setPromoCode(e.target.value)
206
+ }}
207
+ onKeyPress={event => {
208
+ if (event.key === 'Enter') {
209
+ setPromoCodeUpdated(promoCode)
210
+ }
211
+ }}
212
+ />
213
+ <Button
214
+ className="promo-apply-button"
215
+ placeholder="Promo Code"
216
+ onClick={() => {
217
+ setPromoCodeUpdated(promoCode)
218
+ }}
219
+ >
220
+ Apply
221
+ </Button>
222
+ </div>
223
+ )}
224
+ {!showPromoInput && !isAllTicketsSoldOut ? (
225
+ <Button
226
+ className="promo-code-button"
227
+ placeholder="Promo Codes"
228
+ onClick={() => {
229
+ setShowPromoInput(true)
230
+ }}
231
+ >
232
+ Got a promo code? Click here
233
+ </Button>
234
+ ) : null}
235
+ <div className="test v1.0.19" style={{ display: 'none' }} />
236
+ {!isAllTicketsSoldOut && (
237
+ <Button
238
+ aria-hidden={true}
239
+ className={`book-button ${
240
+ handleBookIsLoading ||
241
+ _isEmpty(selectedTickets) ||
242
+ Object.values(selectedTickets)[0] === 0
243
+ ? 'disabled'
244
+ : ''
245
+ }`}
246
+ onClick={
247
+ !handleBookIsLoading &&
248
+ !_isEmpty(selectedTickets) &&
249
+ Object.values(selectedTickets)[0] > 0
250
+ ? handleBook
251
+ : () => {}
252
+ }
253
+ >
254
+ {getTicketsLabel || 'GET TICKETS'}
255
+ </Button>
256
+ )}
348
257
  </div>
349
258
  )}
350
- {!showPromoInput && !isAllTicketsSoldOut ? (
351
- <Button
352
- className="promo-code-button"
353
- placeholder="Promo Codes"
354
- onClick={() => {
355
- setShowPromoInput(true)
356
- }}
357
- >
358
- Got a promo code? Click here
359
- </Button>
360
- ) : null}
361
- <div className="test v1.0.19" style={{ display: 'none' }} />
362
- {!isAllTicketsSoldOut && (
363
- <Button
364
- aria-hidden={true}
365
- className={`book-button ${
366
- handleBookIsLoading ||
367
- _isEmpty(selectedTickets) ||
368
- Object.values(selectedTickets)[0] === 0
369
- ? 'disabled'
370
- : ''
371
- }`}
372
- onClick={
373
- !handleBookIsLoading &&
374
- !_isEmpty(selectedTickets) &&
375
- Object.values(selectedTickets)[0] > 0
376
- ? handleBook
377
- : () => {}
378
- }
379
- >
380
- {getTicketsLabel || 'GET TICKETS'}
381
- </Button>
382
- )}
383
- </div>
259
+ </>
384
260
  )}
385
261
  </div>
386
262
  )