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:
csawatzky 2025-03-26 14:38:31 -06:00
parent b4da0d6859
commit 022925d7d7
41 changed files with 8895 additions and 79 deletions

314
src/weather/weather.tsx Normal file
View 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))}&#176; /{" "}
{Math.round(celsiusConverter(currentLow))}&#176;
</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))}&#176; / {Math.round(celsiusConverter(low))}&#176;
</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))}&#8451;
</Typography>
</Box>
<Box className={classes.lowerSquare}>
<Typography variant="subtitle1" style={{ fontSize: isMobile ? 10 : 15 }}>
Feels like {Math.round(celsiusConverter(currentConditions.main.feels_like))}
&#8451;
</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
View 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} />;
}
}