better comparison + fixed navbar

This commit is contained in:
Nicholas Orlowsky 2023-01-23 14:37:22 -06:00
parent 9c601aa3be
commit d764fd29e1
6 changed files with 191 additions and 54 deletions

View file

@ -2,13 +2,12 @@
<project version="4">
<component name="ChangeListManager">
<list default="true" id="03fafda4-e2c1-4602-a731-a2f96e84badd" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/src/components/CreateCruisePage.css" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/components/UptimeComparisonCard.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/components/UptimeLabelCard.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/App.css" beforeDir="false" afterPath="$PROJECT_DIR$/src/App.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/CreateCruisePage.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/CreateCruisePage.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/HomePage.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/HomePage.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/UptimeCard.css" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/UptimeCard.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.tsx" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -37,16 +36,14 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"list.type.of.created.stylesheet": "CSS",
"ts.external.directory.path": "/home/nickorlow/programmming/personal/nws-site/node_modules/typescript/lib"
}
}]]></component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$/src/components" />
<property name="ts.external.directory.path" value="$PROJECT_DIR$/node_modules/typescript/lib" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/src/static/images" />
<recent name="$PROJECT_DIR$/src/components" />
<recent name="$PROJECT_DIR$/src/static/images" />
</key>
</component>
<component name="RunManager">

View file

@ -6,6 +6,8 @@ import React, {useEffect, useState} from "react";
import {Incident, UptimeResponse} from "../nws-api/types";
import {getIncidents, getUptime} from "../nws-api/calls";
import "../App.css";
import UptimeComparisonCard from "./UptimeComparisonCard";
import UptimeLabelCard from "./UptimeLabelCard";
export default function HomePage() {
@ -30,7 +32,6 @@ export default function HomePage() {
return(
<div className="App">
<div className={"w-100 row"}>
<div className={"col-md-6 d-flex justify-content-center flex-column align-items-center"}>
<img src={NWSLogo} alt="nws-logo" style={{width: "70%"}}/>
@ -45,7 +46,10 @@ export default function HomePage() {
</p>
</div>
</div>
<div className={"w-100 mt-2 flex justify-content-center align-content-center text-center"}>
<h3><i>Better uptime than GitHub Pages!</i></h3>
<h4><a href={"https://youtu.be/WHdXWMFHuqA"} target="_blank" rel="noopener noreferrer">Watch the NWS Deployment Demo</a></h4>
</div>
<div style={{width: '75vw'}}>
<hr/>
</div>
@ -53,10 +57,11 @@ export default function HomePage() {
<div className={"text-left row"} style={{width: '75vw'}}>
<h2>Compare us to our competitors</h2>
<p>Last updated at {new Date(uptime.lastUpdated).toLocaleString()}</p>
<div className={"col-12 row w-100 m-0"}>
<div className={"col-12 row w-100 m-0 align-content-center d-flex justify-content-center pt-2"}>
<UptimeLabelCard/>
{uptime.competitors.sort((a,b)=>{return b.uptimeMonth === a.uptimeMonth ? (a.name === "NWS" ? -1000 : b.name.localeCompare(a.name)) : b.uptimeMonth - a.uptimeMonth}).map((e) => {
return (
<UptimeCard uptime={e} isService={false}/>
<UptimeComparisonCard uptime={e} isService={false}/>
);
})}
</div>

View file

@ -26,3 +26,16 @@
width: 500px;
max-width: 100vw;
}
.stat-perfect {
font-weight: bold;
color: #069D06
}
.stat-middle {
color: #877E1C
}
.stat-bad {
color: #921111
}

View file

@ -0,0 +1,80 @@
import {UptimeRecord} from "../nws-api/types";
import React, {useState} from "react";
import '../App.css';
import "./UptimeCard.css"
import Modal from "react-modal";
function getUptimeClass(uptime: number) {
if(uptime === 100) {
return "stat-perfect";
}
if(uptime >= 95) {
return "stat-middle";
}
return "stat-bad";
}
function getResponseTimeClass(respTime: number) {
// https://www.littledata.io/average/server-response-time
if(respTime < 205) {
return "stat-perfect";
}
if(respTime < 495) {
return "stat-middle";
}
return "stat-bad";
}
export default function UptimeComparisonCard(props: {uptime: UptimeRecord, isService: boolean}) {
const [isModalOpen, setModalOpen] = useState(false);
return(
<div className={"col-12 col-md-2 mb-2 p-0 m-0 text-center"}>
<div style={{height: 25, margin: 0}}>
<h4 className={"uptime-lnk"} onClick={()=>setModalOpen(true)}>{props.uptime.name}</h4>
</div>
<hr/>
<p className={"fw-bold d-md-none"}>Uptime (Last Month)</p>
<p className={getUptimeClass(props.uptime.uptimeMonth)}>{props.uptime.uptimeMonth}%</p>
<hr/>
<p className={"fw-bold d-md-none"}>Uptime ({new Date().getFullYear()} YTD)</p>
<p className={getUptimeClass(props.uptime.uptimeYtd)}>{props.uptime.uptimeYtd}%</p>
<hr/>
<p className={"fw-bold d-md-none"}>Avg Response Time (24hr)</p>
<p className={getResponseTimeClass(props.uptime.averageResponseTime)}>{props.uptime.averageResponseTime}ms</p>
<hr/>
<p className={"fw-bold d-md-none"}>Current Status</p>
<div className={`p-1 d-flex justify-content-start w-100`}>
<p className={`fw-bold severity-label w-100
${props.uptime.isUp ? 'low' : (props.uptime.undergoingMaintenance ? 'med' : 'high')}-severity`}
>
{props.uptime.isUp ? 'Up' : (props.uptime.undergoingMaintenance ? 'Maintenance' : 'Down')}
</p>
</div>
<Modal className={"uptime-modal"} isOpen={isModalOpen}>
<div className={"mb-3"}>
<h1 className={"mb-0"}>{props.uptime.name}</h1>
{props.uptime.url && <p>(<a href={props.uptime.url}>{props.uptime.url}</a>)</p>}
</div>
<div className={"mb-3"}>
<p>Monitoring since {props.uptime.monitorStart}</p>
<p><b>{new Date().getFullYear()} Uptime (YTD):</b> {props.uptime.uptimeYtd}%</p>
<p><b>Last Month Uptime:</b> {props.uptime.uptimeMonth}%</p>
<p><b>All-Time Uptime:</b> {props.uptime.uptimeAllTime}%</p>
<p><b>Average Response Time:</b> {props.uptime.averageResponseTime}ms</p>
</div>
{
props.isService &&
<div className={"mb-3"}>
<i>Note that the uptime and performance of services hosted on NWS may be affected by factors not controlled by NWS such as bad bad optimization or buggy software.</i>
</div>
}
<button className={"w-100"} onClick={()=>setModalOpen(false)}>Close</button>
</Modal>
</div>
);
}

View file

@ -0,0 +1,24 @@
import {UptimeRecord} from "../nws-api/types";
import React, {useState} from "react";
import '../App.css';
import "./UptimeCard.css"
import Modal from "react-modal";
export default function UptimeLabelCard() {
return(
<div className={"col-2 p-0 d-none d-md-block mb-2 m-0 text-center"}>
<div style={{height: 25, margin: 0}}>
<p className={"fw-bold"}>Service Name</p>
</div>
<hr/>
<p className={"fw-bold"}>Uptime (Last Month)</p>
<hr/>
<p className={"fw-bold"}>Uptime ({new Date().getFullYear()} YTD)</p>
<hr/>
<p className={"fw-bold"}>Avg Response Time (24hr)</p>
<hr/>
<p className={"fw-bold"}>Current Status</p>
</div>
);
}

View file

@ -20,49 +20,67 @@ import VerifyPage from "./components/VerifyPage";
import DashboardPage from "./components/DashboardPage";
import CreateCruisePage from "./components/CreateCruisePage";
import HomePage from "./components/HomePage";
import NavbarCollapse from "react-bootstrap/NavbarCollapse";
import NavbarOffcanvas from "react-bootstrap/NavbarOffcanvas";
function Layout (props: {children: any}) {
return (
<div>
<Navbar sticky={"top"} style={{height: "8vh", backgroundColor: "#eee", paddingLeft: "5vw", paddingRight: "5vw", maxWidth:"100%"}} className={"row m-0"}>
<div className={"col-10"}>
<NavbarBrand>
<img src={NWSLogo} alt="nws-logo" style={{width: 120}}/>
</NavbarBrand>
<NavLink className={"nav-lnk"} to={"/"}>
Home
</NavLink>
<NavLink className={"nav-lnk"} to={"/status"}>
Status
</NavLink>
</div>
{/*<NavLink className={"nav-lnk"} to={"/blogs"}>*/}
{/* Blog*/}
{/*</NavLink>*/}
<div className={"col-2 d-none d-md-block"}>
{ localStorage.getItem("session_key") === null &&
(
<NavLink className={"nav-lnk"} to={"/login"}>
Login
</NavLink>
<header className={"w-100 sticky-top"}>
<div className={"w-100"}>
<Navbar sticky={"top"} expand="lg" className={"row justify-content-center m-0 p-0"} style={{backgroundColor: "#eee"}}>
<div className={"row w-100"}>
<div className="row w-100 d-md-none d-sm-block">
<div className={"col-9"}>
<Navbar.Brand href="/">
<img src={NWSLogo} width={150}/>
</Navbar.Brand>
</div>
<div className={"col-2 ml-3 d-flex align-content-center justify-content-center"}>
<Navbar.Toggle className={"h-50 align-self-center"} aria-controls="basic-navbar-nav"/>
</div>
</div>
<div className={"d-md-block d-none col-2"}>
<Navbar.Brand href="/">
<img src={NWSLogo} width={150}/>
</Navbar.Brand>
</div>
<Navbar.Collapse id="basic-navbar-nav" className={"col-10"}>
<Nav className="row w-100 ml-5">
<div className="col-md-4 row">
<NavLink className="col-sm-12 col-md-3 nav-lnk align-self-center" to={"/"}>Home</NavLink>
<NavLink className="col-sm-12 col-md-3 nav-lnk align-self-center" to={"/status"}>Status</NavLink>
</div>
<div className="col-md-6"/>
<div className={"col-md-2 d-md-block d-none"}>
{ localStorage.getItem("session_key") === null &&
(
<NavLink className={"nav-lnk"} to={"/login"}>
Login
</NavLink>
)
}
{ localStorage.getItem("session_key") === null ||
(
<NavDropdown title={"Account"} className={"nav-lnk"}>
<NavLink className={"nav-lnk"} to={"/dashboard"}>
Dashboard
</NavLink>
<hr/>
<NavLink className={"nav-lnk"} to={"/login"} onClick={()=>{localStorage.removeItem("session_key")}}>
Logout
</NavLink>
</NavDropdown>
)
}
</div>
</Navbar>
)
}
{ localStorage.getItem("session_key") === null ||
(
<NavDropdown title={"Account"} className={"nav-lnk"}>
<NavLink className={"nav-lnk"} to={"/dashboard"}>
Dashboard
</NavLink>
<hr/>
<NavLink className={"nav-lnk"} to={"/login"} onClick={()=>{localStorage.removeItem("session_key")}}>
Logout
</NavLink>
</NavDropdown>
)
}
</div>
</Nav>
</Navbar.Collapse>
</div>
</Navbar>
</div>
</header>
<div style={{minHeight: "92vh"}}>
{props.children}
</div>