check server availability

master
Tudor Stanciu 2022-12-18 17:13:49 +02:00
parent ad254682f0
commit 677de87434
9 changed files with 505 additions and 5 deletions

341
notes/theme-example.json Normal file
View File

@ -0,0 +1,341 @@
{
"breakpoints":{
"keys":[
"xs",
"sm",
"md",
"lg",
"xl"
],
"values":{
"xs":0,
"sm":600,
"md":960,
"lg":1280,
"xl":1920
}
},
"direction":"ltr",
"mixins":{
"toolbar":{
"minHeight":56,
"@media (min-width:0px) and (orientation: landscape)":{
"minHeight":48
},
"@media (min-width:600px)":{
"minHeight":64
}
}
},
"overrides":{
"MuiBackdrop":{
"root":{
"backgroundColor":"#4A4A4A1A"
}
},
"MuiMenu":{
"paper":{
"boxShadow":"0px 3px 11px 0px #E8EAFC, 0 3px 3px -2px #B2B2B21A, 0 1px 8px 0 #9A9A9A1A"
}
},
"MuiSelect":{
"icon":{
"color":"#B9B9B9"
}
},
"MuiListItem":{
"root":{
"&$selected":{
"backgroundColor":"#F3F5FF !important",
"&:focus":{
"backgroundColor":"#F3F5FF"
}
}
},
"button":{
"&:hover, &:focus":{
"backgroundColor":"#F3F5FF"
}
}
},
"MuiTouchRipple":{
"child":{
"backgroundColor":"white"
}
},
"MuiTableRow":{
"root":{
"height":56
}
},
"MuiTableCell":{
"root":{
"borderBottom":"1px solid rgba(224, 224, 224, .5)",
"paddingLeft":24
},
"head":{
"fontSize":"0.95rem"
},
"body":{
"fontSize":"0.95rem"
}
},
"PrivateSwitchBase":{
"root":{
"marginLeft":10
}
}
},
"palette":{
"common":{
"black":"#000",
"white":"#fff"
},
"type":"light",
"primary":{
"main":"#536DFE",
"light":"#798dfe",
"dark":"#072cfe",
"contrastText":"#fff"
},
"secondary":{
"main":"#FF5C93",
"light":"#ff82ac",
"dark":"#ff0f60",
"contrastText":"#FFFFFF"
},
"error":{
"light":"#e57373",
"main":"#f44336",
"dark":"#d32f2f",
"contrastText":"#fff"
},
"warning":{
"main":"#FFC260",
"light":"#ffd186",
"dark":"#ffa513",
"contrastText":"rgba(0, 0, 0, 0.87)"
},
"info":{
"main":"#9013FE",
"light":"#a239fe",
"dark":"#6801c4",
"contrastText":"#fff"
},
"success":{
"main":"#3CD4A0",
"light":"#5bdbaf",
"dark":"#23a075",
"contrastText":"rgba(0, 0, 0, 0.87)"
},
"grey":{
"50":"#fafafa",
"100":"#f5f5f5",
"200":"#eeeeee",
"300":"#e0e0e0",
"400":"#bdbdbd",
"500":"#9e9e9e",
"600":"#757575",
"700":"#616161",
"800":"#424242",
"900":"#212121",
"A100":"#d5d5d5",
"A200":"#aaaaaa",
"A400":"#303030",
"A700":"#616161"
},
"contrastThreshold":3,
"tonalOffset":0.2,
"text":{
"primary":"#4A4A4A",
"secondary":"#6E6E6E",
"disabled":"rgba(0, 0, 0, 0.38)",
"hint":"#B9B9B9"
},
"divider":"rgba(0, 0, 0, 0.12)",
"background":{
"paper":"#fff",
"default":"#F6F7FF",
"light":"#F3F5FF"
},
"action":{
"active":"rgba(0, 0, 0, 0.54)",
"hover":"rgba(0, 0, 0, 0.04)",
"hoverOpacity":0.04,
"selected":"rgba(0, 0, 0, 0.08)",
"selectedOpacity":0.08,
"disabled":"rgba(0, 0, 0, 0.26)",
"disabledBackground":"rgba(0, 0, 0, 0.12)",
"disabledOpacity":0.38,
"focus":"rgba(0, 0, 0, 0.12)",
"focusOpacity":0.12,
"activatedOpacity":0.12
}
},
"props":{
},
"shadows":[
"none",
"0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)",
"0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)",
"0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)",
"0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)",
"0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)",
"0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)",
"0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)",
"0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)",
"0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)",
"0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)",
"0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)",
"0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)",
"0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)",
"0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)",
"0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)",
"0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)",
"0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)",
"0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)",
"0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)",
"0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)",
"0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)",
"0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)",
"0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)",
"0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)"
],
"typography":{
"htmlFontSize":16,
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontSize":14,
"fontWeightLight":300,
"fontWeightRegular":400,
"fontWeightMedium":500,
"fontWeightBold":700,
"h1":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":300,
"fontSize":"3rem",
"lineHeight":1.167,
"letterSpacing":"-0.01562em"
},
"h2":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":300,
"fontSize":"2rem",
"lineHeight":1.2,
"letterSpacing":"-0.00833em"
},
"h3":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"1.64rem",
"lineHeight":1.167,
"letterSpacing":"0em"
},
"h4":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"1.5rem",
"lineHeight":1.235,
"letterSpacing":"0.00735em"
},
"h5":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"1.285rem",
"lineHeight":1.334,
"letterSpacing":"0em"
},
"h6":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":500,
"fontSize":"1.142rem",
"lineHeight":1.6,
"letterSpacing":"0.0075em"
},
"subtitle1":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"1rem",
"lineHeight":1.75,
"letterSpacing":"0.00938em"
},
"subtitle2":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":500,
"fontSize":"0.875rem",
"lineHeight":1.57,
"letterSpacing":"0.00714em"
},
"body1":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"1rem",
"lineHeight":1.5,
"letterSpacing":"0.00938em"
},
"body2":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"0.875rem",
"lineHeight":1.43,
"letterSpacing":"0.01071em"
},
"button":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":500,
"fontSize":"0.875rem",
"lineHeight":1.75,
"letterSpacing":"0.02857em",
"textTransform":"uppercase"
},
"caption":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"0.75rem",
"lineHeight":1.66,
"letterSpacing":"0.03333em"
},
"overline":{
"fontFamily":"\\""Roboto\\"", \\""Helvetica\\"", \\""Arial\\"", sans-serif",
"fontWeight":400,
"fontSize":"0.75rem",
"lineHeight":2.66,
"letterSpacing":"0.08333em",
"textTransform":"uppercase"
}
},
"shape":{
"borderRadius":4
},
"transitions":{
"easing":{
"easeInOut":"cubic-bezier(0.4, 0, 0.2, 1)",
"easeOut":"cubic-bezier(0.0, 0, 0.2, 1)",
"easeIn":"cubic-bezier(0.4, 0, 1, 1)",
"sharp":"cubic-bezier(0.4, 0, 0.6, 1)"
},
"duration":{
"shortest":150,
"shorter":200,
"short":250,
"standard":300,
"complex":375,
"enteringScreen":225,
"leavingScreen":195
}
},
"zIndex":{
"mobileStepper":1000,
"speedDial":1050,
"appBar":1100,
"drawer":1200,
"modal":1300,
"snackbar":1400,
"tooltip":1500
},
"customShadows":{
"widget":"0px 3px 11px 0px #E8EAFC, 0 3px 3px -2px #B2B2B21A, 0 1px 8px 0 #9A9A9A1A",
"widgetDark":"0px 3px 18px 0px #4558A3B3, 0 3px 3px -2px #B2B2B21A, 0 1px 8px 0 #9A9A9A1A",
"widgetWide":"0px 12px 33px 0px #E8EAFC, 0 3px 3px -2px #B2B2B21A, 0 1px 8px 0 #9A9A9A1A"
}
}

View File

@ -7,6 +7,7 @@ import Layout from "./Layout/Layout";
// pages // pages
import Error from "../pages/error"; import Error from "../pages/error";
import Login from "../pages/login"; import Login from "../pages/login";
import ServerNotAvailable from "../features/server/availability/components/ServerNotAvailable";
// context // context
import { useUserState } from "../contexts/UserContext"; import { useUserState } from "../contexts/UserContext";
@ -26,7 +27,10 @@ export default function App() {
return ( return (
<BrowserRouter basename={process.env.PUBLIC_URL || ""}> <BrowserRouter basename={process.env.PUBLIC_URL || ""}>
<Switch> <Switch>
<Route exact path="/" render={() => <Redirect to="/dashboard" />} /> <PrivateRoute
path="/server-not-available"
component={ServerNotAvailable}
/>
<PublicRoute path="/login" component={Login} /> <PublicRoute path="/login" component={Login} />
<PrivateRoute path="/" component={Layout} /> <PrivateRoute path="/" component={Layout} />
<Route component={Error} /> <Route component={Error} />

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import { withRouter } from "react-router-dom"; import { withRouter } from "react-router-dom";
import ServerAvailabilityProvider from "../../features/server/providers/ServerAvailabilityProvider";
// components // components
import Header from "../Header/Header"; import Header from "../Header/Header";
@ -13,13 +14,13 @@ function Layout(props) {
var classes = useStyles(); var classes = useStyles();
return ( return (
<ServerAvailabilityProvider>
<div className={classes.root}> <div className={classes.root}>
<>
<Header history={props.history} /> <Header history={props.history} />
<Sidebar /> <Sidebar />
<Content /> <Content />
</>
</div> </div>
</ServerAvailabilityProvider>
); );
} }

View File

@ -0,0 +1,3 @@
import useServerApi from "./useServerApi";
export { useServerApi };

View File

@ -0,0 +1,26 @@
import { useCallback } from "react";
import useHttpRequest from "../../../hooks/useHttpRequest";
import { get } from "../../../utils/axios";
const cdn = process.env.REACT_APP_CDN_URL;
const endpoints = {
ping: `${cdn}/health/ping`
};
const useServerApi = () => {
const { exec } = useHttpRequest();
const checkHealth = useCallback(
(options) => {
const promise = exec(() => get(endpoints.ping), options);
return promise;
},
[exec]
);
return {
checkHealth
};
};
export default useServerApi;

View File

@ -0,0 +1,50 @@
import React from "react";
import { Grid, Paper, Typography, Button } from "@material-ui/core";
import { Link } from "react-router-dom";
import useStyles from "../styles";
import classnames from "classnames";
import ServerIsDown from "../../../../images/ServerIsDown.gif";
const ServerNotAvailable = () => {
const classes = useStyles();
return (
<Grid container className={classes.container}>
<Paper classes={{ root: classes.paperRoot }}>
<div className={classes.imageFrame}>
<img
className={classes.image}
src={ServerIsDown}
alt="server is down"
/>
</div>
<Typography
variant="h5"
className={classnames(classes.textRow, classes.safetyText)}
>
{"Oops. Looks like the server is currently unavailable."}
</Typography>
<Typography
variant="h6"
color="text"
colorBrightness="secondary"
className={classnames(classes.textRow, classes.safetyText)}
>
{"Try again in a few seconds"}
</Typography>
<Button
variant="contained"
// color="primary"
component={Link}
to="/"
size="large"
className={classes.button}
>
Retry
</Button>
</Paper>
</Grid>
);
};
export default ServerNotAvailable;

View File

@ -0,0 +1,49 @@
import { makeStyles } from "@material-ui/styles";
export default makeStyles((theme) => ({
container: {
height: "100vh",
width: "100vw",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
backgroundColor: theme.palette.error.dark,
position: "absolute",
top: 0,
left: 0
},
imageFrame: {
display: "flex",
alignItems: "center",
marginBottom: theme.spacing(2)
},
image: {
width: 200,
marginRight: theme.spacing(2)
},
paperRoot: {
backgroundColor: theme.palette.common.black,
display: "flex",
flexDirection: "column",
alignItems: "center",
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
maxWidth: 404
},
textRow: {
marginBottom: theme.spacing(4),
textAlign: "center"
},
safetyText: {
fontWeight: 300,
color: theme.palette.text.hint
},
button: {
backgroundColor: theme.palette.error.dark,
textTransform: "none",
fontSize: 22
}
}));

View File

@ -0,0 +1,26 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { Redirect } from "react-router-dom";
import { useServerApi } from "../api";
const ServerAvailabilityProvider = ({ children }) => {
const [ok, setOk] = useState(null);
const { checkHealth } = useServerApi();
useEffect(() => {
checkHealth({
onCompleted: () => setOk(true),
onError: () => setOk(false)
});
}, [checkHealth]);
if (ok === null) return <span>Checking server health...</span>;
if (ok === false) return <Redirect to="/server-not-available" />;
return <>{children}</>;
};
ServerAvailabilityProvider.propTypes = {
children: PropTypes.node
};
export default ServerAvailabilityProvider;

BIN
src/images/ServerIsDown.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB