diff options
Diffstat (limited to 'src/containers')
-rw-r--r-- | src/containers/Notifications/Notifications.tsx | 2 | ||||
-rw-r--r-- | src/containers/Page/DynoWaiter.tsx | 83 | ||||
-rw-r--r-- | src/containers/Page/Page.tsx | 30 | ||||
-rw-r--r-- | src/containers/Page/Router.tsx | 27 | ||||
-rw-r--r-- | src/containers/PollCreation/ImageInput.tsx | 37 |
5 files changed, 137 insertions, 42 deletions
diff --git a/src/containers/Notifications/Notifications.tsx b/src/containers/Notifications/Notifications.tsx index 2a9ea13..655e7be 100644 --- a/src/containers/Notifications/Notifications.tsx +++ b/src/containers/Notifications/Notifications.tsx @@ -4,7 +4,7 @@ import EmptyState from '../../components/EmptyState/EmptyState'; const useStyles = makeStyles(theme => ({ root: { - marginTop: theme.spacing(25) + marginTop: theme.spacing(16) } })); diff --git a/src/containers/Page/DynoWaiter.tsx b/src/containers/Page/DynoWaiter.tsx new file mode 100644 index 0000000..05d269f --- /dev/null +++ b/src/containers/Page/DynoWaiter.tsx @@ -0,0 +1,83 @@ +import React, { + useEffect, + useState, + useCallback, + useMemo +} from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import { get } from '../../requests'; +import Loading from '../../components/Loading/Loading'; +import Image from '../../components/Image/Image'; +import Message from '../../components/Message/Message'; +import coffeIcon from '../../assets/coffeeBreak.svg'; + +const DYNO_WAKEUP_TIME = 30; + +const messages = [ + '', + 'It looks like our server is sleeping.', + `We need about ${DYNO_WAKEUP_TIME} seconds to wake it up.`, + 'Please, stay with us.', + 'We love you <3', + 'Almost done.' +]; + +const useStyles = makeStyles(theme => ({ + root: { + textAlign: 'center' + }, + hidden: { + visibility: 'hidden', + position: 'absolute', + width: 0, + height: 0, + overflow: 'hidden' + }, + img: { + width: theme.spacing(24) + } +})); + +// TODO: if Dyno is sleeping, use this time to pre-load pages + +const DynoWaiter: React.FC = ({ children }) => { + const classes = useStyles(); + const [isReady, setIsReady] = useState<boolean>(false); + const [time, setTime] = useState<number>(0); + + const tick = useCallback((): void => setTime(value => value + 1), [setTime]); + + useEffect(() => { + const interval = setInterval(tick, 1000); + get('/ping').then(() => { + setIsReady(true); + clearInterval(interval); + }); + return () => clearInterval(interval); + }, [setIsReady, tick]); + + const message = useMemo(() => { + const interval = DYNO_WAKEUP_TIME / messages.length; + const index = Math.floor(time / interval); + const lastIndex = messages.length - 1; + return messages[index > lastIndex ? lastIndex : index]; + }, [time]); + + return ( + <> + {!isReady && ( + <> + <Loading message={message} tagline={message && 'Waiting for the server'} /> + {message && <Message><Image src={coffeIcon} className={classes.img} /></Message>} + </> + )} + <div className={isReady ? '' : classes.hidden}> + {children} + </div> + </> + ); +}; + + +export default DynoWaiter; + diff --git a/src/containers/Page/Page.tsx b/src/containers/Page/Page.tsx index 023d86e..475f76d 100644 --- a/src/containers/Page/Page.tsx +++ b/src/containers/Page/Page.tsx @@ -2,30 +2,24 @@ import React, { Suspense, useEffect } from 'react'; import { makeStyles, useTheme } from '@material-ui/core/styles'; import { useMediaQuery } from '@material-ui/core'; import { SnackbarProvider } from 'notistack'; -import { Switch, Route, useHistory } from 'react-router-dom'; -import Loading from '../../components/Loading/Loading'; +import { useHistory } from 'react-router-dom'; -const Profile = React.lazy(() => import('../Profile/Profile')); -const Feed = React.lazy(() => import('../Feed/Feed')); -const Login = React.lazy(() => import('../Login/Login')); -const Registration = React.lazy(() => import('../Registration/Registration')); -const Home = React.lazy(() => import('../Home/Home')); -const Notifications = React.lazy(() => import('../Notifications/Notifications')); -const PollCreation = React.lazy(() => import('../PollCreation/PollCreation')); +import Router from './Router'; +import DynoWaiter from './DynoWaiter'; +import Loading from '../../components/Loading/Loading'; const useStyles = makeStyles(theme => ({ root: { [theme.breakpoints.down('sm')]: { - margin: theme.spacing(10, 0, 12, 0) + padding: theme.spacing(10, 0, 12, 0) }, [theme.breakpoints.up('md')]: { - margin: theme.spacing(15, 5, 8, 5) + padding: theme.spacing(15, 5, 8, 5) } } })); - const Page: React.FC = () => { const classes = useStyles(); const theme = useTheme(); @@ -49,15 +43,9 @@ const Page: React.FC = () => { > <div className={classes.root}> <Suspense fallback={<Loading />}> - <Switch> - <Route exact path="/" component={Home} /> - <Route exact path="/login" component={Login} /> - <Route exact path="/registration" component={Registration} /> - <Route exact path="/feed" component={Feed} /> - <Route exact path="/notifications" component={Notifications} /> - <Route exact path="/new" component={PollCreation} /> - <Route path="/profile/:username" component={Profile} /> - </Switch> + <DynoWaiter> + <Router /> + </DynoWaiter> </Suspense> </div> </SnackbarProvider> diff --git a/src/containers/Page/Router.tsx b/src/containers/Page/Router.tsx new file mode 100644 index 0000000..7067eea --- /dev/null +++ b/src/containers/Page/Router.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Switch, Route } from 'react-router-dom'; + +const Profile = React.lazy(() => import('../Profile/Profile')); +const Feed = React.lazy(() => import('../Feed/Feed')); +const Login = React.lazy(() => import('../Login/Login')); +const Registration = React.lazy(() => import('../Registration/Registration')); +const Home = React.lazy(() => import('../Home/Home')); +const Notifications = React.lazy(() => import('../Notifications/Notifications')); +const PollCreation = React.lazy(() => import('../PollCreation/PollCreation')); + + +const Router: React.FC = React.memo(() => ( + <Switch> + <Route exact path="/" component={Home} /> + <Route exact path="/login" component={Login} /> + <Route exact path="/registration" component={Registration} /> + <Route exact path="/feed" component={Feed} /> + <Route exact path="/notifications" component={Notifications} /> + <Route exact path="/new" component={PollCreation} /> + <Route path="/profile/:username" component={Profile} /> + </Switch> +)); + + +export default Router; + diff --git a/src/containers/PollCreation/ImageInput.tsx b/src/containers/PollCreation/ImageInput.tsx index cc60478..475d527 100644 --- a/src/containers/PollCreation/ImageInput.tsx +++ b/src/containers/PollCreation/ImageInput.tsx @@ -2,7 +2,6 @@ import React, { useState } from 'react'; import { makeStyles } from '@material-ui/core/styles'; import { CardActionArea, - CardMedia, Typography, CircularProgress } from '@material-ui/core'; @@ -10,6 +9,7 @@ import { Check, CancelOutlined } from '@material-ui/icons'; import AttachLink from '../../components/AttachLink/AttachLink'; import FileUpload from '../../components/FileUpload/FileUpload'; +import BackgroundImage from '../../components/Image/BackgroundImage'; interface PropTypes { callback: (file?: File | string) => void; @@ -28,19 +28,17 @@ const useStyles = makeStyles({ opacity: '.5', fontSize: 50 }, - media: { - height: '100%', - width: '100%', - display: 'flex', - justifyContent: 'center', - alignItems: 'center' - }, - darkOverlay: { + overlay: { backgroundColor: 'rgba(0, 0, 0, 0.45)', color: 'white', position: 'absolute', top: 0, left: 0, + height: '100%', + width: '100%', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', transitionDuration: '0.5s' }, invisible: { @@ -76,17 +74,16 @@ const ImageInput: React.FC<PropTypes> = ({ callback, progress }) => { const Media = ( <CardActionArea onClick={handleClear} className={classes.root} disabled={Boolean(progress)}> - <CardMedia image={url} className={classes.media}> - <div className={`${classes.media} ${classes.darkOverlay} ${progress === 100 && classes.invisible}`}> - { - progress - ? progress < 100 - ? <CircularProgress variant="static" value={progress} className={classes.icon} /> - : <Check className={classes.icon} fontSize="large" /> - : <CancelOutlined className={classes.icon} fontSize="large" /> - } - </div> - </CardMedia> + <BackgroundImage src={url} /> + <div className={`${classes.overlay} ${progress === 100 && classes.invisible}`}> + { + progress + ? progress < 100 + ? <CircularProgress variant="static" value={progress} className={classes.icon} /> + : <Check className={classes.icon} fontSize="large" /> + : <CancelOutlined className={classes.icon} fontSize="large" /> + } + </div> </CardActionArea> ); |