Refactor weather

This commit is contained in:
Tanguy Gérôme 2025-06-21 14:36:20 +03:00
parent 7c8f0ce2dc
commit 7d73080e30
Signed by: tanguy
GPG key ID: 10B2947233740B88

View file

@ -10,46 +10,48 @@ pub mod wmo;
#[component]
pub fn Weather() -> impl IntoView {
let weather_json = LocalResource::new(async move || {
let json_response = reqwest::get("https://api.open-meteo.com/v1/forecast?latitude=60.236610&longitude=25.083630&timezone=auto&forecast_hours=16&wind_speed_unit=kn&hourly=temperature_2m,wind_speed_10m,precipitation,precipitation_probability,weather_code,is_day").await
let json_response = reqwest::get("https://api.open-meteo.com/v1/forecast?latitude=60.236610&longitude=25.083630&timezone=auto&forecast_hours=17&wind_speed_unit=kn&hourly=temperature_2m,wind_speed_10m,precipitation,precipitation_probability,weather_code,is_day").await
.and_then(|response| Ok(response.json::<Value>()));
match json_response {
Ok(result) => Some(result.await.ok()),
_ => None
}.flatten()
});
let get_hourly_slice = move |key: &str, start_index: usize, end_index: usize| {
Some(weather_json.get().flatten()?["hourly"][key].as_array()?[start_index..end_index].to_vec().into_iter())
};
let times = move || {
Some(weather_json.get().flatten()?["hourly"]["time"].as_array()?.into_iter().map(|timestamp| {
Some(get_hourly_slice("time", 0, 16)?.map(|timestamp| {
let datetime = NaiveDateTime::parse_from_str(timestamp.as_str().unwrap_or_default(), "%Y-%m-%dT%H:%M");
view! {<td>{format!("{}", datetime.unwrap_or_default().hour())}</td>}
}).collect::<Vec<_>>())
};
let weather_codes = move || {
let json = weather_json.get().flatten()?;
let is_day = json["hourly"]["is_day"].as_array()?.into_iter();
let codes = json["hourly"]["weather_code"].as_array()?.into_iter();
let is_day = get_hourly_slice("is_day", 0, 16)?;
let codes = get_hourly_slice("weather_code", 0, 16)?;
Some(is_day.zip(codes).map(move |(is_day, code)| {
let wmo_codes = crate::wmo::get_codes();
let image = wmo_codes[code.to_string()][if *is_day == Value::Number(1.into()) {"day"} else {"night"}]["image"].as_str().unwrap_or_default();
let description = wmo_codes[code.to_string()][if *is_day == Value::Number(1.into()) {"day"} else {"night"}]["description"].as_str().unwrap_or_default();
let code_info = wmo_codes[code.to_string()][if is_day == Value::Number(1.into()) {"day"} else {"night"}].clone();
let image = code_info["image"].as_str().unwrap_or_default();
let description = code_info["description"].as_str().unwrap_or_default();
view! { <td><img src={image.to_string()} alt={description.to_string()}/></td> }
}).collect::<Vec<_>>())
};
let temperatures = move || {
Some(weather_json.get().flatten()?["hourly"]["temperature_2m"].as_array()?.into_iter().map(|temperature| {
view! { <td>{format!("{}°C", temperature.to_string())}</td> }
Some(get_hourly_slice("temperature_2m", 0, 16)?.map(|temperature| {
view! { <td>{format!("{}°C", temperature.as_f64().unwrap_or_default().round().to_string())}</td> }
}).collect::<Vec<_>>())
};
let wind = move || {
Some(weather_json.get().flatten()?["hourly"]["wind_speed_10m"].as_array()?.into_iter().map(|wind_speed| {
view! { <td>{format!("{}kn", wind_speed.to_string())}</td> }
Some(get_hourly_slice("wind_speed_10m", 0, 16)?.map(|wind_speed| {
view! { <td>{format!("{}kn", wind_speed.as_f64().unwrap_or_default().round().to_string())}</td> }
}).collect::<Vec<_>>())
};
let precipitation = move || {
let json = weather_json.get().flatten()?;
let amounts = json["hourly"]["precipitation"].as_array()?.into_iter();
let probabilities = json["hourly"]["precipitation"].as_array()?.into_iter();
Some(amounts.zip(probabilities).map(|(amount, probability_float)| {
let probability = (probability_float.as_f64()? * 100.0).round() as i64;
let amounts = get_hourly_slice("precipitation", 1, 17)?;
let probabilities = get_hourly_slice("precipitation_probability", 1, 17)?;
Some(amounts.zip(probabilities).map(|(amount, probability)| {
Some(view! {
<td>
<span>{format!("{}mm", amount.to_string())}</span>
@ -59,6 +61,7 @@ pub fn Weather() -> impl IntoView {
})
}).collect::<Vec<_>>())
};
view! {
<div class="weather">
<Suspense fallback=move || view! { <p>"Loading..."</p> }>