import type { FC } from '../lib/teact/teact'; import React, { useEffect, useLayoutEffect } from '../lib/teact/teact'; import { getActions, withGlobal } from '../global'; import type { GlobalState } from '../global/types'; import type { UiLoaderPage } from './common/UiLoader'; import type { ThemeKey } from '../types'; import { IS_INSTALL_PROMPT_SUPPORTED, IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from '../util/windowEnvironment'; import { DARK_THEME_BG_COLOR, INACTIVE_MARKER, LIGHT_THEME_BG_COLOR, PAGE_TITLE, } from '../config'; import { selectTabState, selectTheme } from '../global/selectors'; import { updateSizes } from '../util/windowSize'; import { addActiveTabChangeListener } from '../util/activeTabMonitor'; import { hasStoredSession } from '../util/sessions'; import buildClassName from '../util/buildClassName'; import { parseInitialLocationHash } from '../util/routing'; import { setupBeforeInstallPrompt } from '../util/installPrompt'; import useFlag from '../hooks/useFlag'; import usePrevious from '../hooks/usePrevious'; import useAppLayout from '../hooks/useAppLayout'; import Auth from './auth/Auth'; import Main from './main/Main.async'; import LockScreen from './main/LockScreen.async'; import AppInactive from './main/AppInactive'; import Transition from './ui/Transition'; import UiLoader from './common/UiLoader'; // import Test from './test/TestUpdateRef'; import styles from './App.module.scss'; type StateProps = { authState: GlobalState['authState']; isScreenLocked?: boolean; hasPasscode?: boolean; isInactiveAuth?: boolean; hasWebAuthTokenFailed?: boolean; theme: ThemeKey; }; enum AppScreens { auth, main, lock, inactive, } const TRANSITION_RENDER_COUNT = Object.keys(AppScreens).length / 2; const INACTIVE_PAGE_TITLE = `${PAGE_TITLE} ${INACTIVE_MARKER}`; const App: FC = ({ authState, isScreenLocked, hasPasscode, isInactiveAuth, hasWebAuthTokenFailed, theme, }) => { const { disconnect } = getActions(); const [isInactive, markInactive, unmarkInactive] = useFlag(false); const { isMobile } = useAppLayout(); const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android'; useEffect(() => { if (IS_INSTALL_PROMPT_SUPPORTED) { setupBeforeInstallPrompt(); } }, []); // Prevent drop on elements that do not accept it useEffect(() => { const body = document.body; const handleDrag = (e: DragEvent) => { e.preventDefault(); if (!e.dataTransfer) return; if (!(e.target as HTMLElement).dataset.dropzone) { e.dataTransfer.dropEffect = 'none'; } else { e.dataTransfer.dropEffect = 'copy'; } }; const handleDrop = (e: DragEvent) => { e.preventDefault(); }; body.addEventListener('drop', handleDrop); body.addEventListener('dragover', handleDrag); body.addEventListener('dragenter', handleDrag); return () => { body.removeEventListener('drop', handleDrop); body.removeEventListener('dragover', handleDrag); body.removeEventListener('dragenter', handleDrag); }; }, []); // return ; let activeKey: number; let page: UiLoaderPage | undefined; if (isInactive) { activeKey = AppScreens.inactive; } else if (isScreenLocked) { page = 'lock'; activeKey = AppScreens.lock; } else if (authState) { switch (authState) { case 'authorizationStateWaitPhoneNumber': page = 'authPhoneNumber'; activeKey = AppScreens.auth; break; case 'authorizationStateWaitCode': page = 'authCode'; activeKey = AppScreens.auth; break; case 'authorizationStateWaitPassword': page = 'authPassword'; activeKey = AppScreens.auth; break; case 'authorizationStateWaitRegistration': activeKey = AppScreens.auth; break; case 'authorizationStateWaitQrCode': page = 'authQrCode'; activeKey = AppScreens.auth; break; case 'authorizationStateClosed': case 'authorizationStateClosing': case 'authorizationStateLoggingOut': case 'authorizationStateReady': page = 'main'; activeKey = AppScreens.main; break; } } else if (hasStoredSession(true)) { page = 'main'; activeKey = AppScreens.main; } else if (hasPasscode) { activeKey = AppScreens.lock; } else { page = isMobileOs ? 'authPhoneNumber' : 'authQrCode'; activeKey = AppScreens.auth; } if (activeKey !== AppScreens.lock && activeKey !== AppScreens.inactive && activeKey !== AppScreens.main && parseInitialLocationHash()?.tgWebAuthToken && !hasWebAuthTokenFailed) { page = 'main'; activeKey = AppScreens.main; } useEffect(() => { updateSizes(); }, []); useEffect(() => { if (IS_MULTITAB_SUPPORTED) return; addActiveTabChangeListener(() => { disconnect(); document.title = INACTIVE_PAGE_TITLE; markInactive(); }); }, [activeKey, disconnect, markInactive]); useEffect(() => { if (isInactiveAuth) { document.title = INACTIVE_PAGE_TITLE; markInactive(); } else { document.title = PAGE_TITLE; unmarkInactive(); } }, [isInactiveAuth, markInactive, unmarkInactive]); const prevActiveKey = usePrevious(activeKey); // eslint-disable-next-line consistent-return function renderContent() { switch (activeKey) { case AppScreens.auth: return ; case AppScreens.main: return
; case AppScreens.lock: return ; case AppScreens.inactive: return ; } } useLayoutEffect(() => { document.body.classList.add(styles.bg); }, []); useLayoutEffect(() => { document.body.style.setProperty( '--theme-background-color', theme === 'dark' ? DARK_THEME_BG_COLOR : LIGHT_THEME_BG_COLOR, ); }, [theme]); return ( {renderContent} ); }; export default withGlobal( (global): StateProps => { return { authState: global.authState, isScreenLocked: global.passcode?.isScreenLocked, hasPasscode: global.passcode?.hasPasscode, isInactiveAuth: selectTabState(global).isInactive, hasWebAuthTokenFailed: global.hasWebAuthTokenFailed || global.hasWebAuthTokenPasswordRequired, theme: selectTheme(global), }; }, )(App);