use chrono::{DateTime, Utc, NaiveDate}; use serde::{Deserialize, Serialize}; use wasm_bindgen::JsCast; use wasm_bindgen_futures::JsFuture; use web_sys::{Request, RequestInit, RequestMode, Response}; use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CalendarEvent { pub uid: String, pub summary: Option, pub description: Option, pub start: DateTime, pub end: Option>, pub location: Option, pub status: String, pub all_day: bool, } impl CalendarEvent { /// Get the date for this event (for calendar display) pub fn get_date(&self) -> NaiveDate { if self.all_day { self.start.date_naive() } else { self.start.date_naive() } } /// Get display title for the event pub fn get_title(&self) -> String { self.summary.clone().unwrap_or_else(|| "Untitled Event".to_string()) } } pub struct CalendarService { base_url: String, } impl CalendarService { pub fn new() -> Self { let base_url = option_env!("BACKEND_API_URL") .unwrap_or("http://localhost:3000/api") .to_string(); Self { base_url } } /// Fetch calendar events for a specific month pub async fn fetch_events_for_month( &self, token: &str, year: i32, month: u32 ) -> Result, String> { let window = web_sys::window().ok_or("No global window exists")?; let opts = RequestInit::new(); opts.set_method("GET"); opts.set_mode(RequestMode::Cors); let url = format!("{}/calendar/events?year={}&month={}", self.base_url, year, month); let request = Request::new_with_str_and_init(&url, &opts) .map_err(|e| format!("Request creation failed: {:?}", e))?; request.headers().set("Authorization", &format!("Bearer {}", token)) .map_err(|e| format!("Authorization header setting failed: {:?}", e))?; let resp_value = JsFuture::from(window.fetch_with_request(&request)) .await .map_err(|e| format!("Network request failed: {:?}", e))?; let resp: Response = resp_value.dyn_into() .map_err(|e| format!("Response cast failed: {:?}", e))?; let text = JsFuture::from(resp.text() .map_err(|e| format!("Text extraction failed: {:?}", e))?) .await .map_err(|e| format!("Text promise failed: {:?}", e))?; let text_string = text.as_string() .ok_or("Response text is not a string")?; if resp.ok() { let events: Vec = serde_json::from_str(&text_string) .map_err(|e| format!("JSON parsing failed: {}", e))?; Ok(events) } else { Err(format!("Request failed with status {}: {}", resp.status(), text_string)) } } /// Convert events to a HashMap grouped by date for calendar display pub fn group_events_by_date(events: Vec) -> HashMap> { let mut grouped = HashMap::new(); for event in events { let date = event.get_date(); let title = event.get_title(); grouped.entry(date) .or_insert_with(Vec::new) .push(title); } grouped } }