tf-checkout-react 1.4.26 → 1.5.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.
Files changed (76) hide show
  1. package/dist/api/index.d.ts +1 -0
  2. package/dist/api/preRegistrationComplete.d.ts +3 -0
  3. package/dist/components/billing-info-container/index.d.ts +1 -3
  4. package/dist/components/common/CopyField.d.ts +12 -0
  5. package/dist/components/common/CopyMessageModal.d.ts +7 -0
  6. package/dist/components/common/index.d.ts +1 -0
  7. package/dist/components/common/socials.d.ts +10 -0
  8. package/dist/components/confirmationContainer/index.d.ts +7 -7
  9. package/dist/components/confirmationContainer/social-buttons.d.ts +5 -2
  10. package/dist/components/forgotPasswordModal/index.d.ts +2 -3
  11. package/dist/components/loginForm/index.d.ts +1 -0
  12. package/dist/components/loginModal/index.d.ts +2 -3
  13. package/dist/components/preRegistration/FieldsSection.d.ts +13 -0
  14. package/dist/components/preRegistration/Influancers.d.ts +2 -0
  15. package/dist/components/preRegistration/PreRegistrationComplete.d.ts +5 -0
  16. package/dist/components/preRegistration/PreRegistrationInformations.d.ts +2 -0
  17. package/dist/components/preRegistration/Prewards.d.ts +2 -0
  18. package/dist/components/preRegistration/ShareOptions.d.ts +2 -0
  19. package/dist/components/preRegistration/constants.d.ts +2 -0
  20. package/dist/components/preRegistration/index.d.ts +17 -0
  21. package/dist/components/preRegistration/utils.d.ts +12 -0
  22. package/dist/components/ticketsContainer/TicketRow.d.ts +3 -2
  23. package/dist/components/ticketsContainer/utils.d.ts +9 -0
  24. package/dist/hooks/index.d.ts +1 -0
  25. package/dist/hooks/useEventListener.d.ts +1 -0
  26. package/dist/hooks/useLocalStorageListener.d.ts +1 -0
  27. package/dist/images/instagram.svg +5 -0
  28. package/dist/images/spotify.svg +6 -0
  29. package/dist/index.d.ts +4 -1
  30. package/dist/tf-checkout-react.cjs.development.js +1508 -157
  31. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  32. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  33. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  34. package/dist/tf-checkout-react.esm.js +1509 -157
  35. package/dist/tf-checkout-react.esm.js.map +1 -1
  36. package/dist/utils/isValidNumber.d.ts +1 -0
  37. package/package.json +1 -1
  38. package/src/api/index.ts +28 -0
  39. package/src/api/preRegistrationComplete.ts +37 -0
  40. package/src/assets/images/instagram.svg +5 -0
  41. package/src/assets/images/spotify.svg +6 -0
  42. package/src/components/billing-info-container/index.tsx +1 -7
  43. package/src/components/common/CopyField.tsx +53 -0
  44. package/src/components/common/CopyMessageModal.tsx +34 -0
  45. package/src/components/common/NativeSelectFeild/index.tsx +1 -1
  46. package/src/components/common/index.tsx +1 -0
  47. package/src/components/common/socials.tsx +33 -0
  48. package/src/components/confirmationContainer/config.ts +62 -55
  49. package/src/components/confirmationContainer/index.tsx +11 -31
  50. package/src/components/confirmationContainer/social-buttons.tsx +43 -20
  51. package/src/components/forgotPasswordModal/index.tsx +4 -4
  52. package/src/components/loginForm/index.tsx +4 -0
  53. package/src/components/loginModal/index.tsx +5 -4
  54. package/src/components/preRegistration/FieldsSection.tsx +142 -0
  55. package/src/components/preRegistration/Influancers.tsx +34 -0
  56. package/src/components/preRegistration/PreRegistrationComplete.tsx +164 -0
  57. package/src/components/preRegistration/PreRegistrationInformations.tsx +54 -0
  58. package/src/components/preRegistration/Prewards.tsx +41 -0
  59. package/src/components/preRegistration/ShareOptions.tsx +77 -0
  60. package/src/components/preRegistration/constants.tsx +161 -0
  61. package/src/components/preRegistration/index.tsx +274 -0
  62. package/src/components/preRegistration/utils.ts +155 -0
  63. package/src/components/ticketsContainer/ReferralLogic.tsx +1 -1
  64. package/src/components/ticketsContainer/TicketRow.tsx +17 -14
  65. package/src/components/ticketsContainer/TicketsSection.tsx +2 -0
  66. package/src/components/ticketsContainer/index.tsx +77 -8
  67. package/src/components/ticketsContainer/utils.ts +30 -6
  68. package/src/hooks/index.ts +1 -0
  69. package/src/hooks/useEventListener.ts +32 -0
  70. package/src/hooks/useLocalStorageListener.ts +27 -0
  71. package/src/index.ts +6 -2
  72. package/src/types/api/preRegistration.d.ts +11 -0
  73. package/src/types/api/preRegistrationComplete.d.ts +95 -0
  74. package/src/types/pre-registration-complete.d.ts +42 -0
  75. package/src/utils/cookies.ts +7 -7
  76. package/src/utils/isValidNumber.ts +8 -0
@@ -14,6 +14,7 @@ import _identity from 'lodash/identity'
14
14
  import _includes from 'lodash/includes'
15
15
  import _isEmpty from 'lodash/isEmpty'
16
16
  import _some from 'lodash/some'
17
+ import moment from 'moment-timezone'
17
18
  import React, { ReactNode, useEffect, useRef, useState } from 'react'
18
19
  import Button from 'react-bootstrap/Button'
19
20
 
@@ -26,8 +27,10 @@ import {
26
27
  logout,
27
28
  postOnCheckout,
28
29
  } from '../../api'
30
+ import { getPreRegistrationInfluancers } from '../../api/preRegistrationComplete'
29
31
  import { X_TF_ECOMMERCE } from '../../constants'
30
32
  import { useCookieListener } from '../../hooks/useCookieListener'
33
+ import { useLocalStorageListener } from '../../hooks/useLocalStorageListener'
31
34
  import { usePixel } from '../../hooks/usePixel'
32
35
  import {
33
36
  createCheckoutDataBodyWithDefaultHolder,
@@ -168,6 +171,7 @@ export const TicketsContainer = ({
168
171
  showAlertIcons = true,
169
172
  }: IGetTickets) => {
170
173
  const [selectedTickets, setSelectedTickets] = useState({} as ISelectedTickets)
174
+ const isWindowDefined = typeof window !== 'undefined'
171
175
  const [isLogged, setIsLogged] = useState(Boolean(getCookieByName(X_TF_ECOMMERCE)))
172
176
  const [showLoginModal, setShowLoginModal] = useState(false)
173
177
  const [tickets, setTickets] = useState([] as ITicketData[])
@@ -186,15 +190,20 @@ export const TicketsContainer = ({
186
190
  const [isNotInvitedError, setIsNotInvitedError] = useState('')
187
191
  const [isInvalidLinkError, setIsInvalidLinkError] = useState('')
188
192
  const [pendingVerificationMessage, setPendingVerificationMessage] = useState()
189
-
193
+ const [preregistereds, setPreregistereds] = useState([] as Array<IInfluancerData>)
194
+ const [ticketsNotAvailableModalOpen, setTicketsNotAvailableModalOpen] = useState(false)
195
+ const [isPreregistred, setIsPreregisred] = useState(checkUserPreregistration())
190
196
  const ticketsContainerRef = useRef<HTMLDivElement>(null)
191
197
  const pageUrl = isBrowser ? window.location.href.split('?')[0] : ''
192
-
193
198
  useCookieListener(X_TF_ECOMMERCE, value => setIsLogged(Boolean(value)))
199
+ useLocalStorageListener('user_data', (user: any) => {
200
+ const isPreregistredUser = _some(preregistereds, item => item.email === user?.email)
201
+ setIsPreregisred(isPreregistredUser)
202
+ })
194
203
  usePixel(eventId, { pageUrl })
195
204
 
196
205
  useEffect(() => {
197
- if (typeof window !== 'undefined') {
206
+ if (isWindowDefined) {
198
207
  const access_token = window.localStorage.getItem('access_token')
199
208
  if (access_token) {
200
209
  const decoded = jwt_decode<{ exp: number }>(access_token)
@@ -208,9 +217,16 @@ export const TicketsContainer = ({
208
217
  }, [])
209
218
 
210
219
  useEffect(() => {
211
- !!eventId && getTicketsApi()
220
+ if (eventId) {
221
+ getTicketsApi()
222
+ fetchPreregisteredsData()
223
+ }
212
224
  }, [eventId])
213
225
 
226
+ useEffect(() => {
227
+ setIsPreregisred(checkUserPreregistration())
228
+ }, [preregistereds])
229
+
214
230
  useEffect(() => {
215
231
  if (isLogged) {
216
232
  fetchUserData()
@@ -295,6 +311,19 @@ export const TicketsContainer = ({
295
311
  }
296
312
  }
297
313
 
314
+ async function fetchPreregisteredsData() {
315
+ try {
316
+ const preregistrationData = await getPreRegistrationInfluancers({
317
+ eventId,
318
+ })
319
+ setPreregistereds(preregistrationData.data.attributes.influencers)
320
+ } catch (error) {
321
+ if (axios.isAxiosError(error)) {
322
+ setError(_get(error, 'response.data.message'))
323
+ }
324
+ }
325
+ }
326
+
298
327
  const handleTicketSelect = (key: string, value: number | string, isTable = false) => {
299
328
  setSelectedTickets(prevState => {
300
329
  if (Object.keys(prevState)[0] !== key && !value) {
@@ -307,6 +336,16 @@ export const TicketsContainer = ({
307
336
  })
308
337
  }
309
338
 
339
+ function checkUserPreregistration() {
340
+ const userDataString = isWindowDefined ? window.localStorage.getItem('user_data') : ''
341
+ let isPreregistredUser = false
342
+ if (userDataString) {
343
+ const user = JSON.parse(userDataString)
344
+ isPreregistredUser = _some(preregistereds, item => item.email === user?.email)
345
+ }
346
+ return isPreregistredUser
347
+ }
348
+
310
349
  const handleOrdersClick = () => {
311
350
  if (isBrowser) {
312
351
  window.location.href = ordersPath ?? '/orders'
@@ -460,7 +499,8 @@ export const TicketsContainer = ({
460
499
 
461
500
  const isTicketOnSale = _some(
462
501
  tickets,
463
- item => item.salesStarted && !item.salesEnded && !item.soldOut
502
+ item =>
503
+ (item.salesStarted || event?.presalesStarted) && !item.salesEnded && !item.soldOut
464
504
  )
465
505
 
466
506
  const eventHasTickets = !_isEmpty(tickets)
@@ -496,6 +536,12 @@ export const TicketsContainer = ({
496
536
  }
497
537
  }
498
538
 
539
+ const handleNotAvailableTicketsClick = () => {
540
+ if (!_isEmpty(selectedTickets)) {
541
+ setTicketsNotAvailableModalOpen(true)
542
+ }
543
+ }
544
+
499
545
  const bookButtonIsDisabled =
500
546
  (handleBookIsLoading ||
501
547
  _isEmpty(selectedTickets) ||
@@ -504,7 +550,10 @@ export const TicketsContainer = ({
504
550
 
505
551
  const isTicketAvailable = _some(
506
552
  tickets,
507
- ticket => ticket.displayTicket && !ticket.soldOut && ticket.salesStarted
553
+ ticket =>
554
+ ticket.displayTicket &&
555
+ !ticket.soldOut &&
556
+ (ticket.salesStarted || (event?.presalesStarted && !event?.presalesEnded))
508
557
  )
509
558
 
510
559
  const wrappedActionsSectionComponent = React.isValidElement(ActionsSectionComponent)
@@ -547,6 +596,12 @@ export const TicketsContainer = ({
547
596
  const isSeatMapAllowed = _get(event, 'seatMapAllowed', false)
548
597
  const isTableMapEnabled = _get(event, 'tableMapEnabled', false)
549
598
 
599
+ const notAvailableTicketsMessage = `Tickets for this event are not available until ${moment(
600
+ event?.salesStart
601
+ ).format(
602
+ 'dddd, DD MMMM YYYY'
603
+ )}. \n If you pre-registered, log into your account first to buy your pre-sale ticket.`
604
+
550
605
  const tableTickets = _filter(tickets, (ticket: any) => ticket.isTable)
551
606
  const ordinarTickets = {} as ITicket
552
607
  _forEach(tickets, (ticket: any, key: string) => {
@@ -554,7 +609,6 @@ export const TicketsContainer = ({
554
609
  ordinarTickets[key] = ticket
555
610
  }
556
611
  })
557
-
558
612
  return (
559
613
  <ThemeProvider theme={themeMui}>
560
614
  {!isLoading && <ReferralLogic eventId={eventId} />}
@@ -586,6 +640,14 @@ export const TicketsContainer = ({
586
640
  {error}
587
641
  </Alert>
588
642
  )}
643
+ {ticketsNotAvailableModalOpen && (
644
+ <ConfirmModal
645
+ message={notAvailableTicketsMessage}
646
+ hideCancelBtn={true}
647
+ onClose={() => onClose('invalidLink')}
648
+ onConfirm={() => setTicketsNotAvailableModalOpen(false)}
649
+ />
650
+ )}
589
651
  {isLoading ? (
590
652
  <Loader />
591
653
  ) : (
@@ -666,7 +728,14 @@ export const TicketsContainer = ({
666
728
  ${isButtonScrollable ? 'is-scrollable' : ''}
667
729
  ${!isLoggedIn ? 'on-bottom' : ''}
668
730
  `}
669
- onClick={handleGetTicketClick}
731
+ onClick={
732
+ event?.salesStart &&
733
+ event?.presalesStarted &&
734
+ !event?.presalesEnded &&
735
+ (!isPreregistred || !isLogged)
736
+ ? handleNotAvailableTicketsClick
737
+ : handleGetTicketClick
738
+ }
670
739
  >
671
740
  {selectedTickets.isTable
672
741
  ? 'RESERVE TABLES'
@@ -1,11 +1,35 @@
1
- export const getTicketSelectOptions = (
2
- maxCount = 10,
3
- minCount = 1,
4
- multiplier = 1
5
- ) => {
1
+ export const getTicketSelectOptions = (maxCount = 10, minCount = 1, multiplier = 1) => {
6
2
  const options = [{ label: 0, value: 0 }]
7
- for (let i = minCount; i <= Math.min(50, maxCount); i += multiplier) {
3
+ for (let i = minCount || 1; i <= Math.min(50, maxCount); i += multiplier) {
8
4
  options.push({ label: i, value: i })
9
5
  }
10
6
  return options
11
7
  }
8
+
9
+ interface eventDatesInfo {
10
+ salesStarted: boolean;
11
+ salesEnded: boolean;
12
+ presalesStarted: boolean;
13
+ presalesEnded: boolean;
14
+ presalesEnabled: boolean;
15
+ }
16
+
17
+ export const defineIsSalesClosed = (eventDatesInfo: eventDatesInfo): boolean => {
18
+ const { salesStarted, salesEnded, presalesStarted, presalesEnded, presalesEnabled } =
19
+ eventDatesInfo
20
+ let isSalesClosed = false
21
+ if (!salesStarted || (salesStarted && salesEnded)) {
22
+ isSalesClosed = true
23
+ }
24
+ if (presalesEnabled) {
25
+ if (
26
+ (!presalesStarted && !presalesEnded) ||
27
+ (presalesStarted && presalesEnded && !salesStarted)
28
+ ) {
29
+ isSalesClosed = true
30
+ } else {
31
+ isSalesClosed = false
32
+ }
33
+ }
34
+ return isSalesClosed
35
+ }
@@ -0,0 +1 @@
1
+ export { useCookieListener } from './useCookieListener'
@@ -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
+ }
@@ -0,0 +1,27 @@
1
+ import { useEffect, useState } from 'react'
2
+
3
+ export function useLocalStorageListener(
4
+ key: string,
5
+ callback: (value: string | null) => void
6
+ ): string | null {
7
+ const isWindowDefined = typeof window !== 'undefined'
8
+ const [value, setValue] = useState<string | null>(
9
+ isWindowDefined ? localStorage.getItem(key) : ''
10
+ )
11
+
12
+ useEffect(() => {
13
+ const intervalId = setInterval(() => {
14
+ const newValue = localStorage.getItem(key)
15
+ if (newValue !== value) {
16
+ setValue(newValue)
17
+ callback(JSON.parse(newValue || ''))
18
+ }
19
+ }, 100)
20
+
21
+ return () => {
22
+ clearInterval(intervalId)
23
+ }
24
+ }, [key, value, callback])
25
+
26
+ return value
27
+ }
package/src/index.ts CHANGED
@@ -13,9 +13,13 @@ export { RsvpContainer } from './components/rsvpContainer'
13
13
  export { ResetPasswordContainer } from './components/resetPasswordContainer'
14
14
  export { ForgotPasswordModal } from './components/forgotPasswordModal'
15
15
  export { AddonsContainter } from './components/addonsContainer'
16
+ export { PreRegistration } from './components/preRegistration'
17
+ export { PreRegistrationComplete } from './components/preRegistration/PreRegistrationComplete'
18
+ export { PreRegistrationInformations } from './components/preRegistration/PreRegistrationInformations'
19
+
20
+ export { useCookieListener } from './hooks'
16
21
  export { DelegationsContainer } from './components/delegationsContainer'
17
22
  export { PoweredBy } from './components/common/PoweredBy'
18
23
  export { SeatMapContainer } from './components/seatMapContainer'
19
24
  export { IDVerification } from './components/idVerificationContainer'
20
- export { VERIFICATION_STATUSES } from './components/idVerificationContainer/constants'
21
- export { useCookieListener } from './hooks/useCookieListener'
25
+ export { VERIFICATION_STATUSES } from './components/idVerificationContainer/constants'
@@ -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,95 @@
1
+ interface IInfluancerData {
2
+ customer_id: string;
3
+ data_capture: any;
4
+ email: string;
5
+ date: string;
6
+ dateOfBirth: string;
7
+ event_id: string;
8
+ first_name: string;
9
+ last_name: string;
10
+ name: string;
11
+ points: string;
12
+ prereg_id: string;
13
+ quantity: string;
14
+ refferer_customer_ids: Array<string | number> | null;
15
+ }
16
+
17
+ interface IPrizeData {
18
+ name: string;
19
+ id: string;
20
+
21
+ description?: string;
22
+ image?: string;
23
+ tour_id?: string;
24
+ }
25
+
26
+ interface IInfluancersData {
27
+ attributes: {
28
+ influencers: IInfluancerData[];
29
+ prizes: IPrizeData[];
30
+ };
31
+ relationships: Array<unknown>;
32
+ type: string;
33
+ }
34
+
35
+ interface IShareOptionsActionData {
36
+ action: string;
37
+ alreadyApplied: boolean;
38
+ gropName: string | null;
39
+ id: string;
40
+ oneTimeAction: boolean;
41
+ phase: string;
42
+ point: string;
43
+ socialUrl: string | null;
44
+ }
45
+
46
+ interface IShareOptionsData {
47
+ attributes: {
48
+ actions: IShareOptionsActionData[];
49
+ shareActionToken: string;
50
+ shareUrl: string;
51
+ tokenShuffleMethod: string;
52
+ };
53
+ relationships: Array<unknown>;
54
+ type: string;
55
+ }
56
+
57
+ interface ISubmitShareActionAttributes {
58
+ shareActionToken: string;
59
+ tokenShuffleMethod: string;
60
+ }
61
+
62
+ interface ISubmitShareActionData {
63
+ attributes: {
64
+ shareActionToken: string;
65
+ tokenShuffleMethod: string;
66
+ };
67
+ relationships: Array<unknown>;
68
+ type: string;
69
+ }
70
+
71
+ interface IInfluancersRequestData {
72
+ eventId: string | number;
73
+ }
74
+
75
+ interface IShareOptionsRequestData {
76
+ hash: string;
77
+ }
78
+
79
+ interface ISubmitShareActionRequestData {
80
+ eventActionId: string;
81
+ hash: string | null;
82
+ accessToken: string;
83
+ }
84
+
85
+ interface IInfluancersResponseData extends IAxiosResponseData {
86
+ data: IInfluancersData;
87
+ }
88
+
89
+ interface IShareOptionsResponseData extends IAxiosResponseData {
90
+ data: IShareOptionsData;
91
+ }
92
+
93
+ interface ISubmitShareActionResponseData extends IAxiosResponseData {
94
+ data: ISubmitShareActionData;
95
+ }
@@ -0,0 +1,42 @@
1
+ interface IPrewardsProps {
2
+ data: Array<IPrizeData>;
3
+ classNamePrefix: string;
4
+ headerNode?: string | Node;
5
+ }
6
+
7
+ interface IInfluancersProps {
8
+ data: Array<IInfluancerData>;
9
+ classNamePrefix: string;
10
+ headerNode?: string | Node;
11
+ }
12
+
13
+ interface IShareOptionsProps {
14
+ data: IShareOptionsData;
15
+ classNamePrefix: string;
16
+ hasCopyIcon?: boolean;
17
+ onLinkCopied: () => void;
18
+ updateShareActionData: () => void;
19
+ headerText?: string | Node;
20
+ hash: string | null;
21
+ shareActionData: ISubmitShareActionAttributes;
22
+ }
23
+
24
+ interface IPreRegistrationInformationProps {
25
+ eventId: string | number;
26
+ classNamePrefix: string;
27
+ onGetPreregistrationDataSuccess?: () => void;
28
+ onGetPreregistrationDataError?: () => void;
29
+ influancersHeaderNode?: string | Node;
30
+ prewardsHeaderNode?: string | Node;
31
+ }
32
+
33
+ interface IPreRegistrationCompleteProps extends IShareOptionsProps {
34
+ eventId: string | number;
35
+ pageHeader?: string | Node;
36
+ pageMessage?: string | Node;
37
+ onLoginSuccess?: (response: IProfileData) => void;
38
+ onLoginError?: () => void;
39
+ logo?: string;
40
+ showForgotPasswordButton?: boolean;
41
+ onGetConfirmationDataSuccess?: () => void;
42
+ }
@@ -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
  }
@@ -0,0 +1,8 @@
1
+ import _isNumber from 'lodash/isNumber'
2
+
3
+ export const isValidNumber = (value?: number | string): boolean => {
4
+ if (isNaN(Number(value))) {
5
+ return false
6
+ }
7
+ return _isNumber(Number(value))
8
+ }