From 5ca84ded5a1500ad3ea8d029b71488e8b3b74181 Mon Sep 17 00:00:00 2001
From: eug-vs <eug-vs@keemail.me>
Date: Sat, 15 Aug 2020 03:55:27 +0300
Subject: feat: ping server before showing content

---
 src/containers/Page/DynoWaiter.tsx | 64 ++++++++++++++++++++++++++++++++++++++
 src/containers/Page/Page.tsx       | 30 ++++++------------
 src/containers/Page/Router.tsx     | 27 ++++++++++++++++
 3 files changed, 100 insertions(+), 21 deletions(-)
 create mode 100644 src/containers/Page/DynoWaiter.tsx
 create mode 100644 src/containers/Page/Router.tsx

(limited to 'src/containers')

diff --git a/src/containers/Page/DynoWaiter.tsx b/src/containers/Page/DynoWaiter.tsx
new file mode 100644
index 0000000..d8460bf
--- /dev/null
+++ b/src/containers/Page/DynoWaiter.tsx
@@ -0,0 +1,64 @@
+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';
+
+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.',
+  'You are doing good.',
+  'Almost done.'
+];
+
+const useStyles = makeStyles(theme => ({
+  root: {
+    textAlign: 'center'
+  },
+  hidden: {
+    visibility: 'hidden',
+    position: 'absolute'
+  }
+}));
+
+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]);
+
+  const tagline = useMemo(() => time > 3 ? 'Waiting for the server' : '', [time]);
+
+  return (
+    <>
+      {!isReady && <Loading tagline={tagline} message={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;
+
-- 
cgit v1.2.3