tf-checkout-react 1.0.99-beta.19 → 1.0.99-beta.21
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 +2 -0
- package/dist/components/common/CustomField.d.ts +1 -1
- package/dist/components/common/DatePickerField.d.ts +14 -0
- package/dist/components/rsvpContainer/index.d.ts +7 -0
- package/dist/components/ticketResale/index.d.ts +3 -1
- package/dist/components/timerWidget/index.d.ts +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/tf-checkout-react.cjs.development.js +306 -38
- 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 +308 -41
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +7 -0
- package/src/components/billing-info-container/index.tsx +3 -0
- package/src/components/billing-info-container/utils.ts +1 -0
- package/src/components/common/CustomField.tsx +6 -6
- package/src/components/common/DatePickerField.tsx +96 -0
- package/src/components/rsvpContainer/index.tsx +126 -0
- package/src/components/ticketResale/index.tsx +23 -4
- package/src/components/ticketsContainer/index.tsx +4 -3
- package/src/components/timerWidget/index.tsx +2 -2
- package/src/index.ts +1 -0
package/package.json
CHANGED
package/src/api/index.ts
CHANGED
|
@@ -304,3 +304,10 @@ export const logout = () => publicRequest.delete('/auth')
|
|
|
304
304
|
export const processTicket = (hash: string) => {
|
|
305
305
|
return publicRequest.post(`v1/ticket/${hash}/process/`)
|
|
306
306
|
}
|
|
307
|
+
|
|
308
|
+
export const declineInvitation = (hash: string) => {
|
|
309
|
+
return publicRequest.post(`v1/ticket/${hash}/decline`)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export const sendRSVPInfo = (eventId: number, data: any) =>
|
|
313
|
+
publicRequest.post(`v1/event/${eventId}/send-rsvp-info`, data)
|
|
@@ -50,6 +50,7 @@ import { CSSProperties } from '@mui/styles'
|
|
|
50
50
|
import Backdrop from '@mui/material/Backdrop'
|
|
51
51
|
import TimerWidget from '../timerWidget'
|
|
52
52
|
import SnackbarAlert from '../common/SnackbarAlert'
|
|
53
|
+
import { DatePickerField } from '../common/DatePickerField'
|
|
53
54
|
|
|
54
55
|
export interface IBillingInfoPage {
|
|
55
56
|
data?: IBillingInfoData[];
|
|
@@ -680,6 +681,8 @@ export const BillingInfoContainer = ({
|
|
|
680
681
|
? SelectField
|
|
681
682
|
: element.type === 'phone'
|
|
682
683
|
? FormikPhoneNumberField
|
|
684
|
+
: element.type === 'date'
|
|
685
|
+
? DatePickerField
|
|
683
686
|
: CustomField
|
|
684
687
|
}
|
|
685
688
|
selectOptions={
|
|
@@ -63,6 +63,7 @@ export const createRegisterFormData = (
|
|
|
63
63
|
'client_secret',
|
|
64
64
|
CONFIGS.CLIENT_SECRET || 'b89c191eff22fdcf84ac9bfd88d005355a151ec2c83b26b9'
|
|
65
65
|
)
|
|
66
|
+
bodyFormData.append('check_cart_expiration', 'true')
|
|
66
67
|
|
|
67
68
|
_forEach(checkoutBody.attributes, (item: any, key: string) => {
|
|
68
69
|
bodyFormData.append(key, item)
|
|
@@ -3,7 +3,6 @@ import TextField from '@mui/material/TextField'
|
|
|
3
3
|
import _map from 'lodash/map'
|
|
4
4
|
import _get from 'lodash/get'
|
|
5
5
|
import _includes from 'lodash/includes'
|
|
6
|
-
import moment from 'moment-timezone'
|
|
7
6
|
|
|
8
7
|
import { FieldInputProps, FormikProps } from 'formik'
|
|
9
8
|
import { useTheme } from '@mui/styles'
|
|
@@ -37,6 +36,9 @@ export const CustomField = ({
|
|
|
37
36
|
selectOptions = [] as ISelectOption[],
|
|
38
37
|
form: { touched, errors, submitCount },
|
|
39
38
|
theme,
|
|
39
|
+
inputProps: pInputProps = {},
|
|
40
|
+
InputProps = {},
|
|
41
|
+
inputRef,
|
|
40
42
|
}: ICustomField & IOtherProps) => {
|
|
41
43
|
const isSelectField = type === 'select'
|
|
42
44
|
const error = _get(errors, field.name)
|
|
@@ -46,9 +48,6 @@ export const CustomField = ({
|
|
|
46
48
|
|
|
47
49
|
const customTheme: any = useTheme()
|
|
48
50
|
const inputProps: any = { sx: customTheme?.input }
|
|
49
|
-
if (type === 'date') {
|
|
50
|
-
inputProps.max = moment().format('YYYY-MM-DD')
|
|
51
|
-
}
|
|
52
51
|
|
|
53
52
|
return (
|
|
54
53
|
<TextField
|
|
@@ -66,9 +65,10 @@ export const CustomField = ({
|
|
|
66
65
|
}}
|
|
67
66
|
InputLabelProps={{
|
|
68
67
|
sx: customTheme?.input,
|
|
69
|
-
shrink: field.name === 'holderAge' ? true : undefined,
|
|
70
68
|
}}
|
|
71
|
-
|
|
69
|
+
InputProps={InputProps}
|
|
70
|
+
inputProps={{ ...inputProps, ...pInputProps }}
|
|
71
|
+
inputRef={inputRef}
|
|
72
72
|
{...field}
|
|
73
73
|
>
|
|
74
74
|
{isSelectField
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import DatePicker from '@mui/lab/DatePicker'
|
|
3
|
+
import AdapterMoment from '@mui/lab/AdapterMoment'
|
|
4
|
+
import LocalizationProvider from '@mui/lab/LocalizationProvider'
|
|
5
|
+
import { ThemeProvider, createTheme } from '@mui/material/styles'
|
|
6
|
+
import { FieldInputProps, FormikProps } from 'formik'
|
|
7
|
+
import _get from 'lodash/get'
|
|
8
|
+
import { CustomField } from './CustomField'
|
|
9
|
+
|
|
10
|
+
const DATE_SIZE = 32
|
|
11
|
+
const compactStyles = {
|
|
12
|
+
'& > div': {
|
|
13
|
+
minWidth: 256,
|
|
14
|
+
},
|
|
15
|
+
'& > div > div, & > div > div > div, & .MuiCalendarPicker-root': {
|
|
16
|
+
width: 256,
|
|
17
|
+
},
|
|
18
|
+
'& .MuiTypography-caption': {
|
|
19
|
+
width: DATE_SIZE,
|
|
20
|
+
margin: 0,
|
|
21
|
+
},
|
|
22
|
+
'& .PrivatePickersSlideTransition-root': {
|
|
23
|
+
minHeight: DATE_SIZE * 6,
|
|
24
|
+
},
|
|
25
|
+
'& .PrivatePickersSlideTransition-root [role="row"]': {
|
|
26
|
+
margin: 0,
|
|
27
|
+
},
|
|
28
|
+
'& .MuiPickersDay-dayWithMargin': {
|
|
29
|
+
margin: 0,
|
|
30
|
+
},
|
|
31
|
+
'& .MuiPickersDay-root': {
|
|
32
|
+
width: DATE_SIZE,
|
|
33
|
+
height: DATE_SIZE,
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const compactStyleTheme = createTheme({
|
|
38
|
+
components: {
|
|
39
|
+
MuiPaper: {
|
|
40
|
+
defaultProps: {
|
|
41
|
+
sx: compactStyles
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
export interface IDatePickerFieldProps {
|
|
48
|
+
label: string
|
|
49
|
+
|
|
50
|
+
field: FieldInputProps<any>
|
|
51
|
+
form: FormikProps<any>
|
|
52
|
+
theme: 'dark' | 'light'
|
|
53
|
+
|
|
54
|
+
useCompact?: boolean
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface IOtherProps {
|
|
58
|
+
[key: string]: any
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const DatePickerField = ({
|
|
62
|
+
label,
|
|
63
|
+
field,
|
|
64
|
+
form,
|
|
65
|
+
theme,
|
|
66
|
+
useCompact = true,
|
|
67
|
+
}: IDatePickerFieldProps & IOtherProps) => {
|
|
68
|
+
return (
|
|
69
|
+
<ThemeProvider theme={useCompact ? compactStyleTheme : {}}>
|
|
70
|
+
<LocalizationProvider dateAdapter={AdapterMoment}>
|
|
71
|
+
<DatePicker
|
|
72
|
+
value={field.value || ''}
|
|
73
|
+
onChange={value => form.setFieldValue(field.name, value)}
|
|
74
|
+
PopperProps={{
|
|
75
|
+
placement: 'bottom-start',
|
|
76
|
+
}}
|
|
77
|
+
showDaysOutsideCurrentMonth={true}
|
|
78
|
+
disableFuture={true}
|
|
79
|
+
renderInput={params => {
|
|
80
|
+
return (
|
|
81
|
+
<CustomField
|
|
82
|
+
{...params}
|
|
83
|
+
inputProps={{ ...params.inputProps, placeholder: 'dd/mm/yyyy' }}
|
|
84
|
+
theme={theme}
|
|
85
|
+
field={field}
|
|
86
|
+
form={form}
|
|
87
|
+
label={label}
|
|
88
|
+
type="tel"
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
</LocalizationProvider>
|
|
94
|
+
</ThemeProvider>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { Field, Form, Formik } from 'formik'
|
|
3
|
+
import Button from '@mui/material/Button'
|
|
4
|
+
import Modal from '@mui/material/Modal'
|
|
5
|
+
import Box from '@mui/material/Box'
|
|
6
|
+
import { CustomField, Loader } from '../common/index'
|
|
7
|
+
import { combineValidators, requiredValidator, emailValidator } from '../../validators'
|
|
8
|
+
import { sendRSVPInfo } from '../../api'
|
|
9
|
+
|
|
10
|
+
interface IRsvpContainerPage {
|
|
11
|
+
showSection?: boolean;
|
|
12
|
+
eventId: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IRSVPValuesTypes {
|
|
16
|
+
email: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const style: React.CSSProperties = {
|
|
20
|
+
position: 'absolute',
|
|
21
|
+
top: '50%',
|
|
22
|
+
left: '50%',
|
|
23
|
+
transform: 'translate(-50%, -50%)',
|
|
24
|
+
minWidth: 480,
|
|
25
|
+
backgroundColor: '#e3e3e3',
|
|
26
|
+
border: '1px solid white',
|
|
27
|
+
outline: 'none',
|
|
28
|
+
padding: '14px',
|
|
29
|
+
maxHeight: '85vh',
|
|
30
|
+
overflow: 'auto'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const RsvpContainer = ({ showSection = false, eventId }: IRsvpContainerPage) => {
|
|
34
|
+
const userDataEncoded =
|
|
35
|
+
typeof window !== 'undefined' ? window.localStorage.getItem('user_data') : ''
|
|
36
|
+
const parsedData = JSON.parse(userDataEncoded || '{}')
|
|
37
|
+
|
|
38
|
+
const [loading, setLoading] = useState(false)
|
|
39
|
+
const [modal, setModal] = useState({ isOpen: false, text: '' })
|
|
40
|
+
|
|
41
|
+
const handleModalClose = () => {
|
|
42
|
+
setModal({ isOpen: false, text: '' })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const handleSubmit = async (values: IRSVPValuesTypes) => {
|
|
46
|
+
try {
|
|
47
|
+
setLoading(true)
|
|
48
|
+
|
|
49
|
+
const requestData = {
|
|
50
|
+
data: {
|
|
51
|
+
email: values.email
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const { data } = await sendRSVPInfo(eventId, requestData)
|
|
55
|
+
|
|
56
|
+
setModal({ isOpen: true, text: data.message })
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (error.response.status === 403) {
|
|
59
|
+
setModal({ isOpen: true, text: error.response.data?.message })
|
|
60
|
+
}
|
|
61
|
+
} finally {
|
|
62
|
+
setLoading(false)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!showSection) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<Modal
|
|
73
|
+
open={modal.isOpen}
|
|
74
|
+
onClose={handleModalClose}
|
|
75
|
+
aria-labelledby="modal-modal-title"
|
|
76
|
+
aria-describedby="modal-modal-description"
|
|
77
|
+
className="rsvp-modal"
|
|
78
|
+
>
|
|
79
|
+
<Box style={style} className="rsvp-modal-box">
|
|
80
|
+
<div className="rsvp-modal-container">
|
|
81
|
+
<div className="rsvp-modal-header">{modal.text}</div>
|
|
82
|
+
<div className="rsvp-modal-button">
|
|
83
|
+
<button onClick={handleModalClose}>OK</button>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</Box>
|
|
87
|
+
</Modal>
|
|
88
|
+
<div className="rsvp-container">
|
|
89
|
+
{loading ? (
|
|
90
|
+
<Loader />
|
|
91
|
+
) : (
|
|
92
|
+
<>
|
|
93
|
+
<div className="rsvp-header">RSVP</div>
|
|
94
|
+
<div className="rsvp-email-container">
|
|
95
|
+
<Formik
|
|
96
|
+
initialValues={{
|
|
97
|
+
email: parsedData?.email || ''
|
|
98
|
+
}}
|
|
99
|
+
onSubmit={handleSubmit}
|
|
100
|
+
enableReinitialize
|
|
101
|
+
>
|
|
102
|
+
<Form>
|
|
103
|
+
<div className="rsvp-email-input-container">
|
|
104
|
+
<Field
|
|
105
|
+
name="email"
|
|
106
|
+
label="EMAIL ADDRESS"
|
|
107
|
+
type="email"
|
|
108
|
+
validate={combineValidators(
|
|
109
|
+
(value: string) => requiredValidator(value, 'Please enter your Email'),
|
|
110
|
+
(value: string) => emailValidator(value)
|
|
111
|
+
)}
|
|
112
|
+
component={CustomField}
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
<div className="rsvp-button-container">
|
|
116
|
+
<Button type="submit">RSVP</Button>
|
|
117
|
+
</div>
|
|
118
|
+
</Form>
|
|
119
|
+
</Formik>
|
|
120
|
+
</div>
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
</>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react'
|
|
2
2
|
import _get from 'lodash/get'
|
|
3
|
-
import { processTicket } from '../../api'
|
|
3
|
+
import { processTicket, declineInvitation } from '../../api'
|
|
4
4
|
import { AxiosError } from 'axios'
|
|
5
5
|
|
|
6
6
|
export interface ITicketResaleContainer {
|
|
7
7
|
onProcessTicketSuccess: (res: any) => void
|
|
8
8
|
onProcessTicketError: (e: AxiosError) => void
|
|
9
|
+
onDeclineTicketPurchaseSuccess: (res: any) => void
|
|
10
|
+
onDeclineTicketPurchaseError: (e: AxiosError) => void
|
|
9
11
|
orderHash?: string
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export const TicketResaleContainer = ({
|
|
13
15
|
onProcessTicketSuccess = () => {},
|
|
14
16
|
onProcessTicketError = () => {},
|
|
17
|
+
onDeclineTicketPurchaseSuccess = () => {},
|
|
18
|
+
onDeclineTicketPurchaseError = () => {},
|
|
15
19
|
orderHash,
|
|
16
20
|
}: ITicketResaleContainer) => {
|
|
17
21
|
const isWindowDefined = typeof window !== 'undefined'
|
|
18
|
-
const [error, setError] = useState(
|
|
22
|
+
const [error, setError] = useState('')
|
|
23
|
+
const [successMessage, setSuccessMessage] = useState('')
|
|
19
24
|
|
|
20
25
|
useEffect(() => {
|
|
21
26
|
(async () => {
|
|
@@ -23,8 +28,22 @@ export const TicketResaleContainer = ({
|
|
|
23
28
|
const params: URLSearchParams = new URL(`${window.location}`)
|
|
24
29
|
.searchParams
|
|
25
30
|
const hash = params.get('invitation_hash') || orderHash || null
|
|
31
|
+
const isDeclined = params.get('decline') || false
|
|
26
32
|
|
|
27
33
|
if (hash) {
|
|
34
|
+
// Process of declining ticket purchase invitation
|
|
35
|
+
if (isDeclined) {
|
|
36
|
+
try {
|
|
37
|
+
const response = await declineInvitation(hash)
|
|
38
|
+
onDeclineTicketPurchaseSuccess(response)
|
|
39
|
+
setSuccessMessage("Thanks for letting us know! We'll offer this ticket to someone else!")
|
|
40
|
+
} catch (error) {
|
|
41
|
+
setError(error?.response?.data?.message)
|
|
42
|
+
onDeclineTicketPurchaseError(error.response)
|
|
43
|
+
}
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
28
47
|
try {
|
|
29
48
|
const response = await processTicket(hash)
|
|
30
49
|
const data = _get(response, 'data.data.attributes')
|
|
@@ -47,8 +66,8 @@ export const TicketResaleContainer = ({
|
|
|
47
66
|
|
|
48
67
|
return (
|
|
49
68
|
<div className="ticket-resale-page">
|
|
50
|
-
<div className=
|
|
51
|
-
<h3>{error}</h3>
|
|
69
|
+
<div className={`${successMessage ? 'success-block': 'error-block'}`}>
|
|
70
|
+
<h3>{successMessage ? successMessage : error}</h3>
|
|
52
71
|
</div>
|
|
53
72
|
</div>
|
|
54
73
|
)
|
|
@@ -389,7 +389,8 @@ export const TicketsContainer = ({
|
|
|
389
389
|
Object.values(selectedTickets)[0] === 0
|
|
390
390
|
|
|
391
391
|
const wrappedActionsSectionComponent = React.isValidElement(ActionsSectionComponent) ? React.cloneElement(ActionsSectionComponent as React.ReactElement<any>, {
|
|
392
|
-
handleGetTicketClick
|
|
392
|
+
handleGetTicketClick,
|
|
393
|
+
isTicketOnSale
|
|
393
394
|
}) : null
|
|
394
395
|
|
|
395
396
|
const externalUrl = event?.redirectUrl
|
|
@@ -450,8 +451,8 @@ export const TicketsContainer = ({
|
|
|
450
451
|
/>
|
|
451
452
|
) : null
|
|
452
453
|
}
|
|
453
|
-
{wrappedActionsSectionComponent}
|
|
454
|
-
{!wrappedActionsSectionComponent && !eventSaleIsNotStarted &&
|
|
454
|
+
{wrappedActionsSectionComponent}
|
|
455
|
+
{!wrappedActionsSectionComponent && !eventSaleIsNotStarted && isTicketOnSale && !event?.salesEnded && !externalUrl && (
|
|
455
456
|
<Button
|
|
456
457
|
aria-hidden={true}
|
|
457
458
|
className={`book-button
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react'
|
|
1
|
+
import React, { useState, memo } from 'react'
|
|
2
2
|
import Countdown from 'react-countdown'
|
|
3
3
|
import { showZero } from '../../utils/showZero'
|
|
4
4
|
import { getImage } from '../../utils/getImage'
|
|
@@ -84,4 +84,4 @@ const TimerWidget = ({
|
|
|
84
84
|
) : null
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export default TimerWidget
|
|
87
|
+
export default memo(TimerWidget)
|
package/src/index.ts
CHANGED
|
@@ -12,3 +12,4 @@ export { OrderDetailsContainer } from './components/orderDetailsContainer'
|
|
|
12
12
|
export { setConfigs } from './utils/setConfigs'
|
|
13
13
|
export { TicketResaleContainer } from './components'
|
|
14
14
|
export { RedirectModal } from './components/common/RedirectModal'
|
|
15
|
+
export { RsvpContainer } from './components/rsvpContainer'
|