1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// This approach will fetch weather data from a Wunderground API, parse the JSON response,
// and display a simplified version of the current conditions in separate tiles. We'll use
// the fetch API to make the HTTP request and React for rendering the UI.
/** @jsxImportSource https://esm.sh/react */
import React, { useEffect, useState } from "https://esm.sh/react";
import { createRoot } from "https://esm.sh/react-dom/client";
function calculateDensityAltitude(elevation, temperature, pressure) {
// Convert temperature to Celsius
const tempC = (temperature - 32) * 5 / 9;
// Convert pressure from inHg to hPa
const pressureHpa = pressure * 33.86389;
// Calculate density altitude
const densityAltitude = elevation + (145366.45 * (1 - Math.pow(pressureHpa / 1013.25, 0.190284)));
return Math.round(densityAltitude);
}
function App() {
const [weatherData, setWeatherData] = useState(null);
const [error, setError] = useState(null);
const [lastChecked, setLastChecked] = useState(new Date());
const [consecutiveErrors, setConsecutiveErrors] = useState(0);
useEffect(() => {
const fetchWeather = () => {
setLastChecked(new Date());
fetch("/api/weather" + window.location.search)
.then(response => response.json())
.then(data => {
setWeatherData(data);
setConsecutiveErrors(0);
})
.catch(err => {
setError(err.message);
setConsecutiveErrors(prev => prev + 1);
});
};
fetchWeather(); // Fetch immediately on load
const intervalId = setInterval(() => {
if (consecutiveErrors < 5) {
fetchWeather();
} else {
setError("Too many errors occurred. Updates paused. Please refresh the page to try again.");
}
}, 60000); // 60000 ms = 1 minute
// Clean up the interval on component unmount
return () => clearInterval(intervalId);
}, [consecutiveErrors]);
if (error) return <div className="error">Error: {error}</div>;
if (!weatherData) return <div>Loading...</div>;
const densityAltitude = calculateDensityAltitude(
weatherData.elevation,
weatherData.temperature,
weatherData.pressure,
);
return (
<div className="weather-display">
<h1>Current Weather - {weatherData.stationName}</h1>
<div className="weather-tiles">
<div className="tile">
<h2>Conditions</h2>
<div className="tile-content">
<span>Temperature:</span>
<span>{weatherData.temperature}</span>
<span>°F</span>
<span>Humidity:</span>
<span>{weatherData.humidity}</span>
<span>%</span>
<span>Dewpoint:</span>
<span>{weatherData.dewpoint}</span>
<span>°F</span>
<span>Pressure:</span>
<span>{weatherData.pressure}</span>
<span>inHg</span>
</div>
</div>
<div className="tile">
<h2>Wind</h2>
<div className="tile-content">
<span>Wind Speed:</span>
<span>{weatherData.windSpeed}</span>
<span>mph</span>
<span>Direction:</span>
<span>{weatherData.windDirection}</span>
<span>°</span>
<span>Wind Gust:</span>
<span>{weatherData.windGust}</span>
<span>mph</span>
</div>
</div>