ag visual farm added to the dev branch field related stuff not imported yet, and the geocoder has some bugs with the new version
This commit is contained in:
parent
b4da0d6859
commit
022925d7d7
41 changed files with 8895 additions and 79 deletions
314
src/weather/weather.tsx
Normal file
314
src/weather/weather.tsx
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
import {
|
||||
Box,
|
||||
Grid2 as Grid,
|
||||
LinearProgress,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import OpenWeatherMap from "openweathermap-ts";
|
||||
import { CurrentResponse, ThreeHourResponse } from "openweathermap-ts/dist/types";
|
||||
import { useEffect } from "react";
|
||||
//import WeatherIcon from "./weatherIcon";
|
||||
import { getThemeType } from "theme";
|
||||
import { useMobile, useThemeType } from "hooks";
|
||||
import WindSpeedDark from "assets/components/windSpeedDark.png";
|
||||
import WindSpeedLight from "assets/components/windSpeedLight.png";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
//import { WiHumidity } from "weather-icons-react";
|
||||
|
||||
const openWeather = new OpenWeatherMap({
|
||||
//apiKey: process.env.REACT_APP_OPEN_WEATHERMAP ? process.env.REACT_APP_OPEN_WEATHERMAP : ""
|
||||
apiKey: import.meta.env.REACT_APP_OPEN_WEATHERMAP ? import.meta.env.REACT_APP_OPEN_WEATHERMAP : ""
|
||||
});
|
||||
|
||||
interface Props {
|
||||
longitude?: number;
|
||||
latitude?: number;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
currentBox: {
|
||||
boxShadow: "0px 0px 10px black",
|
||||
height: "110px",
|
||||
borderRadius: 10,
|
||||
margin: 7
|
||||
},
|
||||
upperSquare: {
|
||||
height: "75%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
},
|
||||
lowerSquare: {
|
||||
height: "25%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
},
|
||||
dark: {
|
||||
backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
|
||||
padding: 5,
|
||||
opacity: 1
|
||||
},
|
||||
light: {
|
||||
backgroundColor: getThemeType() === "light" ? "rgb(235, 235, 235)" : "rgb(60, 60, 60)",
|
||||
padding: 5,
|
||||
opacity: 1
|
||||
}
|
||||
}))
|
||||
|
||||
export default function Weather(props: Props) {
|
||||
const [currentConditions, setCurrentConditions] = useState<CurrentResponse>();
|
||||
const [forecast, setForecast] = useState<ThreeHourResponse>();
|
||||
const classes = useStyles();
|
||||
const isMobile = useMobile();
|
||||
const themeType = useThemeType();
|
||||
|
||||
useEffect(() => {
|
||||
if (props.longitude && props.latitude) {
|
||||
openWeather
|
||||
.getThreeHourForecastByGeoCoordinates(props.latitude, props.longitude)
|
||||
.then(forecast => {
|
||||
setForecast(forecast);
|
||||
});
|
||||
openWeather
|
||||
.getCurrentWeatherByGeoCoordinates(props.latitude, props.longitude)
|
||||
.then(weather => {
|
||||
setCurrentConditions(weather);
|
||||
});
|
||||
}
|
||||
}, [props.latitude, props.longitude]);
|
||||
|
||||
const celsiusConverter = (temp: number) => {
|
||||
return (temp - 32) * (5 / 9);
|
||||
};
|
||||
|
||||
/**
|
||||
* gets the high and low of the first 8 readings in the 5 day forecast, is technically getting the high and low for tomorrow
|
||||
* but is usually close to the same temperatures, for actual current high/low must use a paid plan for open weather
|
||||
* @returns
|
||||
*/
|
||||
const getHighLow = () => {
|
||||
if (!forecast) return;
|
||||
let loopCounter = 0;
|
||||
let currentHigh = -1000;
|
||||
let currentLow = 1000;
|
||||
while (loopCounter <= 7) {
|
||||
let temp = forecast.list[loopCounter].main.temp;
|
||||
if (temp < currentLow) {
|
||||
currentLow = temp;
|
||||
}
|
||||
if (temp > currentHigh) {
|
||||
currentHigh = temp;
|
||||
}
|
||||
loopCounter++;
|
||||
}
|
||||
return (
|
||||
<Typography variant="h5" style={{ fontSize: 25 }}>
|
||||
{Math.round(celsiusConverter(currentHigh))}° /{" "}
|
||||
{Math.round(celsiusConverter(currentLow))}°
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
const getDirection = (current: CurrentResponse) => {
|
||||
if (!current) return;
|
||||
let windDegrees = current.wind.deg;
|
||||
let direction = "";
|
||||
|
||||
if (windDegrees > 338 || windDegrees <= 23) {
|
||||
direction = "N";
|
||||
}
|
||||
if (windDegrees > 23 && windDegrees <= 67) {
|
||||
direction = "NE";
|
||||
}
|
||||
if (windDegrees > 67 && windDegrees <= 112) {
|
||||
direction = "E";
|
||||
}
|
||||
if (windDegrees > 112 && windDegrees <= 158) {
|
||||
direction = "SE";
|
||||
}
|
||||
if (windDegrees > 158 && windDegrees <= 203) {
|
||||
direction = "S";
|
||||
}
|
||||
if (windDegrees > 203 && windDegrees <= 248) {
|
||||
direction = "SW";
|
||||
}
|
||||
if (windDegrees > 248 && windDegrees <= 293) {
|
||||
direction = "W";
|
||||
}
|
||||
if (windDegrees > 293 && windDegrees <= 338) {
|
||||
direction = "NW";
|
||||
}
|
||||
return direction;
|
||||
};
|
||||
|
||||
const dayOfWeek = (day: number) => {
|
||||
switch (day) {
|
||||
case 1:
|
||||
return "Monday";
|
||||
case 2:
|
||||
return "Tuesday";
|
||||
case 3:
|
||||
return "Wednesday";
|
||||
case 4:
|
||||
return "Thursday";
|
||||
case 5:
|
||||
return "Friday";
|
||||
case 6:
|
||||
return "Saturday";
|
||||
default:
|
||||
return "Sunday";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Three hour response contains a list of 40 items for the weather, each 8 is a 24 hour period
|
||||
* loop through 8 items to get the forecast for that 24 hour period
|
||||
* @param forecast the three hour response that was retrieved
|
||||
* @param day the day we are getting the forecast for as a number
|
||||
*/
|
||||
const getForeCast = (day: number) => {
|
||||
if (!forecast) return;
|
||||
let startingPoint = day * 8;
|
||||
let loopCount = 0;
|
||||
let high = -1000;
|
||||
let low = 1000;
|
||||
let d = forecast.list[startingPoint + 4].dt;
|
||||
let date = new Date(0);
|
||||
date.setUTCSeconds(d);
|
||||
|
||||
while (loopCount < 8) {
|
||||
let temp = forecast.list[startingPoint].main.temp;
|
||||
if (temp > high) {
|
||||
high = temp;
|
||||
}
|
||||
if (temp < low) {
|
||||
low = temp;
|
||||
}
|
||||
startingPoint++;
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box className={day % 2 === 0 ? classes.dark : classes.light}>
|
||||
<Box style={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Typography variant="subtitle1" style={{ fontWeight: 600 }}>
|
||||
{dayOfWeek(date.getDay())}
|
||||
</Typography>
|
||||
<Typography variant="subtitle1" style={{ fontWeight: 600 }}>
|
||||
{Math.round(celsiusConverter(high))}° / {Math.round(celsiusConverter(low))}°
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box padding="25px">
|
||||
{currentConditions && forecast ? (
|
||||
<Box>
|
||||
<Box component="span">
|
||||
<Typography style={{ fontSize: 20, fontWeight: 750 }}>
|
||||
Current Weather - {dayOfWeek(new Date().getDay())}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Grid container direction="row">
|
||||
<Grid size={6}>
|
||||
<Box className={classes.currentBox}>
|
||||
<Box
|
||||
padding="5%"
|
||||
className={classes.upperSquare}
|
||||
style={{ flexDirection: isMobile ? "column" : "row" }}>
|
||||
{/* <WeatherIcon
|
||||
openweatherIconId={currentConditions.weather[0].id}
|
||||
size={isMobile ? 35 : 50}
|
||||
/> */}
|
||||
<Typography variant="body1" style={{ fontSize: 25 }}>
|
||||
{Math.round(celsiusConverter(currentConditions.main.temp))}℃
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className={classes.lowerSquare}>
|
||||
<Typography variant="subtitle1" style={{ fontSize: isMobile ? 10 : 15 }}>
|
||||
Feels like {Math.round(celsiusConverter(currentConditions.main.feels_like))}
|
||||
℃
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid size={6}>
|
||||
<Box className={classes.currentBox}>
|
||||
<Box
|
||||
className={classes.upperSquare}
|
||||
style={{ flexDirection: isMobile ? "column" : "row" }}>
|
||||
{/* <WiHumidity size={isMobile ? 35 : 50} /> */}
|
||||
<Typography variant="body1" style={{ fontSize: 25, display: "inline" }}>
|
||||
{currentConditions.main.humidity}%
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className={classes.lowerSquare}>
|
||||
<Typography variant="subtitle1" style={{ fontSize: isMobile ? 10 : 15 }}>
|
||||
Humidity
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid size={6}>
|
||||
<Box className={classes.currentBox}>
|
||||
<Box
|
||||
className={classes.upperSquare}
|
||||
style={{ flexDirection: isMobile ? "column" : "row" }}>
|
||||
<img
|
||||
src={themeType === "light" ? WindSpeedDark : WindSpeedLight}
|
||||
alt="Wind Speed"
|
||||
height={isMobile ? 35 : 50}
|
||||
width={isMobile ? 35 : 50}
|
||||
/>
|
||||
<Box>
|
||||
<Typography variant="body1" style={{ fontSize: 25, display: "inline" }}>
|
||||
{Math.round(currentConditions.wind.speed * 3.6)}/
|
||||
</Typography>
|
||||
<Typography variant="subtitle1" style={{ fontSize: 15, display: "inline" }}>
|
||||
km/h
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className={classes.lowerSquare}>
|
||||
<Typography variant="subtitle1" style={{ fontSize: isMobile ? 10 : 15 }}>
|
||||
Direction {getDirection(currentConditions)}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid size={6}>
|
||||
<Box className={classes.currentBox}>
|
||||
<Box className={classes.upperSquare} style={{ paddingTop: isMobile ? 35 : 0 }}>
|
||||
{getHighLow()}
|
||||
</Box>
|
||||
<Box className={classes.lowerSquare}>
|
||||
<Typography variant="subtitle1" style={{ fontSize: isMobile ? 10 : 15 }}>
|
||||
Today's High/Low
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box component="span">
|
||||
<Typography style={{ fontSize: 20, fontWeight: 750 }}>5 - Day Forecast</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
{getForeCast(0)}
|
||||
{getForeCast(1)}
|
||||
{getForeCast(2)}
|
||||
{getForeCast(3)}
|
||||
{getForeCast(4)}
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<Box paddingTop="20px">
|
||||
<LinearProgress color="primary" />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
114
src/weather/weatherIcon.tsx
Normal file
114
src/weather/weatherIcon.tsx
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import { AcUnit, Cloud, LightMode, Thunderstorm, WaterDrop } from "@mui/icons-material";
|
||||
// import {
|
||||
// WiDaySunny,
|
||||
// WiDayCloudy,
|
||||
// WiDaySunnyOvercast,
|
||||
// WiDayLightning,
|
||||
// WiDayStormShowers,
|
||||
// WiDayThunderstorm,
|
||||
// WiDaySprinkle,
|
||||
// WiDayRainMix,
|
||||
// WiDayRain,
|
||||
// WiDayShowers,
|
||||
// WiDayRainWind,
|
||||
// WiDaySleet,
|
||||
// WiDaySnow,
|
||||
// WiDayFog,
|
||||
// WiDayHaze,
|
||||
// WiDust,
|
||||
// WiSmoke,
|
||||
// WiVolcano,
|
||||
// WiTornado
|
||||
// } from "weather-icons-react";
|
||||
|
||||
interface Props {
|
||||
openweatherIconId: number;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
//need to get Dustin/Sandaru to make some custom weather icons
|
||||
export default function WeatherIcon(props: Props) {
|
||||
const size = props.size ? props.size : 25;
|
||||
const iconId = props.openweatherIconId;
|
||||
|
||||
switch (iconId) {
|
||||
case 200:
|
||||
case 210:
|
||||
case 221:
|
||||
case 230:
|
||||
//return <WiDayLightning size={size} />;
|
||||
case 201:
|
||||
case 211:
|
||||
case 231:
|
||||
//return <WiDayStormShowers size={size} />;
|
||||
case 202:
|
||||
case 212:
|
||||
case 232:
|
||||
return <Thunderstorm />
|
||||
//return <WiDayThunderstorm size={size} />;
|
||||
case 300:
|
||||
case 301:
|
||||
case 302:
|
||||
case 500:
|
||||
//return <WiDaySprinkle size={size} />;
|
||||
case 310:
|
||||
case 311:
|
||||
case 312:
|
||||
case 501:
|
||||
//return <WiDayRainMix size={size} />;
|
||||
case 502:
|
||||
case 503:
|
||||
case 522:
|
||||
//return <WiDayRain size={size} />;
|
||||
case 314:
|
||||
case 321:
|
||||
case 520:
|
||||
case 521:
|
||||
case 531:
|
||||
//return <WiDayShowers size={size} />;
|
||||
case 504:
|
||||
//return <WiDayRainWind size={size} />;
|
||||
case 511:
|
||||
case 611:
|
||||
case 612:
|
||||
case 613:
|
||||
case 615:
|
||||
case 616:
|
||||
case 620:
|
||||
case 621:
|
||||
case 622:
|
||||
return <WaterDrop />
|
||||
//return <WiDaySleet size={size} />;
|
||||
case 600:
|
||||
case 601:
|
||||
case 602:
|
||||
return <AcUnit />
|
||||
//return <WiDaySnow size={size} />;
|
||||
// case 701:
|
||||
// case 741:
|
||||
// return <WiDayFog size={size} />;
|
||||
// case 711:
|
||||
// return <WiSmoke size={size} />;
|
||||
// case 721:
|
||||
// return <WiDayHaze size={size} />;
|
||||
// case 731:
|
||||
// case 751:
|
||||
// case 761:
|
||||
// return <WiDust size={size} />;
|
||||
// case 762:
|
||||
// return <WiVolcano size={size} />;
|
||||
// case 771:
|
||||
// case 781:
|
||||
// return <WiTornado size={size} />;
|
||||
case 801:
|
||||
case 802:
|
||||
//return <WiDaySunnyOvercast size={size} />;
|
||||
case 803:
|
||||
case 804:
|
||||
return <Cloud />
|
||||
//return <WiDayCloudy size={size} />;
|
||||
default:
|
||||
return <LightMode />
|
||||
//return <WiDaySunny size={size} />;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue