mirror of
https://github.com/furyhawk/home_stack.git
synced 2026-07-20 17:56:37 +00:00
refactor: Add WeatherMap component with Leaflet integration for displaying air temperature readings
This commit is contained in:
@@ -20,6 +20,8 @@ import {
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { createListCollection } from "@ark-ui/react"
|
||||
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
import { WeatherService } from "@/client/sdk.gen"
|
||||
|
||||
@@ -502,6 +504,57 @@ function WindDirection() {
|
||||
)
|
||||
}
|
||||
|
||||
function WeatherMap() {
|
||||
const { data, isLoading, error } = useQuery<ApiNestedResponse<AirTemperaturePayload>>({
|
||||
queryKey: ["weather", "air-temperature"],
|
||||
queryFn: () => WeatherService.getAirTemperature() as Promise<ApiNestedResponse<AirTemperaturePayload>>,
|
||||
refetchInterval: 1000 * 60 * 30, // Refetch every 30 minutes
|
||||
});
|
||||
|
||||
if (isLoading) return <Spinner />;
|
||||
if (error || !data?.data) return <Text color="red.500">Error loading map data</Text>;
|
||||
|
||||
const { stations = [], readings = [] } = data.data;
|
||||
|
||||
if (stations.length === 0 || readings.length === 0) {
|
||||
return <Text>No map data available</Text>;
|
||||
}
|
||||
|
||||
// Get the latest reading
|
||||
const latestReading = readings[0];
|
||||
if (!latestReading || !latestReading.data) {
|
||||
return <Text>No map data available</Text>;
|
||||
}
|
||||
|
||||
// Create a map of station IDs to station details
|
||||
const stationMap = new Map(stations.map(station => [station.id, station]));
|
||||
|
||||
return (
|
||||
<MapContainer center={[1.3521, 103.8198]} zoom={11} style={{ height: "500px", width: "100%" }}>
|
||||
<TileLayer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
attribution="© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
|
||||
/>
|
||||
{latestReading.data.map((reading) => {
|
||||
const station = stationMap.get(reading.stationId);
|
||||
if (!station) return null;
|
||||
|
||||
return (
|
||||
<Marker
|
||||
key={reading.stationId}
|
||||
position={[station.location.latitude, station.location.longitude]}
|
||||
>
|
||||
<Popup>
|
||||
<Text fontWeight="bold">{station.name}</Text>
|
||||
<Text>Temperature: {reading.value?.toFixed(1)}°C</Text>
|
||||
</Popup>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
</MapContainer>
|
||||
);
|
||||
}
|
||||
|
||||
// Define tab values for namespaced Tabs
|
||||
const tabValues = {
|
||||
twoHour: "twoHourForecast",
|
||||
@@ -509,6 +562,7 @@ const tabValues = {
|
||||
fourDay: "fourDayOutlook",
|
||||
stats: "weatherStatistics",
|
||||
windDir: "windDirection",
|
||||
weatherMap: "weatherMap",
|
||||
}
|
||||
|
||||
function WeatherHub() {
|
||||
@@ -529,6 +583,7 @@ function WeatherHub() {
|
||||
<ChakraTabs.Trigger value={tabValues.fourDay}>4-Day Outlook</ChakraTabs.Trigger>
|
||||
<ChakraTabs.Trigger value={tabValues.stats}>Statistics</ChakraTabs.Trigger>
|
||||
<ChakraTabs.Trigger value={tabValues.windDir}>Wind Direction</ChakraTabs.Trigger>
|
||||
<ChakraTabs.Trigger value={tabValues.weatherMap}>Weather Map</ChakraTabs.Trigger>
|
||||
</ChakraTabs.List>
|
||||
|
||||
<ChakraTabs.ContentGroup>
|
||||
@@ -547,6 +602,9 @@ function WeatherHub() {
|
||||
<ChakraTabs.Content value={tabValues.windDir}>
|
||||
<WindDirection />
|
||||
</ChakraTabs.Content>
|
||||
<ChakraTabs.Content value={tabValues.weatherMap}>
|
||||
<WeatherMap />
|
||||
</ChakraTabs.Content>
|
||||
</ChakraTabs.ContentGroup>
|
||||
</ChakraTabs.Root>
|
||||
</Container>
|
||||
|
||||
Generated
+74
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "home_stack",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"leaflet": "^1.9.4",
|
||||
"react-leaflet": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-leaflet/core": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz",
|
||||
"integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==",
|
||||
"license": "Hippocratic-2.1",
|
||||
"peerDependencies": {
|
||||
"leaflet": "^1.9.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/leaflet": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
|
||||
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.26.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-leaflet": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz",
|
||||
"integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==",
|
||||
"license": "Hippocratic-2.1",
|
||||
"dependencies": {
|
||||
"@react-leaflet/core": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"leaflet": "^1.9.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.26.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
|
||||
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"leaflet": "^1.9.4",
|
||||
"react-leaflet": "^5.0.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user