import 'antd/dist/antd.less' import { AutoSaveProvider } from 'components/AutoSaveProvider' import ModulesProvider from 'components/ModulesProvider' import NotSupportSizeBrowser from 'components/NotSupportSizeBrowser' import Loading from 'components/Loading' import { ExchangeRateDefault } from 'constants/exchange-rate' import 'fonts/SFProDisplay/stylesheet.scss' import { useNotificationRequest, useWindowSize } from 'hooks' import { useQuery } from 'hooks/useQuery' import Cookies from 'js-cookie' import LogRocket from 'logrocket' import { getCorrelationId } from '@komi-app/correlation' import moment from 'moment' import { updateTalentProfileActions } from 'pages/BecomeATalent/Reducer/action' import React, { useEffect, useState } from 'react' import { isMobile } from 'react-device-detect' import { useDispatch } from 'react-redux' import { Link, useHistory, useLocation } from 'react-router-dom' import { useTypedSelector } from 'redux/rootReducer' import { detectLocalCurrencyActions, getExchangeRateActions, getExchangeRateUSDActions, getUserProfileActions } from 'redux/User/actions' import { selectIsAdminLogin, selectIsCheckLocalCurrency, selectUserData, selectUserState } from 'redux/User/selector' import Routes from 'routes' import { KOMI_TALENT_CURRENCY } from 'services/UserService' import { IframeMessage } from 'utils/iframeMessage' import 'video.js/dist/video-js.css' import './App.scss' import '@komi-app/creator-ui/dist/style.css' import './i18n' import { webviewMessage } from './utils/webviewMessage' import '@komi-app/components/dist/index.css' import { UserAgentProvider } from 'context/user-agent' import config from 'config' import { initProfileId, linkRedirectService } from 'services' import { useLinkRedirect } from 'context/LinkRedirectContext' import { TALENT_PROFILE_ID } from 'constants/profile' import { KOMI_SPOTIFY_ACCESS_TOKEN, KOMI_SPOTIFY_REFRESH_TOKEN } from './services/SpotifyService' import useMobileView from 'hooks/useMobileView' import { setupLink, ToastContextProvider } from '@komi-app/creator-ui' import { FLAGS, IfFeature, isReady, useFeatureIsOn, useFlags } from '@komi-app/flags-sdk' import When from '@komi-app/when' import { CreatorTrackingProvider, CreatorTrackingProps } from '@komi-app/analytics-sdk' import { useIntercomMessengerWidget } from './hooks/useIntercomMessengerWidget' import ErrorBoundary from 'components/ErrorBoundary/ErrorBoundary' setupLink(Link) LogRocket.init(config.logRocket.id, { rootHostname: 'komi.io', dom: { privateAttributeBlocklist: ['data-no-track'] } }) const KOMI_FIRST_SETUP_ONBOARDING = 'KOMI_FIRST_SETUP_ONBOARDING' function isMobileEnabledPath(path: string | undefined) { if (!path) { return false } return ( path === '/admin/send-login-link' || path.startsWith('/admin/onboarding') ) } const App = () => { const detectCurrency = useTypedSelector(selectIsCheckLocalCurrency) const isAdminLogin = useTypedSelector(selectIsAdminLogin) const user = useTypedSelector(selectUserData) const userState = useTypedSelector(selectUserState) const location = useLocation() const query = useQuery() //TODO: replace the below accessTokens const accessToken = query?.get('access_token') // redirect from admin const token = query?.get('token') // redirect from consumer const talentProfileId = query?.get('talentProfileId') // redirect from consumer const router = useHistory() const [isNotSetup, setIsNotSetup] = useState(false) const [firstRoute, setFirstRoute] = useState() const { width } = useWindowSize() const { setLinkRedirect } = useLinkRedirect() useFlags( gb => { if (user) gb.setAttributes({ ...gb.getAttributes(), tier: user.tier }) }, [user] ) const isLinkRedirectOn = useFeatureIsOn(FLAGS.LINK_REDIRECT) const isSpotifyFixOn = useFeatureIsOn(FLAGS.FIX_GS46_SPOTIFY_AUTH_FIX) const mobileView = useMobileView() const [shouldDisableScreenSizeError, setShouldDisableScreenSizeError] = useState(false) const isNotSupport = mobileView ? false : width && width < 1040 const useAnalyticsSDK = useFeatureIsOn(FLAGS.USE_ANALYTICS_SDK_TALENT) const isAnonIdFixOn = useFeatureIsOn(FLAGS.FIX_SB_1274_ANON_ID_RESET_TALENT) const shouldRemoveOldAnonIdCookie = useFeatureIsOn( FLAGS.FIX_SB_1274_ANON_ID_REMOVE_OLD_COOKIE ) const [tracking, setTracking] = useState() const ready = isReady() useIntercomMessengerWidget() useEffect(() => { setShouldDisableScreenSizeError( isMobileEnabledPath(router?.location?.pathname) ) }, [router.location.pathname]) useEffect(() => { setFirstRoute(router?.location?.pathname) if ( firstRoute !== '/collaborator-login' || !isNotSupport ? !user : !talentProfileId ) { return } const checkSetupStatus = () => { if (!isNotSupport && user) { const { talentProfile } = user const isOnboarding = talentProfile?.onboardSteps && Object.keys(talentProfile?.onboardSteps).every( (key: string) => !(talentProfile?.onboardSteps as any)[key] ) if (isOnboarding && talentProfile) { const result = localStorage.getItem(KOMI_FIRST_SETUP_ONBOARDING) const data = result ? JSON.parse(result) : {} if (!data.items?.includes(talentProfile?.id)) { localStorage.setItem( KOMI_FIRST_SETUP_ONBOARDING, JSON.stringify({ items: [...(data.items || []), talentProfile?.id] }) ) setIsNotSetup(true) return } } return } if (talentProfileId) { const result = localStorage.getItem(KOMI_FIRST_SETUP_ONBOARDING) const data = result ? JSON.parse(result) : {} if (!data.items?.includes(talentProfileId)) { localStorage.setItem( KOMI_FIRST_SETUP_ONBOARDING, JSON.stringify({ items: [...(data.items || []), talentProfileId] }) ) setIsNotSetup(true) return } } } checkSetupStatus() }, [user, firstRoute, isNotSupport]) useNotificationRequest() const dispatch = useDispatch() moment.updateLocale('en-gb', { weekdaysMin: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] }) useEffect(() => { if (!ready || isSpotifyFixOn) { return } if (Cookies.get(KOMI_SPOTIFY_ACCESS_TOKEN)) { Cookies.remove(KOMI_SPOTIFY_ACCESS_TOKEN) } if (Cookies.get(KOMI_SPOTIFY_REFRESH_TOKEN)) { Cookies.remove(KOMI_SPOTIFY_REFRESH_TOKEN) } }, [isSpotifyFixOn, ready]) useEffect(() => { // prevents using talent.* // or local.komi.ci const { location } = window if ( location.hostname.startsWith('talent.') || (location.origin === config.service.url && location.pathname === '/') ) { window.location.href = config.client.url } }, []) useEffect(() => { if (user) { const profileId = user.talentProfile?.id if (profileId) { initProfileId(profileId) Cookies.set(TALENT_PROFILE_ID, profileId as string) } if (!isAnonIdFixOn) { ;(window as any)?.analytics?.reset() } if (shouldRemoveOldAnonIdCookie) { Cookies.remove('ajs_anonymous_id') localStorage.removeItem('ajs_anonymous_id') } ;(window as any)?.analytics?.identify(user.id, { Id: user.id, Name: `${user.talentProfile?.firstName} ${user.talentProfile?.lastName}`, Email: user.email, Platform: webviewMessage.isWebView() ? 'Webview' : isMobile ? 'Responsive' : 'Web' }) } }, [user]) useEffect(() => { const correlationId = sessionStorage.getItem('correlationId') || getCorrelationId() sessionStorage.setItem('correlationId', correlationId!) LogRocket.identify( correlationId!, user ? { name: `${user.talentProfile?.firstName} ${user.talentProfile?.lastName}`, email: user?.email || '' } : undefined ) }, [user]) useEffect(() => { if (ready) dispatch(getUserProfileActions.REQUEST()) }, [router, dispatch, accessToken, token, ready]) useEffect(() => { if (ready && user && useAnalyticsSDK && !tracking) { const userId = user.id! const profileId = user.talentProfile?.id! const profileName = `${user.talentProfile?.firstName} ${user.talentProfile?.lastName}`.trim() const userFullname = `${user.firstName} ${user.lastName}`.trim() const handle = user.talentProfile?.user?.username! const talentId = user.talentProfile?.user?.id! setTracking({ handle, profileId, profileName, userFullname, userId, talentId }) } }, [user, tracking, ready]) // obsolete? useEffect(() => { if (detectCurrency) return if (user && user.localCurrency) { Cookies.set(KOMI_TALENT_CURRENCY, user.localCurrency, { expires: 999999 }) dispatch(getExchangeRateActions.REQUEST(user.localCurrency)) dispatch(getExchangeRateUSDActions.REQUEST()) dispatch(detectLocalCurrencyActions.SUCCESS(true)) } else if (user && !user.localCurrency && !isAdminLogin) { // we will not detect local with expert if (IframeMessage.inIframe()) return ;(async () => { const currency = ExchangeRateDefault.localCurrency Cookies.set(KOMI_TALENT_CURRENCY, currency, { expires: 999999 }) dispatch( updateTalentProfileActions.REQUEST({ localCurrency: currency, userState: userState }) ) dispatch(getExchangeRateActions.REQUEST(currency)) dispatch(getExchangeRateUSDActions.REQUEST()) })() } return () => {} }, [dispatch, user, detectCurrency]) // for Admin (obsolete?) useEffect(() => { const query = new URLSearchParams(location.search) const localCurrency: any = query?.get('localCurrency') if (!user || !localCurrency || !IframeMessage.inIframe()) return Cookies.set(KOMI_TALENT_CURRENCY, localCurrency, { expires: 999999 }) dispatch(getExchangeRateActions.REQUEST(localCurrency)) dispatch(getExchangeRateUSDActions.REQUEST()) }, [user]) useEffect(() => { if (!isLinkRedirectOn) return const loadExistingRedirect = async () => { if (user && user.talentProfile) { const result = await linkRedirectService().getLinkRedirect() let isExistingRedirectExpired = true if ( result?.linkRedirect?.scheduled_end_timestamp != undefined && result?.linkRedirect?.scheduled_timezone != undefined ) { const linkRedirectDateTimeNow = moment().tz( result?.linkRedirect?.scheduled_timezone ) if ( linkRedirectDateTimeNow.isBefore( result?.linkRedirect?.scheduled_end_timestamp ) ) { isExistingRedirectExpired = false } } setLinkRedirect({ link: isExistingRedirectExpired ? '' : result?.linkRedirect?.link, scheduledTimezone: isExistingRedirectExpired ? '' : result?.linkRedirect?.scheduled_timezone, scheduledStartTimestamp: isExistingRedirectExpired ? moment().valueOf() : moment(result?.linkRedirect?.scheduled_start_timestamp).valueOf(), scheduledEndTimestamp: isExistingRedirectExpired ? moment().add(1, 'days').valueOf() : moment(result?.linkRedirect?.scheduled_end_timestamp).valueOf(), isEnabled: isExistingRedirectExpired ? false : result?.linkRedirect?.is_enabled }) } } loadExistingRedirect() }, [setLinkRedirect, user?.talentProfile, isLinkRedirectOn]) return ( ) : ( ) } otherwise={} /> } disabled={ ) : ( ) } otherwise={} /> } /> ) } export default App