Implement real-time event refresh functionality
- Backend: Add GET /api/calendar/events/:uid endpoint for single event refresh - Backend: Implement fetch_event_by_uid method to retrieve updated events from CalDAV - Frontend: Add event click callback system to trigger refresh on interaction - Frontend: Display loading state with orange pulsing animation during refresh - Frontend: Smart event data updates without full calendar reload - Frontend: Graceful error handling with fallback to cached data - CSS: Add refreshing animation for visual feedback during updates Events now automatically refresh from CalDAV server when clicked, ensuring users always see the most current event data including changes made in other calendar applications. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -192,6 +192,17 @@ impl CalDAVClient {
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
/// Fetch a single calendar event by UID from the CalDAV server
|
||||
pub async fn fetch_event_by_uid(&self, calendar_path: &str, uid: &str) -> Result<Option<CalendarEvent>, CalDAVError> {
|
||||
// First fetch all events and find the one with matching UID
|
||||
let events = self.fetch_events(calendar_path).await?;
|
||||
|
||||
// Find event with matching UID
|
||||
let event = events.into_iter().find(|e| e.uid == uid);
|
||||
|
||||
Ok(event)
|
||||
}
|
||||
|
||||
/// Extract calendar data sections from CalDAV XML response
|
||||
fn extract_calendar_data(&self, xml_response: &str) -> Vec<CalendarDataSection> {
|
||||
let mut sections = Vec::new();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use axum::{
|
||||
extract::{State, Query},
|
||||
extract::{State, Query, Path},
|
||||
http::HeaderMap,
|
||||
response::Json,
|
||||
};
|
||||
@@ -73,6 +73,52 @@ pub async fn get_calendar_events(
|
||||
Ok(Json(filtered_events))
|
||||
}
|
||||
|
||||
pub async fn refresh_event(
|
||||
State(_state): State<Arc<AppState>>,
|
||||
Path(uid): Path<String>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Json<Option<CalendarEvent>>, ApiError> {
|
||||
// Verify authentication (extract token from Authorization header)
|
||||
let _token = if let Some(auth_header) = headers.get("authorization") {
|
||||
let auth_str = auth_header
|
||||
.to_str()
|
||||
.map_err(|_| ApiError::Unauthorized("Invalid authorization header".to_string()))?;
|
||||
|
||||
if auth_str.starts_with("Bearer ") {
|
||||
auth_str.strip_prefix("Bearer ").unwrap().to_string()
|
||||
} else {
|
||||
return Err(ApiError::Unauthorized("Invalid authorization format".to_string()));
|
||||
}
|
||||
} else {
|
||||
return Err(ApiError::Unauthorized("Missing authorization header".to_string()));
|
||||
};
|
||||
|
||||
// TODO: Validate JWT token here
|
||||
|
||||
// Load CalDAV configuration
|
||||
let config = CalDAVConfig::from_env()
|
||||
.map_err(|e| ApiError::Internal(format!("Failed to load CalDAV config: {}", e)))?;
|
||||
|
||||
let client = CalDAVClient::new(config);
|
||||
|
||||
// Discover calendars if needed
|
||||
let calendar_paths = client.discover_calendars()
|
||||
.await
|
||||
.map_err(|e| ApiError::Internal(format!("Failed to discover calendars: {}", e)))?;
|
||||
|
||||
if calendar_paths.is_empty() {
|
||||
return Ok(Json(None)); // No calendars found
|
||||
}
|
||||
|
||||
// Fetch the specific event by UID from the first calendar
|
||||
let calendar_path = &calendar_paths[0];
|
||||
let event = client.fetch_event_by_uid(calendar_path, &uid)
|
||||
.await
|
||||
.map_err(|e| ApiError::Internal(format!("Failed to fetch event: {}", e)))?;
|
||||
|
||||
Ok(Json(event))
|
||||
}
|
||||
|
||||
pub async fn register(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(request): Json<RegisterRequest>,
|
||||
|
||||
@@ -53,6 +53,7 @@ pub async fn run_server() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.route("/api/auth/login", post(handlers::login))
|
||||
.route("/api/auth/verify", get(handlers::verify_token))
|
||||
.route("/api/calendar/events", get(handlers::get_calendar_events))
|
||||
.route("/api/calendar/events/:uid", get(handlers::refresh_event))
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_origin(Any)
|
||||
|
||||
Reference in New Issue
Block a user