tf-checkout-react 1.6.6 → 1.7.1
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/README.md +401 -59
- package/dist/adapters/customFields.d.ts +1 -0
- package/dist/api/checkout.d.ts +2 -0
- package/dist/api/common.d.ts +1 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/preRegistrationComplete.d.ts +1 -1
- package/dist/components/addonsContainer/AddonComponent.d.ts +6 -1
- package/dist/components/addonsContainer/SimpleAddonsContainer.d.ts +17 -0
- package/dist/components/addonsContainer/index.d.ts +6 -1
- package/dist/components/billing-info-container/hooks/index.d.ts +3 -0
- package/dist/components/billing-info-container/hooks/usePaymentContext.d.ts +5 -0
- package/dist/components/billing-info-container/hooks/usePaymentRedirect.d.ts +14 -0
- package/dist/components/billing-info-container/hooks/useStripePayment.d.ts +18 -0
- package/dist/components/billing-info-container/index.d.ts +13 -2
- package/dist/components/billing-info-container/utils.d.ts +25 -1
- package/dist/components/common/DatePickerField.d.ts +7 -1
- package/dist/components/confirmationContainer/index.d.ts +4 -1
- package/dist/components/countdown/index.d.ts +1 -1
- package/dist/components/forgotPasswordModal/index.d.ts +2 -1
- package/dist/components/myTicketsContainer/index.d.ts +3 -2
- package/dist/components/orderDetailsContainer/index.d.ts +8 -1
- package/dist/components/paymentContainer/OrderDetails.d.ts +9 -0
- package/dist/components/paymentContainer/handlePayment.d.ts +15 -0
- package/dist/components/paymentContainer/index.d.ts +12 -6
- package/dist/components/preRegistration/FieldsSection.d.ts +7 -1
- package/dist/components/preRegistration/PreRegistrationComplete.d.ts +6 -0
- package/dist/components/preRegistration/constants.d.ts +2 -2
- package/dist/components/preRegistration/index.d.ts +6 -0
- package/dist/components/resetPasswordContainer/index.d.ts +2 -2
- package/dist/components/ticketsContainer/InfoIcon.d.ts +5 -0
- package/dist/components/ticketsContainer/TicketsSection.d.ts +3 -2
- package/dist/components/ticketsContainer/TimeSlotsSection.d.ts +25 -0
- package/dist/components/ticketsContainer/index.d.ts +29 -5
- package/dist/components/timerWidget/index.d.ts +2 -1
- package/dist/constants/index.d.ts +5 -0
- package/dist/index.d.ts +4 -1
- package/dist/tf-checkout-react.cjs.development.js +11231 -9563
- 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 +11194 -9529
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/dist/tf-checkout-styles.css +1 -1
- package/dist/types/add_on.d.ts +1 -0
- package/dist/types/checkoutPageConfigs.d.ts +1 -1
- package/dist/types/order-data.d.ts +3 -1
- package/dist/utils/auth.d.ts +8 -0
- package/dist/utils/customFields.d.ts +11 -0
- package/dist/utils/getDomain.d.ts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/setConfigs.d.ts +1 -0
- package/package.json +14 -8
- package/src/adapters/customFields.ts +7 -1
- package/src/api/auth.ts +2 -1
- package/src/api/checkout.ts +9 -4
- package/src/api/common.ts +49 -2
- package/src/api/index.ts +1 -0
- package/src/api/interceptors.ts +7 -23
- package/src/api/preRegistrationComplete.ts +1 -1
- package/src/api/publicRequest.ts +10 -0
- package/src/components/addonsContainer/AddonComponent.tsx +96 -11
- package/src/components/addonsContainer/SimpleAddonsContainer.tsx +420 -0
- package/src/components/addonsContainer/index.tsx +198 -47
- package/src/components/billing-info-container/hooks/index.ts +3 -0
- package/src/components/billing-info-container/hooks/usePaymentContext.ts +22 -0
- package/src/components/billing-info-container/hooks/usePaymentRedirect.ts +147 -0
- package/src/components/billing-info-container/hooks/useStripePayment.ts +121 -0
- package/src/components/billing-info-container/index.tsx +827 -406
- package/src/components/billing-info-container/{utils.ts → utils.tsx} +119 -0
- package/src/components/common/CheckboxField/index.tsx +1 -1
- package/src/components/common/CustomField.tsx +38 -2
- package/src/components/common/DatePickerField.tsx +25 -10
- package/src/components/common/SnackbarAlert.tsx +32 -34
- package/src/components/confirmationContainer/config.ts +3 -3
- package/src/components/confirmationContainer/index.tsx +20 -1
- package/src/components/confirmationContainer/social-buttons.tsx +5 -3
- package/src/components/confirmationContainer/style.css +9 -5
- package/src/components/countdown/index.tsx +22 -22
- package/src/components/delegationsContainer/IssueComponent.tsx +2 -1
- package/src/components/forgotPasswordModal/index.tsx +44 -13
- package/src/components/loginForm/index.tsx +1 -1
- package/src/components/loginModal/index.tsx +19 -27
- package/src/components/loginModal/style.css +3 -1
- package/src/components/myTicketsContainer/index.tsx +13 -9
- package/src/components/orderDetailsContainer/index.tsx +206 -174
- package/src/components/paymentContainer/OrderDetails.tsx +257 -0
- package/src/components/paymentContainer/handlePayment.ts +86 -0
- package/src/components/paymentContainer/index.tsx +299 -259
- package/src/components/paymentContainer/style.css +141 -0
- package/src/components/preRegistration/FieldsSection.tsx +8 -0
- package/src/components/preRegistration/PreRegistrationComplete.tsx +128 -118
- package/src/components/preRegistration/PreRegistrationInformations.tsx +21 -15
- package/src/components/preRegistration/constants.tsx +10 -4
- package/src/components/preRegistration/index.tsx +194 -174
- package/src/components/registerForm/constants.tsx +3 -1
- package/src/components/registerForm/index.tsx +3 -3
- package/src/components/registerModal/index.tsx +47 -72
- package/src/components/resetPasswordContainer/index.tsx +20 -14
- package/src/components/seatMapContainer/TicketsSection.tsx +2 -2
- package/src/components/signupModal/index.tsx +13 -6
- package/src/components/ticketResale/index.tsx +7 -0
- package/src/components/ticketsContainer/InfoIcon.tsx +35 -0
- package/src/components/ticketsContainer/PromoCodeSection.tsx +34 -28
- package/src/components/ticketsContainer/TicketRow.tsx +1 -1
- package/src/components/ticketsContainer/TicketsSection.tsx +189 -57
- package/src/components/ticketsContainer/TimeSlotsSection.tsx +120 -0
- package/src/components/ticketsContainer/index.tsx +268 -106
- package/src/components/timerWidget/index.tsx +15 -3
- package/src/constants/index.ts +2 -0
- package/src/env.ts +14 -6
- package/src/hoc/CustomFields/index.tsx +9 -1
- package/src/index.ts +7 -2
- package/src/types/add_on.ts +1 -0
- package/src/types/api/cart.d.ts +8 -0
- package/src/types/api/checkout.d.ts +58 -7
- package/src/types/api/common.d.ts +30 -0
- package/src/types/api/orders.d.ts +19 -3
- package/src/types/api/payment.d.ts +6 -2
- package/src/types/api/preRegistrationComplete.d.ts +2 -2
- package/src/types/checkoutPageConfigs.ts +1 -1
- package/src/types/order-data.ts +3 -1
- package/src/types/pre-registration-complete.d.ts +6 -1
- package/src/utils/auth.ts +32 -0
- package/src/utils/cookies.ts +42 -11
- package/src/utils/customFields.ts +22 -0
- package/src/utils/getDomain.ts +10 -4
- package/src/utils/index.ts +1 -1
- package/src/utils/setConfigs.ts +3 -1
- package/dist/components/stripePayment/index.d.ts +0 -24
- package/src/components/stripePayment/index.tsx +0 -281
- package/src/components/stripePayment/style.css +0 -60
|
@@ -1,31 +1,38 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import './style.css'
|
|
2
|
+
|
|
3
3
|
import { CircularProgress } from '@mui/material'
|
|
4
|
-
import { CustomField } from '../common/CustomField'
|
|
5
4
|
import axios, { AxiosError } from 'axios'
|
|
5
|
+
import { Field, Form, Formik } from 'formik'
|
|
6
|
+
import _identity from 'lodash/identity'
|
|
7
|
+
import React, { FC, useState } from 'react'
|
|
6
8
|
import * as Yup from 'yup'
|
|
9
|
+
|
|
7
10
|
import { resetPassword } from '../../api'
|
|
8
|
-
import '
|
|
11
|
+
import { CustomField } from '../common/CustomField'
|
|
9
12
|
|
|
10
13
|
interface IResetPasswordProps {
|
|
11
|
-
token?: string
|
|
12
|
-
onResetPasswordSuccess?: (res: any) => void
|
|
13
|
-
onResetPasswordError?: (e: AxiosError) => void
|
|
14
|
+
token?: string;
|
|
15
|
+
onResetPasswordSuccess?: (res: any) => void;
|
|
16
|
+
onResetPasswordError?: (e: AxiosError) => void;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
const Schema = Yup.object().shape({
|
|
17
20
|
password: Yup.string()
|
|
18
|
-
.min(
|
|
19
|
-
.required('Required')
|
|
20
|
-
|
|
21
|
+
.min(8, 'Password must have 8+ characters')
|
|
22
|
+
.required('Required')
|
|
23
|
+
.matches(
|
|
24
|
+
new RegExp('^(?=.*[@$!%*#?&])'),
|
|
25
|
+
'Password must contain at least one special character'
|
|
26
|
+
),
|
|
27
|
+
password_confirmation: Yup.string()
|
|
21
28
|
.required('Required')
|
|
22
29
|
.oneOf([Yup.ref('password'), null], 'Passwords must match'),
|
|
23
30
|
})
|
|
24
31
|
|
|
25
32
|
export const ResetPasswordContainer: FC<IResetPasswordProps> = ({
|
|
26
33
|
token: tokenProps = '',
|
|
27
|
-
onResetPasswordSuccess =
|
|
28
|
-
onResetPasswordError =
|
|
34
|
+
onResetPasswordSuccess = _identity,
|
|
35
|
+
onResetPasswordError = _identity,
|
|
29
36
|
}) => {
|
|
30
37
|
const [loading, setLoading] = useState(false)
|
|
31
38
|
return (
|
|
@@ -42,8 +49,7 @@ export const ResetPasswordContainer: FC<IResetPasswordProps> = ({
|
|
|
42
49
|
token = tokenProps
|
|
43
50
|
} else {
|
|
44
51
|
if (typeof window !== 'undefined') {
|
|
45
|
-
const params: URLSearchParams = new URL(`${window.location}`)
|
|
46
|
-
.searchParams
|
|
52
|
+
const params: URLSearchParams = new URL(`${window.location}`).searchParams
|
|
47
53
|
token = params.get('token')
|
|
48
54
|
}
|
|
49
55
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CSSProperties } from '@emotion/serialize'
|
|
2
|
-
import {
|
|
2
|
+
import { Select, SelectChangeEvent, ThemeOptions } from '@mui/material'
|
|
3
3
|
import CircularProgress from '@mui/material/CircularProgress'
|
|
4
4
|
import FormControl from '@mui/material/FormControl'
|
|
5
5
|
import InputLabel from '@mui/material/InputLabel'
|
|
6
6
|
import MenuItem from '@mui/material/MenuItem'
|
|
7
|
+
import { createTheme, ThemeProvider } from '@mui/material/styles'
|
|
7
8
|
import Tooltip from '@mui/material/Tooltip'
|
|
8
|
-
import { ThemeProvider } from '@mui/private-theming'
|
|
9
9
|
import _find from 'lodash/find'
|
|
10
10
|
import _identity from 'lodash/identity'
|
|
11
11
|
import _isEmpty from 'lodash/isEmpty'
|
|
@@ -3,6 +3,7 @@ import './style.css'
|
|
|
3
3
|
import { Box, CircularProgress, Modal } from '@mui/material'
|
|
4
4
|
import axios, { AxiosError } from 'axios'
|
|
5
5
|
import { Field, Form, Formik } from 'formik'
|
|
6
|
+
import _identity from 'lodash/identity'
|
|
6
7
|
import React, { FC, useState } from 'react'
|
|
7
8
|
import * as Yup from 'yup'
|
|
8
9
|
|
|
@@ -43,17 +44,23 @@ const SignupSchema = Yup.object().shape({
|
|
|
43
44
|
firstName: Yup.string().required('Required'),
|
|
44
45
|
lastName: Yup.string().required('Required'),
|
|
45
46
|
email: Yup.string().email('Invalid email').required('Required'),
|
|
46
|
-
password: Yup.string()
|
|
47
|
+
password: Yup.string()
|
|
48
|
+
.min(8, 'Password must have 8+ characters')
|
|
49
|
+
.required('Required')
|
|
50
|
+
.matches(
|
|
51
|
+
new RegExp('^(?=.*[@$!%*#?&])'),
|
|
52
|
+
'Password must contain at least one special character'
|
|
53
|
+
),
|
|
47
54
|
confirmPassword: Yup.string()
|
|
48
55
|
.required('Required')
|
|
49
56
|
.oneOf([Yup.ref('password'), null], 'Passwords must match'),
|
|
50
57
|
})
|
|
51
58
|
|
|
52
59
|
export const SignupModal: FC<ISignupProps> = ({
|
|
53
|
-
onClose =
|
|
54
|
-
onLogin =
|
|
55
|
-
onRegisterSuccess =
|
|
56
|
-
onRegisterError =
|
|
60
|
+
onClose = _identity,
|
|
61
|
+
onLogin = _identity,
|
|
62
|
+
onRegisterSuccess = _identity,
|
|
63
|
+
onRegisterError = _identity,
|
|
57
64
|
showPoweredByImage = false,
|
|
58
65
|
}) => {
|
|
59
66
|
const [loading, setLoading] = useState(false)
|
|
@@ -89,7 +96,7 @@ export const SignupModal: FC<ISignupProps> = ({
|
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
98
|
|
|
92
|
-
const _onClose = loading ?
|
|
99
|
+
const _onClose = loading ? _identity : onClose
|
|
93
100
|
|
|
94
101
|
return (
|
|
95
102
|
<Modal
|
|
@@ -33,6 +33,7 @@ export const TicketResaleContainer = ({
|
|
|
33
33
|
const params: URLSearchParams = new URL(`${window.location}`).searchParams
|
|
34
34
|
const hash = params.get('invitation_hash') || orderHash || null
|
|
35
35
|
const isDeclined = params.get('decline') || false
|
|
36
|
+
window.localStorage.removeItem('checkoutAdditionalConfigs')
|
|
36
37
|
|
|
37
38
|
if (hash) {
|
|
38
39
|
// Process of declining ticket purchase invitation
|
|
@@ -53,6 +54,12 @@ export const TicketResaleContainer = ({
|
|
|
53
54
|
try {
|
|
54
55
|
const response = await processTicket(hash)
|
|
55
56
|
const event_id = _get(response.data.data.attributes, 'event_id')
|
|
57
|
+
const eventHasAddons = _get(response.data.data.attributes, 'has_add_on')
|
|
58
|
+
const invitationIncludesAddons = _get(response.data.data.attributes, 'include_add_on')
|
|
59
|
+
window.localStorage.setItem('checkoutAdditionalConfigs', JSON.stringify({
|
|
60
|
+
resale: true,
|
|
61
|
+
resaleWithAddons: eventHasAddons && invitationIncludesAddons,
|
|
62
|
+
}))
|
|
56
63
|
|
|
57
64
|
onProcessTicketSuccess(response.data)
|
|
58
65
|
if (defaultRedirection) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
|
|
3
|
+
const InfoIcon = ({ size = 17 }) => (
|
|
4
|
+
<svg
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
width={size}
|
|
7
|
+
height={size}
|
|
8
|
+
viewBox="0 0 17 17"
|
|
9
|
+
fill="none"
|
|
10
|
+
>
|
|
11
|
+
<circle
|
|
12
|
+
cx="8.5"
|
|
13
|
+
cy="8.5"
|
|
14
|
+
r="8"
|
|
15
|
+
stroke="black"
|
|
16
|
+
strokeWidth="1"
|
|
17
|
+
/>
|
|
18
|
+
<rect
|
|
19
|
+
x="7.5"
|
|
20
|
+
y="4"
|
|
21
|
+
width="2"
|
|
22
|
+
height="2"
|
|
23
|
+
fill="black"
|
|
24
|
+
/>
|
|
25
|
+
<rect
|
|
26
|
+
x="7.5"
|
|
27
|
+
y="7"
|
|
28
|
+
width="2"
|
|
29
|
+
height="5"
|
|
30
|
+
fill="black"
|
|
31
|
+
/>
|
|
32
|
+
</svg>
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
export default InfoIcon
|
|
@@ -33,38 +33,39 @@ export const PromoCodeSection = ({
|
|
|
33
33
|
showAlertIcons
|
|
34
34
|
}: IPromoCodeSectionProps) => {
|
|
35
35
|
const isPromoCodeHasValue = !!code.trim()
|
|
36
|
+
const appliedPromoCode = window?.localStorage?.getItem('appliedPromoCode')
|
|
36
37
|
|
|
37
38
|
const renderInputField = () => (
|
|
39
|
+
<div className="promo-code-block">
|
|
38
40
|
<div className="promo-code-block">
|
|
39
|
-
<
|
|
40
|
-
<p className="promo-code-text">Promo code</p>
|
|
41
|
-
</div>
|
|
42
|
-
<input
|
|
43
|
-
className="promo-code-input"
|
|
44
|
-
placeholder=""
|
|
45
|
-
onChange={e => {
|
|
46
|
-
setCode(e.target.value)
|
|
47
|
-
}}
|
|
48
|
-
onKeyPress={event => {
|
|
49
|
-
if (event.key === 'Enter' && isPromoCodeHasValue) {
|
|
50
|
-
setShowPromoInput(false)
|
|
51
|
-
updateTickets(true, 'promo')
|
|
52
|
-
}
|
|
53
|
-
}}
|
|
54
|
-
/>
|
|
55
|
-
<Button
|
|
56
|
-
className="promo-submit-button"
|
|
57
|
-
onClick={() => {
|
|
58
|
-
if (isPromoCodeHasValue) {
|
|
59
|
-
setShowPromoInput(false)
|
|
60
|
-
updateTickets(true, 'promo')
|
|
61
|
-
}
|
|
62
|
-
}}
|
|
63
|
-
>
|
|
64
|
-
APPLY
|
|
65
|
-
</Button>
|
|
41
|
+
<p className="promo-code-text">Promo code</p>
|
|
66
42
|
</div>
|
|
67
|
-
|
|
43
|
+
<input
|
|
44
|
+
className="promo-code-input"
|
|
45
|
+
placeholder=""
|
|
46
|
+
onChange={e => {
|
|
47
|
+
setCode(e.target.value)
|
|
48
|
+
}}
|
|
49
|
+
onKeyPress={event => {
|
|
50
|
+
if (event.key === 'Enter' && isPromoCodeHasValue) {
|
|
51
|
+
setShowPromoInput(false)
|
|
52
|
+
updateTickets(true, 'promo')
|
|
53
|
+
}
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
<Button
|
|
57
|
+
className="promo-submit-button"
|
|
58
|
+
onClick={() => {
|
|
59
|
+
if (isPromoCodeHasValue) {
|
|
60
|
+
setShowPromoInput(false)
|
|
61
|
+
updateTickets(true, 'promo')
|
|
62
|
+
}
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
APPLY
|
|
66
|
+
</Button>
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
68
69
|
|
|
69
70
|
return (
|
|
70
71
|
<div>
|
|
@@ -81,6 +82,11 @@ export const PromoCodeSection = ({
|
|
|
81
82
|
<p className="promo-code-success">PROMO CODE APPLIED SUCCESSFULLY</p>
|
|
82
83
|
</div>
|
|
83
84
|
) : null}
|
|
85
|
+
{codeIsApplied ? (
|
|
86
|
+
<div className="alert-info">
|
|
87
|
+
<p className="promo-code-success">PROMO CODE: {appliedPromoCode}</p>
|
|
88
|
+
</div>
|
|
89
|
+
) : null}
|
|
84
90
|
{codeIsInvalid ? (
|
|
85
91
|
<div className="alert-info fail">
|
|
86
92
|
{showAlertIcons && (
|
|
@@ -83,7 +83,7 @@ export const TicketRow = ({
|
|
|
83
83
|
// ticketTier.soldOut === false --> means that ticket is in the stock
|
|
84
84
|
const isSoldOut =
|
|
85
85
|
ticketTier.sold_out ||
|
|
86
|
-
!ticketTier.displayTicket ||
|
|
86
|
+
!(ticketTier.displayTicket || ticketTier.slotGroupId) ||
|
|
87
87
|
ticketTier.soldOut ||
|
|
88
88
|
ticketTier.soldOut === false
|
|
89
89
|
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import './style.css'
|
|
2
3
|
|
|
4
|
+
import _get from 'lodash/get'
|
|
3
5
|
import _sortBy from 'lodash/sortBy'
|
|
4
|
-
import React, { ReactNode } from 'react'
|
|
6
|
+
import React, { ReactNode, useState } from 'react'
|
|
7
|
+
import { Tooltip } from 'react-tooltip'
|
|
5
8
|
|
|
9
|
+
import { FEES_STYLES } from '../../constants'
|
|
10
|
+
import { CONFIGS } from '../../utils'
|
|
11
|
+
import InfoIcon from './InfoIcon'
|
|
6
12
|
import { TicketRow } from './TicketRow'
|
|
7
13
|
|
|
14
|
+
function decodeHTML(html: string): string {
|
|
15
|
+
const textArea = document.createElement('textarea')
|
|
16
|
+
textArea.innerHTML = html
|
|
17
|
+
return textArea.value
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
interface ITicketsSectionProps {
|
|
9
21
|
event: any;
|
|
10
22
|
ticketsList: any;
|
|
@@ -17,12 +29,13 @@ interface ITicketsSectionProps {
|
|
|
17
29
|
ticketsHeaderComponent?: ReactNode;
|
|
18
30
|
tableTicketsHeaderComponent?: ReactNode;
|
|
19
31
|
showGroupNameBlock?: boolean;
|
|
20
|
-
|
|
32
|
+
currencySymbol?: string;
|
|
21
33
|
isSeatMapAllowed?: boolean;
|
|
34
|
+
descriptionTrigger?: 'click' | 'hover';
|
|
22
35
|
}
|
|
23
36
|
|
|
24
37
|
export const TicketsSection = ({
|
|
25
|
-
event
|
|
38
|
+
event,
|
|
26
39
|
ticketsList,
|
|
27
40
|
selectedTickets,
|
|
28
41
|
handleTicketSelect,
|
|
@@ -32,26 +45,37 @@ export const TicketsSection = ({
|
|
|
32
45
|
hideTicketsHeader,
|
|
33
46
|
hideTableTicketsHeader,
|
|
34
47
|
showGroupNameBlock,
|
|
35
|
-
|
|
48
|
+
currencySymbol,
|
|
36
49
|
isSeatMapAllowed,
|
|
37
50
|
tableTickets,
|
|
51
|
+
descriptionTrigger = 'click',
|
|
38
52
|
}: ITicketsSectionProps) => {
|
|
39
|
-
const
|
|
40
|
-
currency: { symbol },
|
|
41
|
-
} = event
|
|
53
|
+
const symbol = _get(event, 'currency.symbol')
|
|
42
54
|
const sortedTicketsList = sortBySoldOut
|
|
43
55
|
? _sortBy(_sortBy(ticketsList, 'sortOrder'), 'soldOut')
|
|
44
56
|
: _sortBy(ticketsList, 'sortOrder')
|
|
45
57
|
const showGroup = !!sortedTicketsList.find(ticket => ticket.groupName)
|
|
46
|
-
const priceSymbol =
|
|
58
|
+
const priceSymbol = currencySymbol || symbol
|
|
59
|
+
|
|
60
|
+
const [visibleDescription, setVisibleDescription] = useState<string | null>(null)
|
|
61
|
+
|
|
62
|
+
const handleDescriptionToggle = (ticketId: string) => {
|
|
63
|
+
setVisibleDescription(current => (current === ticketId ? null : ticketId))
|
|
64
|
+
}
|
|
65
|
+
|
|
47
66
|
return (
|
|
48
67
|
<>
|
|
49
68
|
{!hideTicketsHeader && ticketsHeaderComponent}
|
|
50
69
|
{sortedTicketsList.map((ticket, i, arr) => {
|
|
51
|
-
const
|
|
52
|
-
const
|
|
70
|
+
const ticketPriceWithoutFees = `${priceSymbol} ${(+ticket.cost).toFixed(2)}`
|
|
71
|
+
const ticketPriceWithFees = `${priceSymbol} ${(+ticket.basePrice).toFixed(2)}`
|
|
72
|
+
const ticketOldPriceWithFees = `${priceSymbol} ${(+ticket.oldBasePrice).toFixed(2)}`
|
|
73
|
+
const ticketOldPriceWithoutFees = `${priceSymbol} ${(+ticket.oldCost).toFixed(2)}`
|
|
53
74
|
|
|
54
|
-
const isSoldOut =
|
|
75
|
+
const isSoldOut =
|
|
76
|
+
ticket.sold_out ||
|
|
77
|
+
!(ticket.displayTicket || ticket.slotGroupId) ||
|
|
78
|
+
ticket.soldOut
|
|
55
79
|
const ticketSelect = (event: any) => {
|
|
56
80
|
const { value } = event.target
|
|
57
81
|
handleTicketSelect(ticket.id, value)
|
|
@@ -63,11 +87,15 @@ export const TicketsSection = ({
|
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
const ticketIsFree = +ticket.price === 0
|
|
90
|
+
const discountTicketPriceElem = CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH || !ticket.feeIncluded ?
|
|
91
|
+
ticketOldPriceWithoutFees : ticketOldPriceWithFees
|
|
66
92
|
const ticketPriceElem = isSoldOut
|
|
67
93
|
? 'SOLD OUT'
|
|
68
94
|
: ticketIsFree
|
|
69
|
-
|
|
70
|
-
|
|
95
|
+
? 'FREE'
|
|
96
|
+
: (CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH || !ticket.feeIncluded)
|
|
97
|
+
? ticketPriceWithoutFees
|
|
98
|
+
: ticketPriceWithFees
|
|
71
99
|
const isNewGroupTicket = ticket?.groupName !== arr[i - 1]?.groupName
|
|
72
100
|
|
|
73
101
|
return (
|
|
@@ -77,17 +105,59 @@ export const TicketsSection = ({
|
|
|
77
105
|
{ticket.groupName || ''}
|
|
78
106
|
</div>
|
|
79
107
|
) : null}
|
|
80
|
-
<div
|
|
108
|
+
<div
|
|
109
|
+
className={`event-detail__tier ${isSoldOut ? 'disabled' : ''}`}
|
|
110
|
+
id={ticket.id || ticket.name}
|
|
111
|
+
>
|
|
81
112
|
<div className="event-detail__tier-name">
|
|
82
113
|
{ticket.displayName || ticket.name}
|
|
114
|
+
{ticket.descriptionRich && (
|
|
115
|
+
<>
|
|
116
|
+
<span
|
|
117
|
+
aria-hidden
|
|
118
|
+
className="info-icon"
|
|
119
|
+
onClick={
|
|
120
|
+
descriptionTrigger === 'click'
|
|
121
|
+
? () => handleDescriptionToggle(ticket.id)
|
|
122
|
+
: undefined
|
|
123
|
+
}
|
|
124
|
+
onMouseEnter={
|
|
125
|
+
descriptionTrigger === 'hover'
|
|
126
|
+
? () => setVisibleDescription(ticket.id)
|
|
127
|
+
: undefined
|
|
128
|
+
}
|
|
129
|
+
onMouseLeave={
|
|
130
|
+
descriptionTrigger === 'hover'
|
|
131
|
+
? () => setVisibleDescription(null)
|
|
132
|
+
: undefined
|
|
133
|
+
}
|
|
134
|
+
data-tooltip-id={`tooltip-${ticket.id}`}
|
|
135
|
+
data-tooltip-content="View ticket info"
|
|
136
|
+
style={{
|
|
137
|
+
marginLeft: 8,
|
|
138
|
+
cursor: 'pointer',
|
|
139
|
+
display: 'flex',
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
<InfoIcon />
|
|
143
|
+
</span>
|
|
144
|
+
|
|
145
|
+
<Tooltip id={`tooltip-${ticket.id}`} place="top">
|
|
146
|
+
{ticket.description || 'No description available'}
|
|
147
|
+
</Tooltip>
|
|
148
|
+
</>
|
|
149
|
+
)}
|
|
83
150
|
</div>
|
|
84
151
|
<div className="event-tickets-container">
|
|
85
152
|
<div className="event-detail__tier-price">
|
|
86
|
-
{ticketIsDiscounted && <p className="old-price">{
|
|
153
|
+
{ticketIsDiscounted && <p className="old-price">{discountTicketPriceElem}</p>}
|
|
87
154
|
<p className={isSoldOut ? 'sold-out' : ''}>{ticketPriceElem}</p>
|
|
88
155
|
{!isSoldOut && !ticketIsFree && (
|
|
89
156
|
<p className="fees">
|
|
90
|
-
{
|
|
157
|
+
{CONFIGS.FEES_STYLE === FEES_STYLES.TRADITIONAL &&
|
|
158
|
+
(ticket.feeIncluded ? '(incl. Fees)' : '(excl. Fees)')}
|
|
159
|
+
{CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH &&
|
|
160
|
+
`(${ticketPriceWithFees} with fees)`}
|
|
91
161
|
</p>
|
|
92
162
|
)}
|
|
93
163
|
</div>
|
|
@@ -101,16 +171,30 @@ export const TicketsSection = ({
|
|
|
101
171
|
/>
|
|
102
172
|
</div>
|
|
103
173
|
</div>
|
|
174
|
+
{visibleDescription === ticket.id && (
|
|
175
|
+
<div className="ticket-description">
|
|
176
|
+
<div
|
|
177
|
+
dangerouslySetInnerHTML={{
|
|
178
|
+
__html: decodeHTML(ticket.descriptionRich),
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
104
183
|
</div>
|
|
105
184
|
</React.Fragment>
|
|
106
185
|
)
|
|
107
186
|
})}
|
|
108
187
|
{!hideTableTicketsHeader && tableTicketsHeaderComponent}
|
|
109
188
|
{tableTickets.map((ticket: any, i: any, arr: any) => {
|
|
110
|
-
const
|
|
111
|
-
const
|
|
189
|
+
const ticketPriceWithoutFees = `${priceSymbol} ${(+ticket.cost).toFixed(2)}`
|
|
190
|
+
const ticketPriceWithFees = `${priceSymbol} ${(+ticket.basePrice).toFixed(2)}`
|
|
191
|
+
const ticketOldPriceWithFees = `${priceSymbol} ${(+ticket.oldBasePrice).toFixed(2)}`
|
|
192
|
+
const ticketOldPriceWithoutFees = `${priceSymbol} ${(+ticket.oldCost).toFixed(2)}`
|
|
112
193
|
|
|
113
|
-
const isSoldOut =
|
|
194
|
+
const isSoldOut =
|
|
195
|
+
ticket.sold_out ||
|
|
196
|
+
!(ticket.displayTicket || ticket.slotGroupId) ||
|
|
197
|
+
ticket.soldOut
|
|
114
198
|
const ticketSelect = (event: any) => {
|
|
115
199
|
const { value } = event.target
|
|
116
200
|
handleTicketSelect(ticket.id, value, true)
|
|
@@ -122,53 +206,101 @@ export const TicketsSection = ({
|
|
|
122
206
|
}
|
|
123
207
|
|
|
124
208
|
const ticketIsFree = +ticket.price === 0
|
|
209
|
+
const discountTicketPriceElem = CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH || !ticket.feeIncluded ?
|
|
210
|
+
ticketOldPriceWithoutFees : ticketOldPriceWithFees
|
|
125
211
|
const ticketPriceElem = isSoldOut
|
|
126
212
|
? 'SOLD OUT'
|
|
127
213
|
: ticketIsFree
|
|
128
|
-
|
|
129
|
-
|
|
214
|
+
? 'FREE'
|
|
215
|
+
: (CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH || !ticket.feeIncluded)
|
|
216
|
+
? ticketPriceWithoutFees
|
|
217
|
+
: ticketPriceWithFees
|
|
130
218
|
const isNewGroupTicket = ticket?.groupName !== arr[i - 1]?.groupName
|
|
131
219
|
|
|
132
220
|
return (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
221
|
+
<React.Fragment key={ticket.id || ticket.name}>
|
|
222
|
+
{showGroupNameBlock && showGroup && isNewGroupTicket ? (
|
|
223
|
+
<div className="event-detail__tier group-title">
|
|
224
|
+
{ticket.groupName || ''}
|
|
225
|
+
</div>
|
|
226
|
+
) : null}
|
|
227
|
+
<div
|
|
228
|
+
className={`event-detail__tier ${isSoldOut ? 'disabled' : ''}`}
|
|
229
|
+
id={ticket.id || ticket.name}
|
|
230
|
+
>
|
|
231
|
+
<div className="event-detail__tier-name">
|
|
232
|
+
{ticket.displayName || ticket.name}
|
|
233
|
+
{ticket.descriptionRich && (
|
|
234
|
+
<>
|
|
235
|
+
<span
|
|
236
|
+
aria-hidden
|
|
237
|
+
className="info-icon"
|
|
238
|
+
onClick={
|
|
239
|
+
descriptionTrigger === 'click'
|
|
240
|
+
? () => handleDescriptionToggle(ticket.id)
|
|
241
|
+
: undefined
|
|
242
|
+
}
|
|
243
|
+
onMouseEnter={
|
|
244
|
+
descriptionTrigger === 'hover'
|
|
245
|
+
? () => setVisibleDescription(ticket.id)
|
|
246
|
+
: undefined
|
|
247
|
+
}
|
|
248
|
+
onMouseLeave={
|
|
249
|
+
descriptionTrigger === 'hover'
|
|
250
|
+
? () => setVisibleDescription(null)
|
|
251
|
+
: undefined
|
|
252
|
+
}
|
|
253
|
+
style={{ marginLeft: 8, cursor: 'pointer', display: 'flex' }}
|
|
254
|
+
data-tooltip-id={`tooltip-${ticket.id}`}
|
|
255
|
+
data-tooltip-content="View ticket info"
|
|
256
|
+
>
|
|
257
|
+
<InfoIcon />
|
|
258
|
+
</span>
|
|
259
|
+
<Tooltip id={`tooltip-${ticket.id}`} place="top">
|
|
260
|
+
{ticket.description || 'No description available'}
|
|
261
|
+
</Tooltip>
|
|
262
|
+
</>
|
|
263
|
+
)}
|
|
264
|
+
</div>
|
|
265
|
+
<div className="event-tickets-container">
|
|
266
|
+
<div className="event-detail__tier-price">
|
|
267
|
+
{ticketIsDiscounted && <p className="old-price">{discountTicketPriceElem}</p>}
|
|
268
|
+
<p className={isSoldOut ? 'sold-out' : ''}>{ticketPriceElem}</p>
|
|
269
|
+
{!isSoldOut && !ticketIsFree && (
|
|
270
|
+
<p className="fees">
|
|
271
|
+
{CONFIGS.FEES_STYLE === FEES_STYLES.TRADITIONAL &&
|
|
272
|
+
(ticket.feeIncluded ? '(incl. Fees)' : '(excl. Fees)')}
|
|
273
|
+
{CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH &&
|
|
274
|
+
`(${ticketPriceWithFees} with fees)`}
|
|
275
|
+
</p>
|
|
276
|
+
)}
|
|
277
|
+
{ticket.depositPercent && (
|
|
278
|
+
<p className="deposits">{ticket.depositPercent + '% DEPOSIT'}</p>
|
|
279
|
+
)}
|
|
143
280
|
</div>
|
|
144
|
-
<div className="event-
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
<p className="deposits">{ticket.depositPercent + '% DEPOSIT'}</p>
|
|
155
|
-
)}
|
|
156
|
-
</div>
|
|
157
|
-
<div className="event-detail__tier-state" style={{ minWidth: 55 }}>
|
|
158
|
-
<TicketRow
|
|
159
|
-
tableType={true}
|
|
160
|
-
ticketTier={ticket}
|
|
161
|
-
prevTicketTier={arr[i - 1]}
|
|
162
|
-
selectedTickets={selectedTickets}
|
|
163
|
-
handleTicketSelect={ticketSelect}
|
|
164
|
-
isSeatMapAllowed={isSeatMapAllowed}
|
|
165
|
-
event={event}
|
|
166
|
-
/>
|
|
167
|
-
</div>
|
|
281
|
+
<div className="event-detail__tier-state" style={{ minWidth: 55 }}>
|
|
282
|
+
<TicketRow
|
|
283
|
+
tableType={true}
|
|
284
|
+
ticketTier={ticket}
|
|
285
|
+
prevTicketTier={arr[i - 1]}
|
|
286
|
+
selectedTickets={selectedTickets}
|
|
287
|
+
handleTicketSelect={ticketSelect}
|
|
288
|
+
isSeatMapAllowed={isSeatMapAllowed}
|
|
289
|
+
event={event}
|
|
290
|
+
/>
|
|
168
291
|
</div>
|
|
169
292
|
</div>
|
|
170
|
-
|
|
171
|
-
|
|
293
|
+
{visibleDescription === ticket.id && (
|
|
294
|
+
<div className="ticket-description">
|
|
295
|
+
<div
|
|
296
|
+
dangerouslySetInnerHTML={{
|
|
297
|
+
__html: decodeHTML(ticket.descriptionRich),
|
|
298
|
+
}}
|
|
299
|
+
/>
|
|
300
|
+
</div>
|
|
301
|
+
)}
|
|
302
|
+
</div>
|
|
303
|
+
</React.Fragment>
|
|
172
304
|
)
|
|
173
305
|
})}
|
|
174
306
|
</>
|