From 7cbda6bdd8a821af481872662a50853ad69522a7 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Mon, 22 Jul 2024 23:19:49 +0100 Subject: [PATCH 1/4] feat: new Status component Pulls our status from StatusPage.io and renders a coloured dot based on the status indicator. Also refreshes every minute to keep pages up to date --- src/core/Status.tsx | 69 +++++++++++++++++++++++ src/core/Status/Status.stories.tsx | 89 ++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 src/core/Status.tsx create mode 100644 src/core/Status/Status.stories.tsx diff --git a/src/core/Status.tsx b/src/core/Status.tsx new file mode 100644 index 00000000..62513bda --- /dev/null +++ b/src/core/Status.tsx @@ -0,0 +1,69 @@ +import React, { useEffect, useState } from "react"; + +const indicatorClass = (indicator: string) => { + switch (indicator) { + case "none": + return "bg-green-500"; + case "operational": + return "bg-green-500"; + case "minor": + return "bg-yellow-500"; + case "major": + return "bg-orange-500"; + case "critical": + return "bg-orange-800"; + default: + return "bg-neutral-500"; + } +}; + +const Status = ({ + statusUrl, + additionalCSS, +}: { + statusUrl: string; + additionalCSS?: string; +}) => { + const [data, setData] = useState(null); + + useEffect(() => { + let interval; + + if (statusUrl !== "") { + const fetchData = async () => { + try { + const response = await fetch(statusUrl); + const jsonData = await response.json(); + setData(jsonData); + } catch (error) { + console.error("Error fetching status data:", error); + } + }; + + fetchData(); + + interval = setInterval(fetchData, 60000); // Fetch data every minute + } + + return () => { + clearInterval(interval); + }; + }, [statusUrl]); + + return ( + + + + + + ); +}; + +export default Status; diff --git a/src/core/Status/Status.stories.tsx b/src/core/Status/Status.stories.tsx new file mode 100644 index 00000000..70e6328d --- /dev/null +++ b/src/core/Status/Status.stories.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import { delay, http, HttpResponse } from "msw"; +import Status from "../Status"; + +const statusUrl = "https://ntqy1wz94gjv.statuspage.io/api/v2/status.json"; + +export default { + title: "JS Components/Status", + component: Status, + args: { + statusUrl, + }, + tags: ["!autodocs"], +}; + +export const Live = { + render: () => ( +

+ System status +

+ ), +}; + +export const Loading = { + parameters: { + msw: { + handlers: { + statusNone: http.get(statusUrl, async () => { + await delay("infinite"); + + return HttpResponse.json({ + status: { + indicator: "will never arrive", + }, + }); + }), + }, + }, + }, + render: () => , +}; + +const mockParametersWithStatus = (indicator) => { + return { + msw: { + handlers: { + status: http.get(statusUrl, async () => { + await delay(); + + return HttpResponse.json({ + status: { + indicator: indicator, + }, + }); + }), + }, + }, + }; +}; + +export const None = { + parameters: mockParametersWithStatus("none"), + render: () => , +}; + +export const Operational = { + parameters: mockParametersWithStatus("operational"), + render: () => , +}; + +export const Minor = { + parameters: mockParametersWithStatus("minor"), + render: () => , +}; + +export const Major = { + parameters: mockParametersWithStatus("major"), + render: () => , +}; + +export const Critical = { + parameters: mockParametersWithStatus("critical"), + render: () => , +}; + +export const Unknown = { + parameters: mockParametersWithStatus("unknown"), + render: () => , +}; From 72a5840582af002116abf8266ed9f262528d42f7 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Tue, 23 Jul 2024 00:02:13 +0100 Subject: [PATCH 2/4] chore: use new Status component in footer --- src/core/Footer.tsx | 15 ++++++--------- src/core/Footer/Footer.stories.tsx | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/core/Footer.tsx b/src/core/Footer.tsx index 6ceea2a9..e7a51b2f 100644 --- a/src/core/Footer.tsx +++ b/src/core/Footer.tsx @@ -2,6 +2,7 @@ import React from "react"; import Icon from "./Icon"; import _absUrl from "./url-base.js"; +import Status from "./Status.js"; type FooterProps = { paths: { @@ -12,11 +13,14 @@ type FooterProps = { fastestImplementation: string; }; urlBase: string; + statusUrl: string; }; -const Footer = ({ paths, urlBase }: FooterProps) => { +const Footer = ({ paths, urlBase, statusUrl }: FooterProps) => { const absUrl = (path) => _absUrl(path, urlBase); + // create a react hook that calls the statusUrl and returns the status of the system every minute + return (