tf-checkout-react 1.3.11 → 1.3.12-beta.2

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 +1 -0
  2. package/dist/components/billing-info-container/index.d.ts +1 -3
  3. package/dist/components/forgotPasswordModal/index.d.ts +4 -5
  4. package/dist/components/loginForm/index.d.ts +45 -0
  5. package/dist/components/loginModal/index.d.ts +5 -43
  6. package/dist/components/preRegistration/FieldsSection.d.ts +13 -0
  7. package/dist/components/preRegistration/constants.d.ts +2 -0
  8. package/dist/components/preRegistration/index.d.ts +10 -0
  9. package/dist/components/preRegistration/utils.d.ts +9 -0
  10. package/dist/hooks/useCookieListener.d.ts +1 -0
  11. package/dist/hooks/useEventListener.d.ts +1 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/tf-checkout-react.cjs.development.js +706 -90
  14. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  15. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  16. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  17. package/dist/tf-checkout-react.esm.js +707 -92
  18. package/dist/tf-checkout-react.esm.js.map +1 -1
  19. package/dist/utils/index.d.ts +1 -0
  20. package/dist/utils/replaceVarInString.d.ts +1 -0
  21. package/package.json +1 -1
  22. package/src/.DS_Store +0 -0
  23. package/src/api/index.ts +15 -0
  24. package/src/components/.DS_Store +0 -0
  25. package/src/components/billing-info-container/index.tsx +9 -8
  26. package/src/components/common/SelectField.tsx +1 -1
  27. package/src/components/common/dist/PhoneNumberField.js +96 -0
  28. package/src/components/forgotPasswordModal/index.tsx +12 -14
  29. package/src/components/loginForm/index.tsx +195 -0
  30. package/src/components/loginModal/index.tsx +39 -184
  31. package/src/components/preRegistration/FieldsSection.tsx +136 -0
  32. package/src/components/preRegistration/constants.tsx +155 -0
  33. package/src/components/preRegistration/index.tsx +219 -0
  34. package/src/components/preRegistration/utils.ts +95 -0
  35. package/src/hooks/useCookieListener.ts +32 -0
  36. package/src/hooks/useEventListener.ts +32 -0
  37. package/src/index.ts +2 -1
  38. package/src/types/api/auth.d.ts +55 -0
  39. package/src/types/api/preRegistration.d.ts +11 -0
  40. package/src/types/formFields.d.ts +30 -0
  41. package/src/utils/cookies.ts +7 -7
  42. package/src/utils/index.ts +1 -0
  43. package/src/utils/replaceVarInString.ts +9 -0
@@ -0,0 +1,219 @@
1
+ import { Button, CircularProgress } from '@mui/material'
2
+ import axios from 'axios'
3
+ import { Form, Formik, FormikValues } from 'formik'
4
+ import _get from 'lodash/get'
5
+ import _identity from 'lodash/identity'
6
+ import _map from 'lodash/map'
7
+ import React, { FC, useEffect, useState } from 'react'
8
+
9
+ import { confirmPreRegistration, getCountries, register } from '../../api'
10
+ import { useCookieListener } from '../../hooks/useCookieListener'
11
+ import { getCookieByName } from '../../utils'
12
+ import SnackbarAlert from '../common/SnackbarAlert'
13
+ import {
14
+ ForgotPasswordModal,
15
+ IForgotPasswordProps,
16
+ } from '../forgotPasswordModal'
17
+ import { ILoginModalProps, LoginModal } from '../loginModal'
18
+ import { formFieldsLoggedIn, formFieldsNotLoggedIn } from './constants'
19
+ import { FieldsSection } from './FieldsSection'
20
+ import { getFormInitialValues, updateFormFieldsAttributes } from './utils'
21
+
22
+ const X_TF_ECOMMERCE = 'X-TF-ECOMMERCE'
23
+
24
+ interface IPreRegistrationProps extends ILoginModalProps, IForgotPasswordProps {
25
+ eventId: string | number;
26
+ formFields?: IFormFieldsSection[];
27
+ additionalFieldAttribute?: IFieldAttribute;
28
+ }
29
+
30
+ export const PreRegistration: FC<IPreRegistrationProps> = ({
31
+ eventId,
32
+ formFields: pFormFields,
33
+ additionalFieldAttribute,
34
+
35
+ logo,
36
+ showForgotPasswordButton,
37
+ onLoginSuccess = _identity,
38
+ onForgotPasswordSuccess = _identity,
39
+ onForgotPasswordError = _identity,
40
+ }) => {
41
+ const [error, setError] = useState('')
42
+ const [showModalLogin, setShowModalLogin] = useState(false)
43
+ const [showModalForgotPassword, setShowModalForgotPassword] = useState(false)
44
+ const [countries, setCountries] = useState<
45
+ { [key: string]: string | number }[]
46
+ >([])
47
+ const [isLoggedIn, setIsLoggedIn] = useState(
48
+ Boolean(getCookieByName(X_TF_ECOMMERCE))
49
+ )
50
+ useCookieListener(X_TF_ECOMMERCE, value => setIsLoggedIn(Boolean(value)))
51
+
52
+ const formFields = updateFormFieldsAttributes(
53
+ pFormFields || isLoggedIn ? formFieldsLoggedIn : formFieldsNotLoggedIn,
54
+ additionalFieldAttribute
55
+ )
56
+
57
+ useEffect(() => {
58
+ // fetch countries data
59
+ const fetchCountries = async () => {
60
+ try {
61
+ const res = await getCountries()
62
+ setCountries(
63
+ _map(_get(res, 'data.data'), (item, key) => ({
64
+ label: item,
65
+ value: key,
66
+ }))
67
+ )
68
+ // onGetCountriesSuccess(res.data)
69
+ } catch (e) {
70
+ if (axios.isAxiosError(e)) {
71
+ const error = e?.response?.data?.message || 'Error'
72
+ setError(error)
73
+ // onGetCountriesError(e)
74
+ }
75
+ }
76
+ }
77
+ fetchCountries()
78
+ }, [])
79
+
80
+ return (
81
+ <div className="pre-registration-container">
82
+ <SnackbarAlert
83
+ type="error"
84
+ isOpen={!!error}
85
+ message={error || ''}
86
+ onClose={() => {
87
+ setError('')
88
+ }}
89
+ />
90
+ {!isLoggedIn && (
91
+ <div className="account-actions-block">
92
+ <div className="action-item">
93
+ <div>
94
+ Got a <strong>MANA Common</strong> account?
95
+ </div>
96
+ <div>Login & skip ahead:</div>
97
+ </div>
98
+ <div className="action-item login-block">
99
+ <button
100
+ className="login-register-button"
101
+ type="button"
102
+ onClick={() => {
103
+ setShowModalLogin(true)
104
+ }}
105
+ >
106
+ Login
107
+ </button>
108
+ </div>
109
+ </div>
110
+ )}
111
+ {showModalLogin && (
112
+ <LoginModal
113
+ logo={logo}
114
+ onClose={() => {
115
+ setShowModalLogin(false)
116
+ }}
117
+ onLogin={res => {
118
+ setShowModalLogin(false)
119
+ onLoginSuccess(res)
120
+ }}
121
+ showForgotPasswordButton={showForgotPasswordButton}
122
+ onForgotPassword={() => {
123
+ setShowModalLogin(false)
124
+ setShowModalForgotPassword(true)
125
+ }}
126
+ />
127
+ )}
128
+ {showModalForgotPassword && (
129
+ <ForgotPasswordModal
130
+ onClose={() => {
131
+ setShowModalForgotPassword(false)
132
+ }}
133
+ onLoginButtonClick={() => {
134
+ setShowModalForgotPassword(false)
135
+ setShowModalLogin(true)
136
+ }}
137
+ onForgotPasswordSuccess={onForgotPasswordSuccess}
138
+ onForgotPasswordError={onForgotPasswordError}
139
+ />
140
+ )}
141
+ <h2>Pre-Registration</h2>
142
+ <Formik
143
+ initialValues={getFormInitialValues(formFields)}
144
+ enableReinitialize={true}
145
+ onSubmit={async (values: FormikValues) => {
146
+ try {
147
+ if (isLoggedIn) {
148
+ const updatedValues = { ...values }
149
+ const holderAgeDate = new Date(values.holderAge)
150
+ updatedValues.dobDay = holderAgeDate.getDate()
151
+ updatedValues.dobMonth = holderAgeDate.getMonth() + 1
152
+ updatedValues.dobYear = holderAgeDate.getFullYear()
153
+ // remove date picker string value
154
+ delete updatedValues.holderAge
155
+
156
+ await confirmPreRegistration(
157
+ eventId,
158
+ updatedValues as IConfirmPreRegistrationRequestData
159
+ )
160
+ } else {
161
+ const bodyFormData = new FormData()
162
+ bodyFormData.append('first_name', values.firstName)
163
+ bodyFormData.append('last_name', values.lastName)
164
+ bodyFormData.append('email', values.email)
165
+ bodyFormData.append('confirm_email', values.confirmEmail)
166
+ bodyFormData.append('zip', values.zip)
167
+ bodyFormData.append('country', values.country)
168
+ bodyFormData.append('password', values.password)
169
+ bodyFormData.append(
170
+ 'password_confirmation',
171
+ values.confirmPassword
172
+ )
173
+ bodyFormData.append('register_for', 'prereg')
174
+
175
+ await register(bodyFormData)
176
+ }
177
+ } catch (e) {
178
+ if (axios.isAxiosError(e)) {
179
+ const error = e?.response?.data?.message || 'Error'
180
+ setError(error)
181
+ } else if (e instanceof Error) {
182
+ setError(e?.message || 'Error')
183
+ }
184
+ }
185
+ }}
186
+ >
187
+ {props => (
188
+ <Form>
189
+ <div className="login-modal-body">
190
+ <FieldsSection
191
+ formFields={formFields}
192
+ values={props.values}
193
+ setFieldValue={props.setFieldValue}
194
+ containerClass="pre-registration"
195
+ countries={countries}
196
+ />
197
+ </div>
198
+ <div className="button-container">
199
+ <Button
200
+ type="submit"
201
+ variant="contained"
202
+ className="login-register-button"
203
+ disabled={props.isSubmitting}
204
+ >
205
+ {props.isSubmitting ? (
206
+ <CircularProgress size={26} />
207
+ ) : isLoggedIn ? (
208
+ 'Confirm Pre-Registration'
209
+ ) : (
210
+ 'Create Account'
211
+ )}
212
+ </Button>
213
+ </div>
214
+ </Form>
215
+ )}
216
+ </Formik>
217
+ </div>
218
+ )
219
+ }
@@ -0,0 +1,95 @@
1
+ import { FormikValues } from 'formik'
2
+ import _forEach from 'lodash/forEach'
3
+ import _get from 'lodash/get'
4
+ import _isEmpty from 'lodash/isEmpty'
5
+ import _map from 'lodash/map'
6
+
7
+ import { combineValidators, requiredValidator } from '../../validators'
8
+
9
+ export const getValidateFunctions = ({
10
+ element,
11
+ values,
12
+ }: {
13
+ element: IFormField;
14
+ values: FormikValues;
15
+ }) => {
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ const validationFunctions: any[] = []
18
+ if (element.required) {
19
+ validationFunctions.push(requiredValidator)
20
+ }
21
+
22
+ if (element.onValidate) {
23
+ validationFunctions.push(element.onValidate)
24
+ }
25
+
26
+ if (element.name === 'confirmEmail') {
27
+ const isSameEmail = (confirmEmail?: string) =>
28
+ values.email !== confirmEmail
29
+ ? 'Please confirm your email address correctly'
30
+ : null
31
+ validationFunctions.push(isSameEmail)
32
+ }
33
+
34
+ if (element.name === 'confirmPassword') {
35
+ const isSame = (confirmPassword?: string) =>
36
+ values.password !== confirmPassword
37
+ ? 'Password confirmation does not match'
38
+ : null
39
+ validationFunctions.push(isSame)
40
+ }
41
+
42
+ return combineValidators(...validationFunctions)
43
+ }
44
+
45
+ export const getFormInitialValues = (fieldsSections: IFormFieldsSection[]) => {
46
+ const initialValues: { [key: string]: string | number | boolean } = {}
47
+ const isWindowDefined = typeof window !== 'undefined'
48
+ const userData = JSON.parse(
49
+ isWindowDefined ? window.localStorage.getItem('user_data') || '{}' : '{}'
50
+ ) as IProfileData
51
+
52
+ _forEach(fieldsSections, item => {
53
+ _forEach(item.fields, fieldItem => {
54
+ switch (fieldItem.name) {
55
+ case 'country':
56
+ case 'numTickets':
57
+ initialValues[fieldItem.name] = 1
58
+ break
59
+ case 'brandOptIn':
60
+ initialValues[fieldItem.name] = true
61
+ break
62
+ default:
63
+ initialValues[fieldItem.name] = _get(userData, fieldItem.name) || ''
64
+ break
65
+ }
66
+ })
67
+ })
68
+
69
+ return initialValues
70
+ }
71
+
72
+ export const updateFormFieldsAttributes = (
73
+ formFields: IFormFieldsSection[],
74
+ attributes?: IFieldAttribute
75
+ ) => {
76
+ if (attributes && !_isEmpty(attributes)) {
77
+ const updatedFormFields = _map(formFields, fieldSection => {
78
+ const fieldSectionAttributes = attributes[fieldSection.name] || {}
79
+
80
+ const updatedFields = _map(fieldSection.fields, fieldItem => {
81
+ const fieldItemAttributes = attributes[fieldItem.name] || {}
82
+ return { ...fieldItem, ...fieldItemAttributes }
83
+ })
84
+
85
+ return {
86
+ ...fieldSection,
87
+ ...fieldSectionAttributes,
88
+ fields: updatedFields,
89
+ }
90
+ })
91
+
92
+ return updatedFormFields
93
+ }
94
+ return formFields
95
+ }
@@ -0,0 +1,32 @@
1
+ import { useEffect, useRef, useState } from 'react'
2
+
3
+ import { getCookieByName } from '../utils'
4
+
5
+ export const useCookieListener = (
6
+ key: string,
7
+ handler: (value: string | null) => void
8
+ ) => {
9
+ const getCookie = () => getCookieByName(key)
10
+ const [intervalValue, setIntervalValue] = useState<NodeJS.Timeout>()
11
+ const cookieRef = useRef<string>(getCookie())
12
+
13
+ const handleCookieChange = () => {
14
+ const currentCookie = getCookie()
15
+ const prevCookie = cookieRef.current
16
+
17
+ if (currentCookie !== prevCookie) {
18
+ cookieRef.current = getCookie()
19
+ handler(cookieRef.current)
20
+ }
21
+ }
22
+
23
+ useEffect(() => {
24
+ const interval = setInterval(handleCookieChange, 500)
25
+ setIntervalValue(interval)
26
+
27
+ return () => {
28
+ intervalValue && clearInterval(intervalValue)
29
+ }
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ }, [])
32
+ }
@@ -0,0 +1,32 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ export const useEventListener = (
4
+ eventName: string,
5
+ handler: () => void,
6
+ element = window
7
+ ) => {
8
+ // Create a ref that stores handler
9
+ const savedHandler = useRef<{ current: () => void }>()
10
+ // Update ref.current value if handler changes.
11
+
12
+ useEffect(() => {
13
+ savedHandler.current = handler
14
+ }, [handler])
15
+
16
+ useEffect(
17
+ () => {
18
+ // Make sure element supports addEventListener
19
+ const isSupported = element && element.addEventListener
20
+ if (!isSupported) return
21
+ // Create event listener that calls handler function stored in ref
22
+ const eventListener = (event: Event) => savedHandler.current(event)
23
+ // Add event listener
24
+ element.addEventListener(eventName, eventListener)
25
+ // Remove event listener on cleanup
26
+ return () => {
27
+ element.removeEventListener(eventName, eventListener)
28
+ }
29
+ },
30
+ [eventName, element] // Re-run if eventName or element changes
31
+ )
32
+ }
package/src/index.ts CHANGED
@@ -15,4 +15,5 @@ export { RedirectModal } from './components/common/RedirectModal'
15
15
  export { RsvpContainer } from './components/rsvpContainer'
16
16
  export { ResetPasswordContainer } from './components/resetPasswordContainer'
17
17
  export { ForgotPasswordModal } from './components/forgotPasswordModal'
18
- export { AddonsContainter } from './components/addonsContainer'
18
+ export { AddonsContainter } from './components/addonsContainer'
19
+ export { PreRegistration } from './components/preRegistration'
@@ -0,0 +1,55 @@
1
+ // autorize request body
2
+ interface IAuthorizeRequestData {
3
+ email: string;
4
+ password: string;
5
+ }
6
+
7
+ // authorize, get user data
8
+ interface IProfileData {
9
+ id: number | string;
10
+ firstName: string;
11
+ lastName: string;
12
+ email: string;
13
+ phone: string;
14
+ streetAddress: string;
15
+ zipCode: number;
16
+ countryId: number;
17
+ company: string;
18
+ state: string | number;
19
+ stateId: number;
20
+ city: string;
21
+ username: string;
22
+ screenName: string | null;
23
+ bio: string;
24
+ shortBio: string | null;
25
+ region: string | null;
26
+ image: string;
27
+ recommendedEvents: Array<any>;
28
+ rnRoles: Array<string>;
29
+ hasDashboardAccess: boolean;
30
+ ticketHolders: Array<any>;
31
+ }
32
+
33
+ interface IProfileResponse extends IAxiosResponseData {
34
+ data: IProfileData;
35
+ }
36
+
37
+ // signup request body
38
+ interface ISignupRequestData {
39
+ firstName: string;
40
+ lastName: string;
41
+ email: string;
42
+ password: string;
43
+ passwordConfirmation: string;
44
+ checkCartExpiration: boolean;
45
+ confirmEmail?: string;
46
+ }
47
+
48
+ interface ISignupRequestDataExtended extends ISignupRequestData {
49
+ phone: string | number;
50
+ countryId: string | number;
51
+ city: string;
52
+ stateId: string | number;
53
+ streetAddress: string;
54
+ zip: string | number;
55
+ }
@@ -0,0 +1,11 @@
1
+ interface IConfirmPreRegistrationRequestData {
2
+ brandOptIn: boolean;
3
+ confirmEmail: string;
4
+ dobDay: number;
5
+ dobMonth: number;
6
+ dobYear: number;
7
+ email: string;
8
+ numTickets: string | number;
9
+ password: string;
10
+ zip: string | number;
11
+ }
@@ -0,0 +1,30 @@
1
+ interface IFormField {
2
+ name: string;
3
+ label: string;
4
+
5
+ uniqueId?: string;
6
+ component?: HTMLElement | JSX.Element;
7
+ type?: string;
8
+ required?: boolean;
9
+ className?: string;
10
+ options?: { [key: string]: string | number }[];
11
+ onValidate?: (() => void) | null;
12
+ }
13
+
14
+ interface IFormFieldsSection {
15
+ name: string;
16
+ fields: IFormField[];
17
+
18
+ groupLabel?: string | HTMLElement | JSX.Element;
19
+ groupLabelVars?: string[];
20
+ groupLabelClassName?: string;
21
+ groupClassName?: string;
22
+ id?: string | number;
23
+ uniqueId?: string;
24
+ }
25
+
26
+ interface IFieldAttribute {
27
+ [key: string]: {
28
+ [key: string]: string | number | boolean | Array<string | number>;
29
+ };
30
+ }
@@ -1,29 +1,29 @@
1
1
  import { getDomain } from './getDomain'
2
2
 
3
- export function setCustomCookie(name: string, value: string, days: number = 5) {
3
+ export function setCustomCookie(name: string, value: string, days = 5) {
4
4
  let expires = ''
5
5
  if (days) {
6
- let date = new Date()
6
+ const date = new Date()
7
7
  date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000)
8
8
  expires = '; expires=' + date.toUTCString()
9
9
  }
10
10
  if (typeof window !== 'undefined') {
11
11
  const domain = getDomain(window.location.hostname)
12
12
  document.cookie =
13
- name + '=' + (value || '') + expires + '; path=/' + `; domain=${domain}`
13
+ name + '=' + (value || '') + expires + `; path=/; domain=${domain}`
14
14
  }
15
15
  }
16
16
 
17
17
  export function getCookieByName(cname: string) {
18
18
  if (typeof window === 'undefined') return ''
19
- let name = cname + '='
20
- let ca = document.cookie.split(';')
19
+ const name = cname + '='
20
+ const ca = document.cookie.split(';')
21
21
  for (let i = 0; i < ca.length; i++) {
22
22
  let c = ca[i]
23
- while (c.charAt(0) == ' ') {
23
+ while (c.charAt(0) === ' ') {
24
24
  c = c.substring(1)
25
25
  }
26
- if (c.indexOf(name) == 0) {
26
+ if (c.indexOf(name) === 0) {
27
27
  return c.substring(name.length, c.length)
28
28
  }
29
29
  }
@@ -6,3 +6,4 @@ export { createCheckoutDataBodyWithDefaultHolder } from './createCheckoutDataBod
6
6
  export { setCustomCookie, getCookieByName, deleteCookieByName } from './cookies'
7
7
  export { getDomain } from './getDomain'
8
8
  export { createMarkup } from './createMarkup'
9
+ export { replaceVarInString } from './replaceVarInString'
@@ -0,0 +1,9 @@
1
+ export const replaceVarInString = (message = '', varArray: Array<string>) => {
2
+ const re = new RegExp(/\{.*?\}/g)
3
+ let index = 0
4
+ return message.replace(re, _ => {
5
+ const value = varArray[index] || ''
6
+ index++
7
+ return value
8
+ })
9
+ }