Skip to content

Commit

Permalink
Added air quality index
Browse files Browse the repository at this point in the history
  • Loading branch information
jamie6king committed Nov 19, 2024
1 parent 0a6d1a7 commit 44d4d25
Show file tree
Hide file tree
Showing 7 changed files with 1,534 additions and 118 deletions.
175 changes: 115 additions & 60 deletions client/Show.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React, { useEffect, useState } from "react";
import { Link, useSearchParams } from "react-router-dom";

import { BarLoader } from "react-spinners";
import { BarLoader, BeatLoader } from "react-spinners";
import { FaLocationDot } from "react-icons/fa6";
import { IoIosArrowBack } from "react-icons/io";

Expand All @@ -14,6 +14,7 @@ import enLocale from "i18n-iso-countries/langs/en.json";

// import styles
import * as Styles from "./styles/show.module.scss";
import GaugeComponent from "react-gauge-component";


export default function Weather() {
Expand All @@ -28,11 +29,13 @@ export default function Weather() {

const [ mainLoading, setMainLoading ] = useState(true);
const [ forecastLoading, setForecastLoading ] = useState(true);
const [ airQualityLoading, setAirQualityLoading ] = useState(true)

const [ data, setData ] = useState();
const [ localTime, setLocalTime ] = useState();
const [ localDayOrNight, setLocalDayOrNight ] = useState();
const [ forecastData, setForecastData ] = useState();
const [ airQualityData, setAirQualityData ] = useState();


useEffect(() => {
Expand All @@ -43,6 +46,7 @@ export default function Weather() {
// urls
const weatherUrl = "http://localhost:3000/weather";
const forecastUrl = "http://localhost:3000/forecast";
const airQualityUrl = "http://localhost:3000/airquality";
const lat = searchParams.get("lat");
const lon = searchParams.get("lon");
const tz = tz_lookup(lat, lon)
Expand All @@ -69,9 +73,21 @@ export default function Weather() {
body: JSON.stringify({ lat, lon }),
});
const forecastData = await forecastResponse.json();

setForecastData(forecastData);
setForecastLoading(false);

// get air quality data
const airQualityResponse = await fetch(airQualityUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ lat, lon })
});
const airQualityData = await airQualityResponse.json();

setAirQualityData(airQualityData)
setAirQualityLoading(false);

} catch (error) {

// log error
Expand All @@ -92,90 +108,129 @@ export default function Weather() {

// render page
return (
<div className={Styles.main}>
<div className={Styles.main}>

<div className={Styles.weather}>
<div className={Styles.weather}>

{ (mainLoading) ? (
{ (mainLoading) ? (

<BarLoader color="#ffffff" cssOverride={{ width: "100%" }} />
<BarLoader color="#ffffff" cssOverride={{ width: "100%" }} />

) : (
<>
<div className={Styles.locationBar} data-testid="locationbar">
) : (
<>
<div className={Styles.locationBar} data-testid="locationbar">

<Link to="/"><IoIosArrowBack className={Styles.backIcon} /></Link>
<Link to="/"><IoIosArrowBack className={Styles.backIcon} /></Link>

<FaLocationDot className={Styles.locationIcon} />
<p>{data.name}, {getName(data.sys.country, "en")}</p>
<FaLocationDot className={Styles.locationIcon} />
<p>{data.name}, {getName(data.sys.country, "en")}</p>

<p className={Styles.localTime}>
{localTime.toFormat("HH:mm")}
</p>
<p className={Styles.localTime}>
{localTime.toFormat("HH:mm")}
</p>

</div>
<div className={Styles.mainTemp}>

<div className={Styles.mainTempPanel}>
<div>
<i className={`owf owf-${data.weather[0].id}-${localDayOrNight} owf-3x`} />
</div>
<div className={Styles.mainTemp}>
<div className={Styles.mainTempPanel}>
<div>
<i className={`owf owf-${data.weather[0].id}-${localDayOrNight} owf-3x`} />

<p><span>{parseInt(data.main.temp).toString().padStart(2, "0")}</span>°C</p>
<p><span>{parseInt(data.main.temp).toString().padStart(2, "0")}</span>°C</p>

<p className={Styles.feelsLike}>Feels like <span>{parseInt(data.main.feels_like).toString().padStart(2, "0")}</span>°C</p>
<p className={Styles.feelsLike}>Feels like <span>{parseInt(data.main.feels_like).toString().padStart(2, "0")}</span>°C</p>
</div>
</div>
</div>

<div className={Styles.mainTempBoxes}>

<div className={Styles.mainTempBoxes}>
<div className={Styles.mainTempBox}>
{ (airQualityLoading) ? (
<BeatLoader color="#ffffff" />
) : (
<>
<p>Air Quality</p>
<GaugeComponent
type="semicircle"
value={airQualityData.list[0].main.aqi}
minValue={0}
maxValue={5}
arc={{
subArcs: [
{
limit: 1,
color: "#00ff00"
},
{
limit: 2,
color: "#7fff00"
},
{
limit: 3,
color: "#ffff00"
},
{
limit: 4,
color: "#ff7f00"
},
{
limit: 5,
color: "#ff0000"
}
]
}}
pointer={{ type: "blob", animationDelay: 0 }}
/>
</>
)}
</div>
</div>
</div>
</div>
</>
)}
</div>
<div className={Styles.info}>
</>
)}
</div>
<div className={Styles.info}>

{ (forecastLoading) ? (
{ (forecastLoading) ? (

<BarLoader color="#ffffff" cssOverride={{ width: "100%" }} />
<BarLoader color="#ffffff" cssOverride={{ width: "100%" }} />

) : (
<>
<div className={Styles.forecast}>
) : (
<>
<div className={Styles.forecast}>

<h1>5-Day Forecast</h1>
<h1>5-Day Forecast</h1>

<div className={Styles.forecastBox} data-testid="forecasts">
<div className={Styles.forecastBox} data-testid="forecasts">

{ forecastData.list.map((day) => {
{ forecastData.list.map((day) => {

const localDate = DateTime.fromSeconds(day.dt)
const date = localDate.setZone(localTime.zone);
const dateDayOrNight = (date.hour > 6 && date.hour < 20) ? "d" : "n";
const now = DateTime.now();
const dateString = (now.month < localDate.month || now.day < localDate.day) ? localDate.toFormat("dd/MM") : "";
const localDate = DateTime.fromSeconds(day.dt)
const date = localDate.setZone(localTime.zone);
const dateDayOrNight = (date.hour > 6 && date.hour < 20) ? "d" : "n";
const now = DateTime.now();
const dateString = (now.month < localDate.month || now.day < localDate.day) ? localDate.toFormat("dd/MM") : "";

return (
<div key={day.dt}>
<p className={Styles.forecastDate}>
<span>{dateString}</span><br />
{date.toFormat("HH:mm")}
</p>
return (
<div key={day.dt}>
<p className={Styles.forecastDate}>
<span>{dateString}</span><br />
{date.toFormat("HH:mm")}
</p>

<i className={`owf owf-${day.weather[0].id}-${dateDayOrNight} owf-5x`} />
<i className={`owf owf-${day.weather[0].id}-${dateDayOrNight} owf-5x`} />

<p className={Styles.forecastTemp}>
{parseInt(day.main.temp).toString().padStart(2, "0")}°C
</p>
</div>
);
})};
<p className={Styles.forecastTemp}>
{parseInt(day.main.temp).toString().padStart(2, "0")}°C
</p>
</div>
);
})};

</div>
</div>
</div>
</>
)};
</>
)};
</div>
</div>
</div>
);
};
30 changes: 29 additions & 1 deletion client/styles/show.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
margin: 16px;
margin-top: 0px;
display: grid;
grid-template-rows: 1fr 1fr;
grid-template-rows: auto min-content;
background-color: #1e1e1e;
border-radius: 16px;
}
Expand Down Expand Up @@ -84,7 +84,35 @@
}

.mainTempBoxes {
width: 100%;
padding: 16px;
overflow-x: auto;
display: flex;
gap: 16px;
border-radius: 16px;

}

.mainTempBox {
min-height: 300px;
min-width: 300px;
aspect-ratio: 1 / 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #2a2a2a;
border-radius: 16px;

p {
margin-bottom: 32px;
color: #ffffff;
font-size: 16pt;
}

div svg g g text {
font-family: "Fira Code", monospace;
}
}

.info {
Expand Down
Loading

0 comments on commit 44d4d25

Please sign in to comment.