diff --git a/package.json b/package.json
index 1782863..8451f13 100644
--- a/package.json
+++ b/package.json
@@ -7,10 +7,12 @@
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
- "preview": "vite preview"
+ "preview": "vite preview",
+ "fmt": "npx prettier . --write"
},
"dependencies": {
"@tanstack/react-query": "^5.102.8",
+ "country-codes-list": "^3.2.0",
"react": "^19.2.8",
"react-dom": "^19.2.8"
},
diff --git a/src/App.css b/src/App.css
index f460279..a4bc79d 100644
--- a/src/App.css
+++ b/src/App.css
@@ -61,7 +61,6 @@
flex-direction: column;
gap: 25px;
place-content: center;
- place-items: center;
flex-grow: 1;
@media (max-width: 1024px) {
diff --git a/src/components/listItem.tsx b/src/components/listItem.tsx
index b55799b..352c3c8 100644
--- a/src/components/listItem.tsx
+++ b/src/components/listItem.tsx
@@ -1,5 +1,5 @@
type cityWeather = {
- name: string
+ name?: string
temperature?: number
precipitation?: number
nextDays?: { time: string; temperature: number | undefined }[]
diff --git a/src/components/location-list.tsx b/src/components/location-list.tsx
index 9476553..0b5f007 100644
--- a/src/components/location-list.tsx
+++ b/src/components/location-list.tsx
@@ -1,13 +1,7 @@
-import type { WeatherApiResponse } from "../hooks/fetchWeather/types"
-import useGetWeather from "../hooks/fetchWeather/useGetWeather"
+import type { WeatherApiResponse, City } from "../hooks/fetchWeather/types"
+import { useGetWeatherForCities } from "../hooks/fetchWeather/useGetWeather"
import ListItem from "./listItem"
-type City = {
- name: string
- lat: number
- lon: number
-}
-
const cities: City[] = [
{ name: "Oslo", lat: 59.91273, lon: 10.74609 },
{ name: "Sørumsand", lat: 59.98621, lon: 11.24154 },
@@ -31,7 +25,12 @@ const getNextDays = (data?: WeatherApiResponse) => {
return (
date >= now &&
date.getUTCHours() === 12 &&
- date < new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000)
+ date <
+ new Date(
+ now.getTime() -
+ now.getHours() * 60 * 60 * 1000 +
+ 4 * 24 * 60 * 60 * 1000
+ )
)
})
.map((entry) => ({
@@ -43,23 +42,17 @@ const getNextDays = (data?: WeatherApiResponse) => {
}
const LocationList = () => {
- const weatherResults = cities.map((city) => useGetWeather(city.lat, city.lon))
-
- console.log(weatherResults)
-
- if (weatherResults.some((result) => result.isLoading)) {
- return
Loading weather…
- }
+ const { isLoading, results } = useGetWeatherForCities(cities)
- if (weatherResults.some((result) => result.error)) {
- return Could not load weather data.
+ if (isLoading) {
+ return Loading...
}
const cityWeather = cities.map((city, index) => ({
name: city.name,
- temperature: getTemperature(weatherResults[index]?.result),
- precipitation: getPrecipitation(weatherResults[index]?.result),
- nextDays: getNextDays(weatherResults[index]?.result),
+ temperature: getTemperature(results[index]),
+ precipitation: getPrecipitation(results[index]),
+ nextDays: getNextDays(results[index]),
}))
return (
@@ -98,10 +91,6 @@ const LocationList = () => {
>
{cityWeather.map((item) => (
- //
- // {item.name}: {typeof item.temperature === 'number' ? `${item.temperature}°` : '—'}
- // {typeof item.precipitation === 'number' ? `, ${item.precipitation} mm` : ''}
- //
))}
diff --git a/src/hooks/fetchWeather/types.ts b/src/hooks/fetchWeather/types.ts
index 1c008ba..74b5b75 100644
--- a/src/hooks/fetchWeather/types.ts
+++ b/src/hooks/fetchWeather/types.ts
@@ -175,4 +175,11 @@ export type METJSONForecast = {
type: "Feature"
}
+export type City = {
+ name?: string
+ lat: number
+ lon: number
+ alt?: number
+}
+
export type WeatherApiResponse = METJSONForecast
diff --git a/src/hooks/fetchWeather/useGetWeather.ts b/src/hooks/fetchWeather/useGetWeather.ts
index 163650e..e6cc108 100644
--- a/src/hooks/fetchWeather/useGetWeather.ts
+++ b/src/hooks/fetchWeather/useGetWeather.ts
@@ -1,12 +1,13 @@
-import { useQuery } from "@tanstack/react-query"
-import { type WeatherApiResponse } from "./types"
+import { useQuery, useQueries } from "@tanstack/react-query"
+import { type City, type WeatherApiResponse } from "./types"
-const useGetWeather = (lat: number, lon: number, alt?: number) => {
- let sanitized_alt = alt
- if (alt != undefined) {
- sanitized_alt = alt > 9000 ? 9000 : alt
- sanitized_alt = sanitized_alt < -500 ? -500 : sanitized_alt
- }
+const sanitizeAltitude = (alt?: number) => {
+ if (alt === undefined) return undefined
+ return Math.min(9000, Math.max(-500, alt))
+}
+
+export const useGetWeather = (lat: number, lon: number, alt?: number) => {
+ const sanitized_alt = sanitizeAltitude(alt)
const { isLoading, error, data } = useQuery({
queryKey: ["citySearch", `${lat}-${lon}`],
@@ -18,5 +19,33 @@ const useGetWeather = (lat: number, lon: number, alt?: number) => {
return { isLoading, error, result: data }
}
-
export default useGetWeather
+
+const fetchWeather = (
+ lat: number,
+ lon: number,
+ alt?: number
+): Promise => {
+ const sanitizedAlt = sanitizeAltitude(alt)
+ const url = `https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=${lat}&lon=${lon}${
+ sanitizedAlt !== undefined ? `&altitude=${sanitizedAlt}` : ""
+ }`
+ return fetch(url).then((res) => res.json() as Promise)
+}
+
+export const useGetWeatherForCities = (cities: City[]) => {
+ const queries = useQueries({
+ queries: cities.map((city) => ({
+ queryKey: ["citySearch", `${city.lat}-${city.lon}`],
+ queryFn: () => fetchWeather(city.lat, city.lon, city.alt),
+ })),
+ })
+
+ const isLoading = queries.some((q) => q.isLoading)
+ const errors = queries.filter((q) => q.error).map((q) => q.error)
+ const results = queries
+ .map((q) => q.data)
+ .filter((d): d is WeatherApiResponse => d !== undefined)
+
+ return { isLoading, errors, results }
+}