From 702d384bd3e094c2c1d3652a4a47ba0eaf068a53 Mon Sep 17 00:00:00 2001 From: addetz <43963729+addetz@users.noreply.github.com> Date: Wed, 20 Dec 2023 15:27:06 +0000 Subject: [PATCH 1/2] feat: update landing page with API server status DOC-934 This patch makes the following changes: - Adds API connection status - Add caching between renders with `useCallback` - Small update to the README --- README.md | 3 +- src/App.css | 10 +++- src/App.js | 148 +++++++++++++++++++++++++++++----------------------- 3 files changed, 93 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 6c684e1..2044ff8 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ REACT_APP_API_URI=http://localhost:3000 REACT_APP_API_VERSION=1 ``` -The `.env` file is how you point to the local development API server. Otherwise, you will use the global API counter. +The `.env` file is how you point to the local development API server. Use the [`docker-compose.yml`](./docker-compose.yml) to start the required services. @@ -118,5 +118,4 @@ To start the Caddy server with a reverse proxy use the command `make start-proxy ## Dependencies - [Caddy](https://caddyserver.com/docs/) -- [Count API](https://countapi.xyz/) is used to keep a global count of clicks. - [React Spring](https://github.com/pmndrs/react-spring) is used to animate the logo. diff --git a/src/App.css b/src/App.css index 25644d8..2d203dc 100644 --- a/src/App.css +++ b/src/App.css @@ -39,11 +39,19 @@ html { color: #61dafb; } -.Click-counter { +.Click-header { font-family: Poppins,Arial,Helvetica,sans-serif,Russo One; margin-bottom: 5%; } +.Click-counter { + margin-bottom: 5%; +} + +.Server-status { + font-size: calc(10px + 1vmin); +} + .App-footer { min-height: 20vh; } diff --git a/src/App.js b/src/App.js index d95319f..9ed2cc6 100644 --- a/src/App.js +++ b/src/App.js @@ -4,110 +4,128 @@ import linkedin from "./img/linkedin.png"; import mastodon from "./img/mastodon.png"; import logo_text from "./img/logo_text.png"; import { FadeIn, SpinningComponent } from "./components/Animated/Animated"; -import { useEffect, useState } from "react"; -import countapi from "countapi-js"; +import { useEffect, useState, useCallback } from "react"; import {randomLogo} from "./utilities/helpers"; import { env } from './env'; import { getCounter, postCounter } from "./utilities/requests"; import Menu from "./components/Animated/Menu/Menu"; +const Status = { + OK: "OK", + Error: "Connection error", + NotSet: "No API configured" +} + function App() { - const countapiKey = "f3dceeba-1841-42cf-b76c-26e9026dc0cf"; // Yes, it's an API key but it's not a secret. It's used to identify the counter. - const countapiNamespace = "spectrocloud.com"; const [isLogoVisible, setIsLogoVisible] = useState(false); const [clickCount, setClickCount] = useState(0); - const [connected, setConnected] = useState(false); const [firstLoad, setFirstLoad] = useState(true); + const [apiStatus, setAPIStatus] = useState([Status.NotSet, null]); let API_URI = env.REACT_APP_API_URI; let API_VERSION = env.REACT_APP_API_VERSION; let TOKEN = env.REACT_APP_TOKEN; - if (TOKEN == "undefined") { + if (TOKEN === "undefined") { TOKEN = "" } - if (API_URI == "undefined") { + if (API_URI === "undefined" || API_URI === undefined) { API_URI = "" } - if (API_VERSION === "" || API_VERSION == "undefined") { + if (API_VERSION === "" || API_VERSION === "undefined") { API_VERSION = 1 } - - useEffect(() => { - // Checks if internet is connected by attempting to load an image - const image = new Image(); - image.onload = () => {setConnected(true)}; - image.onerror = () => {setConnected(false)}; - image.src = "https://www.google.com/images/phd/px.gif"; - - setIsLogoVisible(true); - loadCount(); - }, []) - - async function loadCount() { - - // If an API URI is provided, use that to get the count - if (API_URI) { - let count; - try { - count = await getCounter(API_URI, API_VERSION, TOKEN); - if (count.message) { - count = 0; - throw new Error(`Error: Unable to connect to the API server on ${API_URI}. Please try again later. 😢`) - } - } catch(error) { - alert(`Error: Unable to connect to the API server on ${API_URI}. Please try again later. 😢`) - } finally { - setClickCount(count); - } - } - - - // If not connected to the internet, and no API URI is provided then use local storage for count. - if (API_URI == "" || API_URI === "undefined") { + + // useCallback enables caching between re-renders + const connectionError = useCallback(()=> { + return new Error(`Error: Unable to connect to the API server on ${API_URI}. Please try again later. 😢`) + }, [API_URI]) + + const loadCount = useCallback(async () => { + // If no API URI is provided then use local storage for count. + if (API_URI === "") { const count = localStorage.getItem("clickCount"); setClickCount(parseInt(count) || 0); + return } - } - async function countUp() { - - console.log("HERE") - - // If an API URI is provided, use that to update the count - if (API_URI) { - let count; - try { - count = await postCounter(API_URI, API_VERSION, TOKEN); - if (count.message) { - count = 0; - throw new Error(`Error: Unable to connect to the API server on ${API_URI}. Please try again later. 😢`) - } - } catch (error) { - alert(`Error: Unable to connect to the API server on ${API_URI}. Please try again later. 😢`) - } finally { - setClickCount(count); + // An API URI must have been provided, use that to get the count + let count; + try { + count = await getCounter(API_URI, API_VERSION, TOKEN); + setAPIStatus([Status.OK, null]) + if (count.message) { + count = 0; + setAPIStatus([Status.Error, connectionError()]) } + } catch(error) { + setAPIStatus([Status.Error, connectionError()]) + } finally { + setClickCount(count); + } + }, [API_URI, API_VERSION, TOKEN, connectionError]) + + const countUp = useCallback(async () => { + if (firstLoad) { + setFirstLoad(false); } - // If not connected to the internet, and no API URI is provided then use local storage for count. - if(API_URI == "" || API_URI === "undefined") { + // If no API URI is provided then use local storage for count. + if(API_URI === "") { setClickCount(clickCount + 1); localStorage.setItem("clickCount", clickCount); + return } - if (firstLoad) { - setFirstLoad(false); + // An API URI must have been provided, use that to update the count + let count; + try { + count = await postCounter(API_URI, API_VERSION, TOKEN); + setAPIStatus([Status.OK, null]) + if (count.message) { + count = 0; + setAPIStatus([Status.Error, connectionError()]) + } + } catch (error) { + setAPIStatus([Status.Error, connectionError()]) + } finally { + setClickCount(count); } - } + }, [API_URI, API_VERSION, TOKEN, connectionError, clickCount, firstLoad]) + + const getCounterHeader = useCallback(()=> { + if (apiStatus[0] === Status.OK) { + return
+
{`Click Count ${clickCount} 🤖 `}
+
🟢 API Server Connected
+
+ } + if (apiStatus[0] === Status.Error) { + console.log(apiStatus[1]) + return
+
{`Click Count Not Available 🤖`}
+
🔴 API Server Connection Error
+
+ } + + return
+
{`Click Count ${clickCount} 🌏`}
+
⚪️ API Server Not Configured
+
+ }, [clickCount, apiStatus]) + + useEffect(() => { + setIsLogoVisible(true); + loadCount(); + }, [loadCount]) return (
- { API_URI ? {`Clicked ${clickCount} 🤖 `} : {`Clicked ${clickCount} 🌏`}} + {getCounterHeader()}
countUp()}> From d0f128b8bd24cc34937c1e05202dbe9c61b9d257 Mon Sep 17 00:00:00 2001 From: Adelina Simion <43963729+addetz@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:24:21 +0000 Subject: [PATCH 2/2] Update README.md Co-authored-by: Karl Cardenas --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2044ff8..1bd8996 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ REACT_APP_API_URI=http://localhost:3000 REACT_APP_API_VERSION=1 ``` -The `.env` file is how you point to the local development API server. +The `.env` file is how you point to the local development API server. Otherwise, local browser storage is used. Use the [`docker-compose.yml`](./docker-compose.yml) to start the required services.