aboutsummaryrefslogtreecommitdiff
path: root/src/containers
diff options
context:
space:
mode:
Diffstat (limited to 'src/containers')
-rw-r--r--src/containers/Notifications/Notifications.tsx2
-rw-r--r--src/containers/Page/DynoWaiter.tsx83
-rw-r--r--src/containers/Page/Page.tsx30
-rw-r--r--src/containers/Page/Router.tsx27
-rw-r--r--src/containers/PollCreation/ImageInput.tsx37
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>
);