Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions vær/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vær/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/react-query": "^5.102.8",
"react": "^19.2.8",
"react-dom": "^19.2.8"
},
Expand Down
4 changes: 4 additions & 0 deletions vær/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import heroImg from './assets/hero.png'
import reactLogo from './assets/react.svg'
import viteLogo from './assets/vite.svg'
import './App.css'
import useGetWeather from './hooks/fetchWeather/useGetWeather'

function App() {
const [count, setCount] = useState(0)
// Example fetch, plz remove asap
const { result } = useGetWeather(67, 67, 420)

return (
<>
Expand All @@ -16,6 +19,7 @@ function App() {
<img src={viteLogo} className="vite" alt="Vite logo" />
</div>
<div>
{JSON.stringify(result)}
<h1>Get started</h1>
<p>
Edit <code>src/App.tsx</code> and save to test <code>HMR</code>
Expand Down
178 changes: 178 additions & 0 deletions vær/src/hooks/fetchWeather/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
export const weatherSymbolCodes = [
"clearsky_day",
"clearsky_night",
"clearsky_polartwilight",
"fair_day",
"fair_night",
"fair_polartwilight",
"lightssnowshowersandthunder_day",
"lightssnowshowersandthunder_night",
"lightssnowshowersandthunder_polartwilight",
"lightsnowshowers_day",
"lightsnowshowers_night",
"lightsnowshowers_polartwilight",
"heavyrainandthunder",
"heavysnowandthunder",
"rainandthunder",
"heavysleetshowersandthunder_day",
"heavysleetshowersandthunder_night",
"heavysleetshowersandthunder_polartwilight",
"heavysnow",
"heavyrainshowers_day",
"heavyrainshowers_night",
"heavyrainshowers_polartwilight",
"lightsleet",
"heavyrain",
"lightrainshowers_day",
"lightrainshowers_night",
"lightrainshowers_polartwilight",
"heavysleetshowers_day",
"heavysleetshowers_night",
"heavysleetshowers_polartwilight",
"lightsleetshowers_day",
"lightsleetshowers_night",
"lightsleetshowers_polartwilight",
"snow",
"heavyrainshowersandthunder_day",
"heavyrainshowersandthunder_night",
"heavyrainshowersandthunder_polartwilight",
"snowshowers_day",
"snowshowers_night",
"snowshowers_polartwilight",
"fog",
"snowshowersandthunder_day",
"snowshowersandthunder_night",
"snowshowersandthunder_polartwilight",
"lightsnowandthunder",
"heavysleetandthunder",
"lightrain",
"rainshowersandthunder_day",
"rainshowersandthunder_night",
"rainshowersandthunder_polartwilight",
"rain",
"lightsnow",
"lightrainshowersandthunder_day",
"lightrainshowersandthunder_night",
"lightrainshowersandthunder_polartwilight",
"heavysleet",
"sleetandthunder",
"lightrainandthunder",
"sleet",
"lightssleetshowersandthunder_day",
"lightssleetshowersandthunder_night",
"lightssleetshowersandthunder_polartwilight",
"lightsleetandthunder",
"partlycloudy_day",
"partlycloudy_night",
"partlycloudy_polartwilight",
"sleetshowersandthunder_day",
"sleetshowersandthunder_night",
"sleetshowersandthunder_polartwilight",
"rainshowers_day",
"rainshowers_night",
"rainshowers_polartwilight",
"snowandthunder",
"sleetshowers_day",
"sleetshowers_night",
"sleetshowers_polartwilight",
"cloudy",
"heavysnowshowersandthunder_day",
"heavysnowshowersandthunder_night",
"heavysnowshowersandthunder_polartwilight",
"heavysnowshowers_day",
"heavysnowshowers_night",
"heavysnowshowers_polartwilight"
] as const

export type WeatherSymbolCode = (typeof weatherSymbolCodes)[number]

export type PointGeometry = {
coordinates: [longitude: number, latitude: number, altitude: number],
type: "Point"
}

export type ForecastUnits = {
air_pressure_at_sea_level?: string,
air_temperature?: string,
air_temperature_max?: string,
air_temperature_min?: string,
cloud_area_fraction?: string,
cloud_area_fraction_high?: string,
cloud_area_fraction_low?: string,
cloud_area_fraction_medium?: string,
dew_point_temperature?: string,
fog_area_fraction?: string,
precipitation_amount?: string,
precipitation_amount_max?: string,
precipitation_amount_min?: string,
probability_of_precipitation?: string,
probability_of_thunder?: string,
relative_humidity?: string,
ultraviolet_index_clear_sky_max?: string,
wind_from_direction?: string,
wind_speed?: string,
wind_speed_of_gust?: string
}

export type ForecastTimeInstant = {
air_pressure_at_sea_level?: number,
air_temperature?: number,
cloud_area_fraction?: number,
cloud_area_fraction_high?: number,
cloud_area_fraction_low?: number,
cloud_area_fraction_medium?: number,
dew_point_temperature?: number,
fog_area_fraction?: number,
relative_humidity?: number,
wind_from_direction?: number,
wind_speed?: number,
wind_speed_of_gust?: number
}

export type ForecastTimePeriod = {
air_temperature_max?: number,
air_temperature_min?: number,
precipitation_amount?: number,
precipitation_amount_max?: number,
precipitation_amount_min?: number,
probability_of_precipitation?: number,
probability_of_thunder?: number,
ultraviolet_index_clear_sky_max?: number
}

export type ForecastSummary = {
symbol_code: WeatherSymbolCode
}

export type ForecastPeriod = {
details: ForecastTimePeriod,
summary: ForecastSummary
}

export type ForecastTimeStep = {
data: {
instant: {
details?: ForecastTimeInstant
},
next_1_hours?: ForecastPeriod,
next_6_hours?: ForecastPeriod,
next_12_hours?: ForecastPeriod
},
time: string
}

export type Forecast = {
meta: {
units: ForecastUnits,
updated_at: string
},
timeseries: ForecastTimeStep[]
}

export type METJSONForecast = {
geometry: PointGeometry,
properties: Forecast,
type: "Feature"
}

export type WeatherApiResponse = METJSONForecast
19 changes: 19 additions & 0 deletions vær/src/hooks/fetchWeather/useGetWeather.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useQuery } from "@tanstack/react-query"
import { 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 { isLoading, error, data } = useQuery({
queryKey: ["citySearch", `${lat}-${lon}`],
queryFn: () => fetch(`https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=${lat}&lon=${lon}${alt != undefined ? `&altitude=${sanitized_alt}` : ""}`).then((res) => res.json() as Promise<WeatherApiResponse>)
})

return { isLoading, error, result: data }
}

export default useGetWeather
24 changes: 24 additions & 0 deletions vær/src/hooks/useGetCityCoordinates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useQuery } from "@tanstack/react-query"

export type citySearchResult = {
result: {
name: string,
latitude: number,
longitude: number
elevation: number,
timezone: string
}[]
}

const useGetCityCoordinates = (cityName: string) => {
const { isLoading, error, data } = useQuery({
queryKey: ["citySearch", cityName],
queryFn: () => fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${cityName}`).then((res) => res.json() as Promise<citySearchResult>)
})

const result = data?.result ?? []

return { isLoading, error, result }
}

export default useGetCityCoordinates
13 changes: 10 additions & 3 deletions vær/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
import {
QueryClient, QueryClientProvider
} from '@tanstack/react-query'

const queryClient = new QueryClient()

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
<QueryClientProvider client={queryClient}>
<StrictMode>
<App />
</StrictMode>
</QueryClientProvider>,
)