Merge branch 'loading-screen' into 'develop'

Refactor SoapboxMount

See merge request soapbox-pub/soapbox-fe!1436
ci-review-rules
Alex Gleason 2022-05-20 21:20:20 +00:00
commit c729f30efa
7 zmienionych plików z 133 dodań i 127 usunięć

Wyświetl plik

@ -0,0 +1,19 @@
import React from 'react';
import LandingGradient from 'soapbox/components/landing-gradient';
import { Spinner } from 'soapbox/components/ui';
/** Fullscreen loading indicator. */
const LoadingScreen: React.FC = () => {
return (
<div className='fixed h-screen w-screen'>
<LandingGradient />
<div className='fixed h-screen w-screen flex items-center justify-center z-10'>
<Spinner size={40} withText={false} />
</div>
</div>
);
};
export default LoadingScreen;

Wyświetl plik

@ -14,13 +14,16 @@ import { loadSoapboxConfig, getSoapboxConfig } from 'soapbox/actions/soapbox';
import { fetchVerificationConfig } from 'soapbox/actions/verification';
import * as BuildConfig from 'soapbox/build_config';
import Helmet from 'soapbox/components/helmet';
import { Spinner } from 'soapbox/components/ui';
import LoadingScreen from 'soapbox/components/loading-screen';
import AuthLayout from 'soapbox/features/auth_layout';
import OnboardingWizard from 'soapbox/features/onboarding/onboarding-wizard';
import PublicLayout from 'soapbox/features/public_layout';
import NotificationsContainer from 'soapbox/features/ui/containers/notifications_container';
import { ModalContainer } from 'soapbox/features/ui/util/async-components';
import WaitlistPage from 'soapbox/features/verification/waitlist_page';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import {
ModalContainer,
NotificationsContainer,
OnboardingWizard,
WaitlistPage,
} from 'soapbox/features/ui/util/async-components';
import { createGlobals } from 'soapbox/globals';
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks';
import MESSAGES from 'soapbox/locales/messages';
@ -31,7 +34,6 @@ import { checkOnboardingStatus } from '../actions/onboarding';
import { preload } from '../actions/preload';
import ErrorBoundary from '../components/error_boundary';
import UI from '../features/ui';
import BundleContainer from '../features/ui/containers/bundle_container';
import { store } from '../store';
/** Ensure the given locale exists in our codebase */
@ -67,6 +69,7 @@ const loadInitial = () => {
};
};
/** Highest level node with the Redux store. */
const SoapboxMount = () => {
useCachedLocationHandler();
const dispatch = useAppDispatch();
@ -80,7 +83,9 @@ const SoapboxMount = () => {
const locale = validLocale(settings.get('locale')) ? settings.get('locale') : 'en';
const waitlisted = account && !account.source.get('approved', true);
const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding);
const showOnboarding = account && !waitlisted && needsOnboarding;
const singleUserMode = soapboxConfig.singleUserMode && soapboxConfig.singleUserModeProfile;
const [messages, setMessages] = useState<Record<string, string>>({});
@ -124,20 +129,6 @@ const SoapboxMount = () => {
localeLoading,
].some(Boolean);
if (showLoading) {
return (
<div className='p-4 h-screen w-screen flex items-center justify-center'>
<Helmet>
{themeCss && <style id='theme' type='text/css'>{`:root{${themeCss}}`}</style>}
</Helmet>
<Spinner size={40} withText={false} />
</div>
);
}
const waitlisted = account && !account.source.get('approved', true);
const bodyClass = classNames('bg-white dark:bg-slate-900 text-base h-full', {
'no-reduce-motion': !settings.get('reduceMotion'),
'underline-links': settings.get('underlineLinks'),
@ -145,94 +136,117 @@ const SoapboxMount = () => {
'demetricator': settings.get('demetricator'),
});
if (account && !waitlisted && needsOnboarding) {
return (
<IntlProvider locale={locale} messages={messages}>
<Helmet>
<html lang={locale} className={classNames({ dark: darkMode })} />
<body className={bodyClass} />
{themeCss && <style id='theme' type='text/css'>{`:root{${themeCss}}`}</style>}
<meta name='theme-color' content={soapboxConfig.brandColor} />
</Helmet>
const helmet = (
<Helmet>
<html lang={locale} className={classNames('h-full', { dark: darkMode })} />
<body className={bodyClass} />
{themeCss && <style id='theme' type='text/css'>{`:root{${themeCss}}`}</style>}
<meta name='theme-color' content={soapboxConfig.brandColor} />
</Helmet>
);
<ErrorBoundary>
<BrowserRouter basename={BuildConfig.FE_SUBDIRECTORY}>
<OnboardingWizard />
<NotificationsContainer />
</BrowserRouter>
</ErrorBoundary>
</IntlProvider>
/** Render the onboarding flow. */
const renderOnboarding = () => (
<BundleContainer fetchComponent={OnboardingWizard} loading={LoadingScreen}>
{(Component) => <Component />}
</BundleContainer>
);
/** Render the auth layout or UI. */
const renderSwitch = () => (
<Switch>
<Redirect from='/v1/verify_email/:token' to='/verify/email/:token' />
{/* Redirect signup route depending on Pepe enablement. */}
{/* We should prefer using /signup in components. */}
{pepeEnabled ? (
<Redirect from='/signup' to='/verify' />
) : (
<Redirect from='/verify' to='/signup' />
)}
{waitlisted && (
<Route render={(props) => (
<BundleContainer fetchComponent={WaitlistPage} loading={LoadingScreen}>
{(Component) => <Component {...props} account={account} />}
</BundleContainer>
)}
/>
)}
{!me && (singleUserMode
? <Redirect exact from='/' to={`/${singleUserMode}`} />
: <Route exact path='/' component={PublicLayout} />)}
{!me && (
<Route exact path='/' component={PublicLayout} />
)}
<Route exact path='/about/:slug?' component={PublicLayout} />
<Route exact path='/mobile/:slug?' component={PublicLayout} />
<Route path='/login' component={AuthLayout} />
{(features.accountCreation && instance.registrations) && (
<Route exact path='/signup' component={AuthLayout} />
)}
{pepeEnabled && (
<Route path='/verify' component={AuthLayout} />
)}
<Route path='/reset-password' component={AuthLayout} />
<Route path='/edit-password' component={AuthLayout} />
<Route path='/invite/:token' component={AuthLayout} />
<Route path='/' component={UI} />
</Switch>
);
/** Render the onboarding flow or UI. */
const renderBody = () => {
if (showOnboarding) {
return renderOnboarding();
} else {
return renderSwitch();
}
};
// intl is part of loading.
// It's important nothing in here depends on intl.
if (showLoading) {
return (
<>
{helmet}
<LoadingScreen />
</>
);
}
return (
<IntlProvider locale={locale} messages={messages}>
<Helmet>
<html lang={locale} className={classNames('h-full', { dark: darkMode })} />
<body className={bodyClass} />
{themeCss && <style id='theme' type='text/css'>{`:root{${themeCss}}`}</style>}
<meta name='theme-color' content={soapboxConfig.brandColor} />
</Helmet>
{helmet}
<ErrorBoundary>
<BrowserRouter basename={BuildConfig.FE_SUBDIRECTORY}>
<>
<ScrollContext shouldUpdateScroll={shouldUpdateScroll}>
<Switch>
<Redirect from='/v1/verify_email/:token' to='/verify/email/:token' />
<ScrollContext shouldUpdateScroll={shouldUpdateScroll}>
<>
{renderBody()}
{/* Redirect signup route depending on Pepe enablement. */}
{/* We should prefer using /signup in components. */}
{pepeEnabled ? (
<Redirect from='/signup' to='/verify' />
) : (
<Redirect from='/verify' to='/signup' />
)}
<BundleContainer fetchComponent={NotificationsContainer}>
{(Component) => <Component />}
</BundleContainer>
{waitlisted && (
<>
<Route render={(props) => <WaitlistPage {...props} account={account} />} />
<BundleContainer fetchComponent={ModalContainer}>
{Component => <Component />}
</BundleContainer>
</>
)}
{!me && (singleUserMode
? <Redirect exact from='/' to={`/${singleUserMode}`} />
: <Route exact path='/' component={PublicLayout} />)}
{!me && (
<Route exact path='/' component={PublicLayout} />
)}
<Route exact path='/about/:slug?' component={PublicLayout} />
<Route exact path='/mobile/:slug?' component={PublicLayout} />
<Route path='/login' component={AuthLayout} />
{(features.accountCreation && instance.registrations) && (
<Route exact path='/signup' component={AuthLayout} />
)}
{pepeEnabled && (
<Route path='/verify' component={AuthLayout} />
)}
<Route path='/reset-password' component={AuthLayout} />
<Route path='/edit-password' component={AuthLayout} />
<Route path='/invite/:token' component={AuthLayout} />
<Route path='/' component={UI} />
</Switch>
</ScrollContext>
</>
<BundleContainer fetchComponent={ModalContainer}>
{Component => <Component />}
</BundleContainer>
</>
</ScrollContext>
</BrowserRouter>
</ErrorBoundary>
</IntlProvider>
);
};
/** The root React node of the application. */
const Soapbox = () => {
return (
<Provider store={store}>

Wyświetl plik

@ -4,8 +4,6 @@ import { Link, Redirect, Route, Switch, useHistory } from 'react-router-dom';
import LandingGradient from 'soapbox/components/landing-gradient';
import SiteLogo from 'soapbox/components/site-logo';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
import { Button, Card, CardBody } from '../../components/ui';
@ -86,10 +84,6 @@ const AuthLayout = () => {
</div>
</div>
</main>
<BundleContainer fetchComponent={NotificationsContainer}>
{(Component) => <Component />}
</BundleContainer>
</div>
);
};

Wyświetl plik

@ -2,11 +2,6 @@ import React from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import LandingGradient from 'soapbox/components/landing-gradient';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import {
NotificationsContainer,
ModalContainer,
} from 'soapbox/features/ui/util/async-components';
import { useAppSelector } from 'soapbox/hooks';
import { isStandalone } from 'soapbox/utils/state';
@ -42,14 +37,6 @@ const PublicLayout = () => {
</div>
<Footer />
<BundleContainer fetchComponent={NotificationsContainer}>
{(Component) => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={ModalContainer}>
{(Component) => <Component />}
</BundleContainer>
</div>
</div>
);

Wyświetl plik

@ -104,8 +104,6 @@ import {
Directory,
SidebarMenu,
UploadArea,
NotificationsContainer,
ModalContainer,
ProfileHoverCard,
Share,
NewStatus,
@ -670,14 +668,6 @@ const UI: React.FC = ({ children }) => {
{me && floatingActionButton}
<BundleContainer fetchComponent={NotificationsContainer}>
{Component => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={ModalContainer}>
{Component => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={UploadArea}>
{Component => <Component active={draggingOver} onClose={closeUploadModal} />}
</BundleContainer>

Wyświetl plik

@ -494,6 +494,14 @@ export function DatePicker() {
return import(/* webpackChunkName: "date_picker" */'../../birthdays/date_picker');
}
export function OnboardingWizard() {
return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/onboarding-wizard');
}
export function WaitlistPage() {
return import(/* webpackChunkName: "features/verification" */'../../verification/waitlist_page');
}
export function CompareHistoryModal() {
return import(/*webpackChunkName: "modals/compare_history_modal" */'../components/compare_history_modal');
}

Wyświetl plik

@ -7,8 +7,6 @@ import { Link } from 'react-router-dom';
import { openModal } from 'soapbox/actions/modals';
import LandingGradient from 'soapbox/components/landing-gradient';
import SiteLogo from 'soapbox/components/site-logo';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
import { logOut } from '../../actions/auth';
@ -74,10 +72,6 @@ const WaitlistPage = ({ account }) => {
</div>
</div>
</main>
<BundleContainer fetchComponent={NotificationsContainer}>
{(Component) => <Component />}
</BundleContainer>
</div>
);
};