🦀/100 Projects/Notes/Source

src/main.rs

View on GitHub
use yew::prelude::*;
use gloo_net::http::Request;
use serde::Deserialize;
use wasm_bindgen_futures; 

#[derive(Deserialize, Debug, Clone, PartialEq)]
struct WeatherData {
    name: String,
    main: Main,
    weather: Vec<Weather>,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
struct Main {
    temp: f64,
    humidity: u8,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
struct Weather {
    description: String,
}

#[function_component(App)]
fn app() -> Html {
    let city = use_state(|| "London".to_string());
    let weather = use_state(|| None::<WeatherData>);
    let input = use_state(|| city.to_string());
    let fetch_counter = use_state(|| 0); 

    let on_input = {
        let input = input.clone();
        Callback::from(move |e: InputEvent| {
            let val = e.target_unchecked_into::<web_sys::HtmlInputElement>().value();
            input.set(val);
        })
    };

    let on_click = {
        let city = city.clone();
        let input = input.clone();
        let fetch_counter = fetch_counter.clone();
        Callback::from(move |_| {
            city.set((*input).clone());
            fetch_counter.set(*fetch_counter + 1); 
        })
    };

    {
        let weather = weather.clone();
        let current_city = (*city).clone();
        
        use_effect_with(*fetch_counter, move |_| {
            if !current_city.is_empty() {
                let weather = weather.clone();
                let city_clone = current_city.clone();
                
                wasm_bindgen_futures::spawn_local(async move {
                    // Replace with your actual API key
                    let url = format!(
                        "https://api.openweathermap.org/data/2.5/weather?q={}&units=metric&appid=YOUR_API_KEY
",
                        city_clone
                    );
                    
                    weather.set(None);
                    
                    match Request::get(&url).send().await {
                        Ok(response) => {
                            if response.status() == 200 {
                                match response.json::<WeatherData>().await {
                                    Ok(data) => {
                                        weather.set(Some(data));
                                    }
                                    Err(e) => {
                                        web_sys::console::error_1(&format!("JSON parse error: {:?}", e).into());
                                    }
                                }
                            } else {
                                web_sys::console::error_1(&format!("HTTP error: {}", response.status()).into());
                            }
                        }
                        Err(e) => {
                            web_sys::console::error_1(&format!("Request error: {:?}", e).into());
                        }
                    }
                });
            }
            
            || ()
        });
    }

    html! {
        <div style="font-family: sans-serif; text-align: center; padding-top: 2em;">
            <h1>{ "🌦️ Weather Dashboard" }</h1>
            <input 
                value={(*input).clone()} 
                oninput={on_input} 
                placeholder="Enter city..." 
                style="padding: 8px; margin-right: 8px;"
            />
            <button 
                onclick={on_click} 
                style="padding: 8px 16px; background: #007acc; color: white; border: none; border-radius: 4px; cursor: pointer;"
            >
                { "Get Weather" }
            </button>

            {
                if let Some(data) = &*weather {
                    html! {
                        <div style="margin-top: 2em; padding: 20px; background: #f5f5f5; border-radius: 8px; max-width: 400px; margin-left: auto; margin-right: auto;">
                            <h2>{ format!("Weather in {}", data.name) }</h2>
                            <p>{ format!("🌡️ Temp: {:.1}°C", data.main.temp) }</p>
                            <p>{ format!("💧 Humidity: {}%", data.main.humidity) }</p>
                            <p>{ format!("🌤️ Description: {}", data.weather[0].description) }</p>
                        </div>
                    }
                } else if *fetch_counter > 0 {
                    html! { <p style="margin-top: 2em;">{ "🔄 Loading weather data..." }</p> }
                } else {
                    html! { <p style="margin-top: 2em; color: #666;">{ "Enter a city and click 'Get Weather'" }</p> }
                }
            }
        </div>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

← Back to folder