Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update landing page with API server status DOC-934 #15

Merged
merged 2 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
addetz marked this conversation as resolved.
Show resolved Hide resolved


Use the [`docker-compose.yml`](./docker-compose.yml) to start the required services.
Expand Down Expand Up @@ -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.
10 changes: 9 additions & 1 deletion src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
148 changes: 83 additions & 65 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <div className="Click-header">
<div className="Click-counter">{`Click Count ${clickCount} 🤖 `}</div>
<div className="Server-status" > 🟢 API Server Connected </div>
</div>
}
if (apiStatus[0] === Status.Error) {
console.log(apiStatus[1])
return <div className="Click-header">
<div className="Click-counter">{`Click Count Not Available 🤖`}</div>
<div className="Server-status" > 🔴 API Server Connection Error </div>
</div>
}

return <div className="Click-header">
<div className="Click-counter">{`Click Count ${clickCount} 🌏`}</div>
<div className="Server-status" > ⚪️ API Server Not Configured </div>
</div>
}, [clickCount, apiStatus])

useEffect(() => {
setIsLogoVisible(true);
loadCount();
}, [loadCount])

return (
<div className="App">
<header className="App-header">
<Menu />
<div className="Header-items">
{ API_URI ? <span className="Click-counter">{`Clicked ${clickCount} 🤖 `}</span> : <span className="Click-counter">{`Clicked ${clickCount} 🌏`}</span>}
{getCounterHeader()}
<FadeIn isVisible={isLogoVisible}>
<SpinningComponent>
<div onClick={() => countUp()}>
Expand Down
Loading