Implement complete event creation functionality with CalDAV backend
- Add CalDAV create_event method with proper iCalendar generation - Add comprehensive backend API for event creation with validation - Add event creation models and handlers with date/time parsing - Add frontend service method for creating events via API - Update frontend to call backend API instead of placeholder - Fix CalDAV URL construction to avoid duplicate /dav.php paths - Support all event fields: title, description, dates, location, all-day 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										50
									
								
								src/app.rs
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								src/app.rs
									
									
									
									
									
								
							| @@ -199,10 +199,52 @@ pub fn App() -> Html { | ||||
|         Callback::from(move |event_data: EventCreationData| { | ||||
|             web_sys::console::log_1(&format!("Creating event: {:?}", event_data).into()); | ||||
|             create_event_modal_open.set(false); | ||||
|             // TODO: Implement actual event creation API call | ||||
|             // For now, just close the modal and refresh | ||||
|             if (*auth_token).is_some() { | ||||
|                 web_sys::window().unwrap().location().reload().unwrap(); | ||||
|              | ||||
|             if let Some(token) = (*auth_token).clone() { | ||||
|                 wasm_bindgen_futures::spawn_local(async move { | ||||
|                     let calendar_service = CalendarService::new(); | ||||
|                      | ||||
|                     // Get CalDAV password from storage | ||||
|                     let password = if let Ok(credentials_str) = LocalStorage::get::<String>("caldav_credentials") { | ||||
|                         if let Ok(credentials) = serde_json::from_str::<serde_json::Value>(&credentials_str) { | ||||
|                             credentials["password"].as_str().unwrap_or("").to_string() | ||||
|                         } else { | ||||
|                             String::new() | ||||
|                         } | ||||
|                     } else { | ||||
|                         String::new() | ||||
|                     }; | ||||
|                      | ||||
|                     // Format date and time strings | ||||
|                     let start_date = event_data.start_date.format("%Y-%m-%d").to_string(); | ||||
|                     let start_time = event_data.start_time.format("%H:%M").to_string(); | ||||
|                     let end_date = event_data.end_date.format("%Y-%m-%d").to_string(); | ||||
|                     let end_time = event_data.end_time.format("%H:%M").to_string(); | ||||
|                      | ||||
|                     match calendar_service.create_event( | ||||
|                         &token, | ||||
|                         &password, | ||||
|                         event_data.title, | ||||
|                         event_data.description, | ||||
|                         start_date, | ||||
|                         start_time, | ||||
|                         end_date, | ||||
|                         end_time, | ||||
|                         event_data.location, | ||||
|                         event_data.all_day, | ||||
|                         None // Let backend use first available calendar | ||||
|                     ).await { | ||||
|                         Ok(_) => { | ||||
|                             web_sys::console::log_1(&"Event created successfully".into()); | ||||
|                             // Refresh the page to show the new event | ||||
|                             web_sys::window().unwrap().location().reload().unwrap(); | ||||
|                         } | ||||
|                         Err(err) => { | ||||
|                             web_sys::console::error_1(&format!("Failed to create event: {}", err).into()); | ||||
|                             web_sys::window().unwrap().alert_with_message(&format!("Failed to create event: {}", err)).unwrap(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         }) | ||||
|     }; | ||||
|   | ||||
| @@ -586,6 +586,78 @@ impl CalendarService { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Create a new event on the CalDAV server | ||||
|     pub async fn create_event( | ||||
|         &self, | ||||
|         token: &str, | ||||
|         password: &str,  | ||||
|         title: String, | ||||
|         description: String, | ||||
|         start_date: String, | ||||
|         start_time: String, | ||||
|         end_date: String, | ||||
|         end_time: String, | ||||
|         location: String, | ||||
|         all_day: bool, | ||||
|         calendar_path: Option<String> | ||||
|     ) -> Result<(), String> { | ||||
|         let window = web_sys::window().ok_or("No global window exists")?; | ||||
|          | ||||
|         let opts = RequestInit::new(); | ||||
|         opts.set_method("POST"); | ||||
|         opts.set_mode(RequestMode::Cors); | ||||
|  | ||||
|         let body = serde_json::json!({ | ||||
|             "title": title, | ||||
|             "description": description, | ||||
|             "start_date": start_date, | ||||
|             "start_time": start_time, | ||||
|             "end_date": end_date, | ||||
|             "end_time": end_time, | ||||
|             "location": location, | ||||
|             "all_day": all_day, | ||||
|             "calendar_path": calendar_path | ||||
|         }); | ||||
|  | ||||
|         let body_string = serde_json::to_string(&body) | ||||
|             .map_err(|e| format!("JSON serialization failed: {}", e))?; | ||||
|  | ||||
|         let url = format!("{}/calendar/events/create", self.base_url); | ||||
|         opts.set_body(&body_string.into()); | ||||
|         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))?; | ||||
|          | ||||
|         request.headers().set("X-CalDAV-Password", password) | ||||
|             .map_err(|e| format!("Password header setting failed: {:?}", e))?; | ||||
|  | ||||
|         request.headers().set("Content-Type", "application/json") | ||||
|             .map_err(|e| format!("Content-Type 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() { | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             Err(format!("Request failed with status {}: {}", resp.status(), text_string)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Delete a calendar from the CalDAV server | ||||
|     pub async fn delete_calendar( | ||||
|         &self,  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Connor Johnstone
					Connor Johnstone