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,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
|
+
}
|