import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import Fab from '@mui/material/Fab'; import { styled } from '@mui/material/styles'; import React, { useCallback, useEffect, useMemo } from 'react'; import { translate } from 'react-polyglot'; import { connect } from 'react-redux'; import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom'; import { ScrollSync } from 'react-scroll-sync'; import TopBarProgress from 'react-topbar-progress-indicator'; import { loginUser as loginUserAction } from '@staticcms/core/actions/auth'; import { discardDraft as discardDraftAction } from '@staticcms/core/actions/entries'; import { currentBackend } from '@staticcms/core/backend'; import { colors, GlobalStyles } from '@staticcms/core/components/UI/styles'; import { history } from '@staticcms/core/routing/history'; import { getDefaultPath } from '../../lib/util/collection.util'; import CollectionRoute from '../Collection/CollectionRoute'; import EditorRoute from '../Editor/EditorRoute'; import MediaLibrary from '../MediaLibrary/MediaLibrary'; import Page from '../page/Page'; import Snackbars from '../snackbar/Snackbars'; import { Alert } from '../UI/Alert'; import { Confirm } from '../UI/Confirm'; import Loader from '../UI/Loader'; import ScrollTop from '../UI/ScrollTop'; import NotFoundPage from './NotFoundPage'; import type { Credentials, TranslatedProps } from '@staticcms/core/interface'; import type { RootState } from '@staticcms/core/store'; import type { ComponentType } from 'react'; import type { ConnectedProps } from 'react-redux'; TopBarProgress.config({ barColors: { 0: colors.active, '1.0': colors.active, }, shadowBlur: 0, barThickness: 2, }); const AppRoot = styled('div')` width: 100%; min-width: 1200px; height: 100vh; position: relative; `; const AppWrapper = styled('div')` width: 100%; min-width: 1200px; min-height: 100vh; `; const ErrorContainer = styled('div')` margin: 20px; `; const ErrorCodeBlock = styled('pre')` margin-left: 20px; font-size: 15px; line-height: 1.5; `; function CollectionSearchRedirect() { const { name } = useParams(); return ; } function EditEntityRedirect() { const { name, entryName } = useParams(); return ; } const App = ({ auth, user, config, collections, loginUser, isFetching, useMediaLibrary, t, scrollSyncEnabled, discardDraft, }: TranslatedProps) => { const configError = useCallback( (error?: string) => { return (

{t('app.app.errorHeader')}

{t('app.app.configErrors')}: {error ?? config.error} {t('app.app.checkConfigYml')}
); }, [config.error, t], ); const handleLogin = useCallback( (credentials: Credentials) => { loginUser(credentials); }, [loginUser], ); const AuthComponent = useMemo(() => { if (!config.config) { return null; } const backend = currentBackend(config.config); return backend?.authComponent(); }, [config.config]); const authenticationPage = useMemo(() => { if (!config.config) { return null; } if (AuthComponent == null) { return (

{t('app.app.waitingBackend')}

); } return (
history.replace('/')} t={t} />
); }, [AuthComponent, auth.error, auth.isFetching, config.config, handleLogin, t]); const defaultPath = useMemo(() => getDefaultPath(collections), [collections]); const { pathname } = useLocation(); useEffect(() => { if (!/\/collections\/[a-zA-Z0-9_-]+\/entries\/[a-zA-Z0-9_-]+/g.test(pathname)) { discardDraft(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [pathname]); const content = useMemo(() => { if (!user) { return authenticationPage; } return ( <> {isFetching && } } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {useMediaLibrary ? : null} ); }, [authenticationPage, collections, defaultPath, isFetching, useMediaLibrary, user]); if (!config.config) { return configError(t('app.app.configNotFound')); } if (config.error) { return configError(); } if (config.isFetching) { return {t('app.app.loadingConfig')}; } return ( <> <>
{content} ); }; function mapStateToProps(state: RootState) { const { auth, config, collections, globalUI, mediaLibrary, scroll } = state; const user = auth.user; const isFetching = globalUI.isFetching; const useMediaLibrary = !mediaLibrary.externalLibrary; const scrollSyncEnabled = scroll.isScrolling; return { auth, config, collections, user, isFetching, useMediaLibrary, scrollSyncEnabled, }; } const mapDispatchToProps = { loginUser: loginUserAction, discardDraft: discardDraftAction, }; const connector = connect(mapStateToProps, mapDispatchToProps); export type AppProps = ConnectedProps; export default connector(translate()(App) as ComponentType);