Add comprehensive reminder/alarm support to calendar events

- Backend: Parse VALARM components from CalDAV iCalendar data
- Backend: Add EventReminder struct with minutes_before, action, and description
- Backend: Support Display, Email, and Audio reminder types
- Backend: Parse ISO 8601 duration triggers (-PT15M, -P1D, etc.)
- Frontend: Add reminders field to CalendarEvent structure
- Frontend: Display reminders in event modal with human-readable formatting
- Frontend: Show reminder timing (15 minutes before, 1 day before) and action type
- Fix: Update Trunk.toml to properly copy CSS files to dist directory

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-08-28 17:37:30 -04:00
parent 01a21cb869
commit 1c4857ccad
8 changed files with 458 additions and 20 deletions

View File

@@ -0,0 +1,61 @@
use crate::calendar::CalDAVClient;
use crate::config::CalDAVConfig;
pub async fn debug_caldav_fetch() -> Result<(), Box<dyn std::error::Error>> {
let config = CalDAVConfig::from_env()?;
let client = CalDAVClient::new(config);
println!("=== DEBUG: CalDAV Fetch ===");
// Discover calendars
let calendars = client.discover_calendars().await?;
println!("Found {} calendars: {:?}", calendars.len(), calendars);
if let Some(calendar_path) = calendars.first() {
println!("Fetching events from: {}", calendar_path);
// Make the raw REPORT request
let report_body = r#"<?xml version="1.0" encoding="utf-8" ?>
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag/>
<c:calendar-data/>
</d:prop>
<c:filter>
<c:comp-filter name="VCALENDAR">
<c:comp-filter name="VEVENT"/>
</c:comp-filter>
</c:filter>
</c:calendar-query>"#;
let url = format!("{}{}", client.config.server_url.trim_end_matches('/'), calendar_path);
println!("Request URL: {}", url);
let response = client.http_client
.request(reqwest::Method::from_bytes(b"REPORT").unwrap(), &url)
.header("Authorization", format!("Basic {}", client.config.get_basic_auth()))
.header("Content-Type", "application/xml")
.header("Depth", "1")
.header("User-Agent", "calendar-app/0.1.0")
.body(report_body)
.send()
.await?;
println!("Response status: {}", response.status());
let body = response.text().await?;
println!("Response body length: {}", body.len());
println!("First 500 chars of response: {}", &body[..std::cmp::min(500, body.len())]);
// Try to parse it
let events = client.parse_calendar_response(&body)?;
println!("Parsed {} events", events.len());
for (i, event) in events.iter().enumerate() {
println!("Event {}: {}", i+1, event.summary.as_deref().unwrap_or("No title"));
println!(" Start: {}", event.start);
println!(" UID: {}", event.uid);
}
}
Ok(())
}