tf-checkout-react 1.0.43 → 1.0.47

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 (43) hide show
  1. package/dist/api/index.d.ts +2 -0
  2. package/dist/components/billing-info-container/index.d.ts +22 -3
  3. package/dist/components/billing-info-container/utils.d.ts +2 -2
  4. package/dist/components/common/CheckboxField.d.ts +2 -2
  5. package/dist/components/confirmationContainer/index.d.ts +4 -1
  6. package/dist/components/loginModal/index.d.ts +8 -4
  7. package/dist/components/paymentContainer/index.d.ts +5 -1
  8. package/dist/components/registerModal/index.d.ts +3 -0
  9. package/dist/components/ticketsContainer/TicketRow.d.ts +10 -0
  10. package/dist/components/ticketsContainer/TicketsSection.d.ts +10 -0
  11. package/dist/components/ticketsContainer/index.d.ts +7 -1
  12. package/dist/components/ticketsContainer/utils.d.ts +4 -0
  13. package/dist/components/waitingList/index.d.ts +7 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/tf-checkout-react.cjs.development.css +3 -2
  16. package/dist/tf-checkout-react.cjs.development.js +827 -269
  17. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  18. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  19. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  20. package/dist/tf-checkout-react.esm.js +832 -272
  21. package/dist/tf-checkout-react.esm.js.map +1 -1
  22. package/dist/types/billing-info-data.d.ts +2 -2
  23. package/dist/validators/index.d.ts +2 -1
  24. package/package.json +4 -1
  25. package/src/api/index.ts +7 -3
  26. package/src/components/billing-info-container/index.tsx +278 -70
  27. package/src/components/billing-info-container/style.css +15 -0
  28. package/src/components/billing-info-container/utils.ts +41 -13
  29. package/src/components/common/CheckboxField.tsx +3 -2
  30. package/src/components/common/CustomField.tsx +16 -1
  31. package/src/components/confirmationContainer/index.tsx +8 -3
  32. package/src/components/loginModal/index.tsx +46 -13
  33. package/src/components/paymentContainer/index.tsx +10 -0
  34. package/src/components/registerModal/index.tsx +20 -3
  35. package/src/components/ticketsContainer/TicketRow.tsx +86 -0
  36. package/src/components/ticketsContainer/TicketsSection.tsx +82 -0
  37. package/src/components/ticketsContainer/index.tsx +98 -210
  38. package/src/components/ticketsContainer/utils.ts +11 -0
  39. package/src/components/waitingList/index.tsx +162 -0
  40. package/src/components/waitingList/style.css +18 -0
  41. package/src/index.ts +2 -1
  42. package/src/types/billing-info-data.ts +2 -2
  43. package/src/validators/index.ts +9 -3
@@ -16,7 +16,8 @@ export interface IValues {
16
16
 
17
17
  export const getInitialValues = (
18
18
  data: any = [],
19
- propsInitialValues: IValues = {}
19
+ propsInitialValues: IValues = {},
20
+ userValues: any = {}
20
21
  ): IValues => {
21
22
  const results = _flatMapDeep(data, ({ fields }) =>
22
23
  _map(fields, ({ groupItems }) => _map(groupItems, ({ name }) => name))
@@ -24,7 +25,7 @@ export const getInitialValues = (
24
25
 
25
26
  const initialValues: IValues = {}
26
27
  _forEach(results, item => {
27
- initialValues[item] = propsInitialValues[item] || ''
28
+ initialValues[item] = propsInitialValues[item] || userValues[item] || ''
28
29
  })
29
30
 
30
31
  return initialValues
@@ -68,6 +69,13 @@ interface IUserData {
68
69
  zipCode?: string;
69
70
  }
70
71
 
72
+ interface IticketHolder {
73
+ first_name?: string;
74
+ last_name?: string;
75
+ phone?: string;
76
+ email?: string;
77
+ }
78
+
71
79
  export const setLoggedUserData = (data: IUserData) => ({
72
80
  id: data.id,
73
81
  first_name: data.firstName,
@@ -82,34 +90,55 @@ export const setLoggedUserData = (data: IUserData) => ({
82
90
  })
83
91
 
84
92
  export const createCheckoutDataBody = (
93
+ ticketsQuantity: number,
85
94
  values: IValues = {},
86
95
  logedInValues: ILoggedInValues = {},
87
96
  includeDob: boolean = false
88
97
  ): ICheckoutBody => {
89
98
  const {
90
- holderAge,
91
99
  firstName,
92
100
  lastName,
101
+ holderAge,
93
102
  confirmEmail,
94
103
  confirmPassword,
95
- holderFirstName,
96
- holderLastName,
97
104
  ...restValues
98
105
  } = values
99
106
 
107
+ const holders = []
108
+ let ticket_holders: IticketHolder[] = []
109
+
110
+ for (let i = 0; i <= ticketsQuantity; i++) {
111
+ const individualHolder = Object.fromEntries(
112
+ Object.entries(values).filter(([key, _val]) => key.includes(String(i)))
113
+ )
114
+ holders.push(individualHolder)
115
+ }
116
+
117
+ const filteredHolders = holders.filter(
118
+ holder => Object.entries(holder).length > 0
119
+ )
120
+ ticket_holders = filteredHolders.map((item, index) => ({
121
+ first_name: item[`holderFirstName-${index}`] || '',
122
+ last_name: item[`holderLastName-${index}`] || '',
123
+ phone: item[`holderPhone-${index}`] || '',
124
+ email: item[`holderEmail-${index}`] || '',
125
+ }))
126
+
127
+ const filteredRestValue: { [key: string]: any } = {}
128
+ _forEach(restValues, (value, key) => {
129
+ if (!key.includes('holder')) {
130
+ filteredRestValue[key] = value
131
+ }
132
+ })
133
+
100
134
  const body: ICheckoutBody = {
101
135
  attributes: {
102
- ...restValues,
136
+ ...filteredRestValue,
103
137
  email: restValues.email || logedInValues.emailLogged,
104
138
  confirm_email: restValues.email || logedInValues.emailLogged,
105
139
  first_name: firstName || logedInValues.firstNameLogged,
106
140
  last_name: lastName || logedInValues.lastNameLogged,
107
- ticket_holders: [
108
- {
109
- first_name: holderFirstName,
110
- last_name: holderLastName,
111
- },
112
- ],
141
+ ticket_holders,
113
142
  },
114
143
  }
115
144
 
@@ -119,6 +148,5 @@ export const createCheckoutDataBody = (
119
148
  body.attributes.dob_month = holderAgeDate.getMonth() + 1
120
149
  body.attributes.dob_year = holderAgeDate.getFullYear()
121
150
  }
122
-
123
151
  return body
124
152
  }
@@ -5,7 +5,7 @@ import Checkbox from '@mui/material/Checkbox'
5
5
  import { FieldInputProps } from 'formik'
6
6
 
7
7
  export interface ICheckboxField {
8
- label: string;
8
+ label: string | number | JSX.Element;
9
9
  field: FieldInputProps<any>;
10
10
  }
11
11
 
@@ -16,8 +16,9 @@ interface IOtherProps {
16
16
  export const CheckboxField = ({
17
17
  label,
18
18
  field,
19
+ ...rest
19
20
  }: ICheckboxField & IOtherProps) => (
20
21
  <FormGroup>
21
- <FormControlLabel control={<Checkbox {...field} />} label={label} />
22
+ <FormControlLabel control={<Checkbox {...field} {...rest} />} label={label} />
22
23
  </FormGroup>
23
24
  )
@@ -4,6 +4,7 @@ import _map from 'lodash/map'
4
4
  import _get from 'lodash/get'
5
5
 
6
6
  import { FieldInputProps, FormikProps } from 'formik'
7
+ import { makeStyles } from '@mui/styles'
7
8
 
8
9
  export interface ISelectOption {
9
10
  label: string | number;
@@ -26,6 +27,14 @@ interface IOtherProps {
26
27
  [key: string]: any;
27
28
  }
28
29
 
30
+ const useStyles = makeStyles({
31
+ input: {
32
+ "&::placeholder": {
33
+ color: "gray",
34
+ }
35
+ },
36
+ })
37
+
29
38
  export const CustomField = ({
30
39
  label,
31
40
  type = 'text',
@@ -37,6 +46,7 @@ export const CustomField = ({
37
46
  const isShrink = Boolean(field.value) || type === 'date' || type === 'select'
38
47
  const isTouched = Boolean(_get(touched, field.name))
39
48
  const error = _get(errors, field.name)
49
+ const classes = useStyles()
40
50
 
41
51
  return (
42
52
  <TextField
@@ -48,12 +58,17 @@ export const CustomField = ({
48
58
  error={!!error && isTouched}
49
59
  helperText={isTouched && error}
50
60
  InputLabelProps={{ shrink: isShrink }}
61
+ InputProps={{
62
+ classes: {
63
+ input: classes.input
64
+ }
65
+ }}
51
66
  SelectProps={{ native: true }}
52
67
  {...field}
53
68
  >
54
69
  {isSelectField
55
70
  ? _map(selectOptions, option => (
56
- <option key={option.value} value={option.value}>
71
+ <option key={option.value} value={option.value} disabled={option.disabled}>
57
72
  {option.label}
58
73
  </option>
59
74
  ))
@@ -7,6 +7,7 @@ import _get from 'lodash/get'
7
7
 
8
8
  import { IReferralPromotion } from '../../types'
9
9
  import { getConfirmationData } from '../../api'
10
+ import { AxiosError } from 'axios'
10
11
 
11
12
  export interface IShareButton {
12
13
  mainLabel: string;
@@ -26,6 +27,8 @@ export interface IConfirmationPage {
26
27
  shareLink: string;
27
28
  isReferralEnabled: boolean;
28
29
  shareButtons: IShareButton[];
30
+ onGetConfirmationDataSuccess: (res: any) => void;
31
+ onGetConfirmationDataError: (e: AxiosError) => void;
29
32
  }
30
33
 
31
34
  const defaultSvg =
@@ -35,6 +38,8 @@ export const ConfirmationContainer = ({
35
38
  referralPromotions = [],
36
39
  shareButtons = [],
37
40
  shareLink = '',
41
+ onGetConfirmationDataSuccess = () => {},
42
+ onGetConfirmationDataError = () => {},
38
43
  }: IConfirmationPage) => {
39
44
  const inputRef = useRef(null)
40
45
  const [data, setData] = useState<any>({})
@@ -55,14 +60,14 @@ export const ConfirmationContainer = ({
55
60
  try {
56
61
  const response = await getConfirmationData(hash)
57
62
  const data = _get(response, 'data.data.attributes')
58
-
59
63
  setData(data)
64
+ onGetConfirmationDataSuccess(response.data)
60
65
  } catch (error) {
61
- //...
66
+ onGetConfirmationDataError(error.response)
62
67
  }
63
68
  }
64
69
  })()
65
- }, [])
70
+ }, [onGetConfirmationDataSuccess, onGetConfirmationDataError])
66
71
 
67
72
  return (
68
73
  <div className="confirmation-page">
@@ -1,4 +1,5 @@
1
1
  import React, { FC, useState } from 'react'
2
+ import { AxiosError } from 'axios'
2
3
  import {
3
4
  authorize,
4
5
  getAccessToken,
@@ -18,9 +19,12 @@ import axios from 'axios'
18
19
  interface Props {
19
20
  onClose: () => void;
20
21
  onLogin: () => void;
21
- alreadyHasUser: boolean;
22
- userExpired: boolean;
23
- setUserExpired: React.Dispatch<React.SetStateAction<boolean>>;
22
+ alreadyHasUser?: boolean;
23
+ userExpired?: boolean;
24
+ onAuthorizeSuccess?: (res: any) => void;
25
+ onAuthorizeError?: (e: AxiosError) => void;
26
+ onGetProfileDataSuccess?: (res: any) => void;
27
+ onGetProfileDataError?: (e: AxiosError) => void;
24
28
  }
25
29
 
26
30
  const style: React.CSSProperties = {
@@ -37,9 +41,12 @@ const style: React.CSSProperties = {
37
41
  export const LoginModal: FC<Props> = ({
38
42
  onClose,
39
43
  onLogin,
40
- alreadyHasUser,
41
- userExpired,
42
- setUserExpired,
44
+ alreadyHasUser = false,
45
+ userExpired = false,
46
+ onAuthorizeSuccess = () => {},
47
+ onAuthorizeError = () => {},
48
+ onGetProfileDataSuccess = () => {},
49
+ onGetProfileDataError = () => {},
43
50
  }) => {
44
51
  const [error, setError] = useState('')
45
52
  return (
@@ -58,8 +65,8 @@ export const LoginModal: FC<Props> = ({
58
65
  const bodyFormData = new FormData()
59
66
  bodyFormData.append('email', email)
60
67
  bodyFormData.append('password', password)
61
- const resAutorize = await authorize(bodyFormData)
62
68
 
69
+ const resAutorize = await authorize(bodyFormData)
63
70
  const bodyFormDataToken = new FormData()
64
71
  bodyFormDataToken.append('code', resAutorize.data.data.code)
65
72
  bodyFormDataToken.append('scope', 'profile')
@@ -73,22 +80,48 @@ export const LoginModal: FC<Props> = ({
73
80
  ENV.CLIENT_SECRET ||
74
81
  'b89c191eff22fdcf84ac9bfd88d005355a151ec2c83b26b9'
75
82
  )
76
- const resAccessToken = await getAccessToken(bodyFormDataToken)
83
+
84
+ let resAccessToken = null
85
+
86
+ try {
87
+ resAccessToken = await getAccessToken(bodyFormDataToken)
88
+ onAuthorizeSuccess(resAccessToken.data)
89
+ } catch (e) {
90
+ if (axios.isAxiosError(e)) {
91
+ onAuthorizeError(e)
92
+ }
93
+ return
94
+ }
95
+
77
96
  const accessToken = _get(resAccessToken, 'data.access_token')
78
97
  handleSetAccessToken(accessToken)
79
- const profileData = await getProfileData(accessToken)
80
- const profileSpecifiedData = _get(profileData, 'data.data')
98
+
99
+ let profileResponse = null
100
+
101
+ try {
102
+ profileResponse = await getProfileData(accessToken)
103
+ onGetProfileDataSuccess(profileResponse.data)
104
+ } catch (e) {
105
+ if (axios.isAxiosError(e)) {
106
+ onGetProfileDataError(e)
107
+ }
108
+ return
109
+ }
110
+
111
+ const profileSpecifiedData = _get(profileResponse, 'data.data')
81
112
  const profileDataObj = {
82
113
  id: profileSpecifiedData.id,
83
114
  first_name: profileSpecifiedData.firstName,
84
115
  last_name: profileSpecifiedData.lastName,
85
- email: profileSpecifiedData.email
116
+ email: profileSpecifiedData.email,
86
117
  }
87
118
  if (typeof window !== 'undefined') {
88
- window.localStorage.setItem('user_data', JSON.stringify(profileDataObj))
119
+ window.localStorage.setItem(
120
+ 'user_data',
121
+ JSON.stringify(profileDataObj)
122
+ )
89
123
  window.localStorage.setItem('access_token', accessToken)
90
124
  }
91
- setUserExpired(false)
92
125
  onLogin()
93
126
  } catch (e) {
94
127
  if (axios.isAxiosError(e)) {
@@ -1,4 +1,5 @@
1
1
  import React, { useEffect, useState } from 'react'
2
+ import { AxiosError } from 'axios'
2
3
  import Container from '@mui/material/Container'
3
4
  import Alert from '@mui/material/Alert'
4
5
  import { Elements } from '@stripe/react-stripe-js'
@@ -26,6 +27,9 @@ export interface IPaymentPage {
26
27
  formTitle?: string;
27
28
  errorText?: string;
28
29
  onErrorClose?: () => void;
30
+ onGetPaymentDataSuccess: (value: any) => void;
31
+ onGetPaymentDataError: (value: AxiosError) => void;
32
+ onPaymentError: (value: AxiosError) => void;
29
33
  }
30
34
 
31
35
  const initialOrderValues: IOrderData = {
@@ -53,6 +57,9 @@ export const PaymentContainer = ({
53
57
  errorText,
54
58
  checkoutData,
55
59
  onErrorClose = _identity,
60
+ onGetPaymentDataSuccess = () => {},
61
+ onGetPaymentDataError = () => {},
62
+ onPaymentError = () => {}
56
63
  }: IPaymentPage) => {
57
64
  const [reviewData, setReviewData] = useState(initialReviewValues)
58
65
  const [orderData, setOrderData] = useState(initialOrderValues)
@@ -83,9 +90,11 @@ export const PaymentContainer = ({
83
90
  currency: order_details?.currency,
84
91
  }
85
92
  setOrderData(orderData)
93
+ onGetPaymentDataSuccess(response.data)
86
94
  }
87
95
  } catch (e) {
88
96
  setError(_get(e, 'response.data.message'))
97
+ onGetPaymentDataError(e.response)
89
98
  }
90
99
  })()
91
100
  }, [checkoutData])
@@ -109,6 +118,7 @@ export const PaymentContainer = ({
109
118
  }
110
119
  } catch (e) {
111
120
  setError(_get(e, 'response.data.message'))
121
+ onPaymentError(e.response)
112
122
  }
113
123
  }
114
124
 
@@ -1,4 +1,5 @@
1
1
  import React, { FC } from 'react'
2
+ import { AxiosError } from 'axios'
2
3
  import './style.css'
3
4
  import { getProfileData, handleSetAccessToken, register } from '../../api'
4
5
  import { Field, Form, Formik } from 'formik'
@@ -10,9 +11,15 @@ import { ENV } from '../../env'
10
11
  interface Props {
11
12
  onClose: () => void;
12
13
  onRegister: () => void;
14
+ onGetProfileDataSuccess: (res: any) => void;
15
+ onGetProfileDataError: (e: AxiosError) => void;
13
16
  }
14
17
 
15
- export const RegisterModal: FC<Props> = ({ onClose }) => (
18
+ export const RegisterModal: FC<Props> = ({
19
+ onClose,
20
+ onGetProfileDataSuccess = () => {},
21
+ onGetProfileDataError = () => {},
22
+ }) => (
16
23
  <div
17
24
  style={{
18
25
  display: 'flex',
@@ -63,8 +70,18 @@ export const RegisterModal: FC<Props> = ({ onClose }) => (
63
70
  'data.data.attributes.access_token'
64
71
  )
65
72
  handleSetAccessToken(access_token)
66
- const profileData = await getProfileData(access_token)
67
- const profileSpecifiedData = _get(profileData, 'data.data')
73
+
74
+ let profileResponse = null
75
+
76
+ try {
77
+ profileResponse = await getProfileData(access_token)
78
+ onGetProfileDataSuccess(profileResponse.data)
79
+ } catch (e) {
80
+ onGetProfileDataError(e.response)
81
+ return
82
+ }
83
+
84
+ const profileSpecifiedData = _get(profileResponse, 'data.data')
68
85
  const profileDataObj = {
69
86
  id: profileSpecifiedData.id,
70
87
  first_name: profileSpecifiedData.firstName,
@@ -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
+ }