import { type FC, useEffect } from 'react' import { init as initSentry, reactRouterV6BrowserTracingIntegration, replayIntegration, } from '@sentry/react' import { createRoot } from 'react-dom/client' import { QueryClient, QueryClientProvider } from 'react-query' import { Provider, useDispatch } from 'react-redux' import { useLocation, unstable_HistoryRouter as HistoryRouter, useNavigate, useNavigationType, createRoutesFromChildren, matchRoutes, } from 'react-router-dom' import { theme } from '@boards/shared' import { UNIVERSAL_LINK_KEEP_IN_WEB_SYMBOL } from '@app/constants/routes' import { useChromeExtensionMessageProvider } from '@app/features/chromeExtension' import { PlanResolverProvider } from '@features/pricing' import { useAuth } from '@hooks/useAuth' import useEmailAuthenticationCheck from '@hooks/useEmailAuthenticationCheck' import useGeoLocation from '@hooks/useGeoLocation' import useIdentifyAnalyticsUser from '@hooks/useIdentifyAnalyticsUser' import useSkipFirstChange from '@hooks/useSkipFirst' import { useUpdateUserInfo } from '@hooks/useUpdateUserInfo' import { configurationObjectFromEnv } from '@utils/configurationObjectFromEnv' import { ENV_KEYS } from '@utils/envKeys' import FirebaseAuthProvider from './_firebase/providers/FirebaseAuthProvider' import FirebaseListenersProvider from './_firebase/providers/FirebaseListenersProvider' import Router from './app/routes' import store, { history } from './app/store' import defaultTheme from './defaultTheme' import CustomerIO from './ui/components/CustomerIO' import TagManager from './utils/gtm' import './translations/i18n' import './css/index.css' import './css/Normalize.css' import './css/App.css' const queryClient = new QueryClient() interface EnvProps { gtmId: string nodeEnv: 'development' | 'staging' | 'production' sentryDSN: string firebaseContentFunctionsUrl: string firebaseGeneralFunctionsUrl: string } const { gtmId, nodeEnv, sentryDSN, firebaseContentFunctionsUrl, firebaseGeneralFunctionsUrl, } = configurationObjectFromEnv({ gtmId: ENV_KEYS.GTM_ID, nodeEnv: ENV_KEYS.NODE_ENV, sentryDSN: ENV_KEYS.SENTRY_DSN, firebaseContentFunctionsUrl: ENV_KEYS.FIREBASE_CONTENT_FUNCTIONS_URL, firebaseGeneralFunctionsUrl: ENV_KEYS.FIREBASE_CONTENT_FUNCTIONS_URL, }) if (nodeEnv === 'production') { TagManager.initialize({ gtmId }) initSentry({ dsn: sentryDSN, integrations: [ reactRouterV6BrowserTracingIntegration({ useEffect: useEffect, useLocation, useNavigationType, createRoutesFromChildren, matchRoutes, }), replayIntegration(), ], tracesSampleRate: 1.0, tracePropagationTargets: [ 'localhost', firebaseContentFunctionsUrl, firebaseGeneralFunctionsUrl, ], replaysSessionSampleRate: 0.1, replaysOnErrorSampleRate: 1.0, }) } const AppWrapper: FC = () => { const dispatch = useDispatch() const { user, loaded } = useAuth() const { pathname, search, hash } = useLocation() const navigate = useNavigate() const { loadGeoData } = useGeoLocation() useUpdateUserInfo(user) const { identified } = useIdentifyAnalyticsUser(user) const { onSyncAuthState } = useChromeExtensionMessageProvider() useEmailAuthenticationCheck(user, loaded) useSkipFirstChange(() => { return onSyncAuthState(() => user) }, [user]) /** * Removes the dollar ($) from the path and navigate to the same URL excluding * $ sign. Context: Any route starting with /$/ should not open Mobile app * (Universal Links feature) */ useEffect(() => { if (pathname.startsWith(UNIVERSAL_LINK_KEEP_IN_WEB_SYMBOL)) { const newPath = pathname.replace(UNIVERSAL_LINK_KEEP_IN_WEB_SYMBOL, '/') const finalUrl = `${newPath}${search}${hash}` navigate(finalUrl, { replace: true }) } }, [pathname, navigate, search, hash]) return ( ) } const container = document.getElementById('root') if (container) { const root = createRoot(container) root.render( {/* @ts-expect-error: https://github.com/remix-run/react-router/issues/9630#issuecomment-1341643731 */} , ) }