Implement custom reminders with multiple VAlarms per event
Major Features: - Replace single ReminderType enum with Vec<VAlarm> throughout stack - Add comprehensive alarm management UI with AlarmList and AddAlarmModal components - Support relative (15min before, 2hrs after) and absolute (specific date/time) triggers - Display reminder icons in both month and week calendar views - RFC 5545 compliant VALARM implementation using calendar-models library Frontend Changes: - Create AlarmList component for displaying configured reminders - Create AddAlarmModal with full alarm configuration (trigger, timing, description) - Update RemindersTab to use new alarm management interface - Replace old ReminderType dropdown with modern multi-alarm system - Add reminder icons to event displays in month/week views - Fix event title ellipsis behavior in week view with proper CSS constraints Backend Changes: - Update all request/response models to use Vec<VAlarm> instead of String - Remove EventReminder conversion logic, pass VAlarms directly through - Maintain RFC 5545 compliance for CalDAV server compatibility UI/UX Improvements: - Improved basic details tab layout (calendar/repeat side-by-side, All Day checkbox repositioned) - Simplified reminder system to single notification type for user clarity - Font Awesome icons throughout instead of emojis for consistency - Clean modal styling with proper button padding and hover states - Removed non-standard custom message fields for maximum CalDAV compatibility 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -522,19 +522,8 @@ pub async fn create_event(
|
||||
.collect()
|
||||
};
|
||||
|
||||
// Parse alarms - convert from minutes string to EventReminder structs
|
||||
let alarms: Vec<crate::calendar::EventReminder> = if request.reminder.trim().is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
match request.reminder.parse::<i32>() {
|
||||
Ok(minutes) => vec![crate::calendar::EventReminder {
|
||||
minutes_before: minutes,
|
||||
action: crate::calendar::ReminderAction::Display,
|
||||
description: None,
|
||||
}],
|
||||
Err(_) => Vec::new(),
|
||||
}
|
||||
};
|
||||
// Use VAlarms directly from request (no conversion needed)
|
||||
let alarms = request.alarms;
|
||||
|
||||
// Check if recurrence is already a full RRULE or just a simple type
|
||||
let rrule = if request.recurrence.starts_with("FREQ=") {
|
||||
@@ -645,21 +634,7 @@ pub async fn create_event(
|
||||
event.categories = categories;
|
||||
event.rrule = rrule;
|
||||
event.all_day = request.all_day;
|
||||
event.alarms = alarms
|
||||
.into_iter()
|
||||
.map(|reminder| VAlarm {
|
||||
action: AlarmAction::Display,
|
||||
trigger: AlarmTrigger::Duration(chrono::Duration::minutes(
|
||||
-reminder.minutes_before as i64,
|
||||
)),
|
||||
duration: None,
|
||||
repeat: None,
|
||||
description: reminder.description,
|
||||
summary: None,
|
||||
attendees: Vec::new(),
|
||||
attach: Vec::new(),
|
||||
})
|
||||
.collect();
|
||||
event.alarms = alarms;
|
||||
event.calendar_path = Some(calendar_path.clone());
|
||||
|
||||
// Create the event on the CalDAV server
|
||||
|
||||
@@ -3,6 +3,7 @@ use axum::{
|
||||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use calendar_models::VAlarm;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// API request/response types
|
||||
@@ -113,7 +114,7 @@ pub struct CreateEventRequest {
|
||||
pub organizer: String, // organizer email
|
||||
pub attendees: String, // comma-separated attendee emails
|
||||
pub categories: String, // comma-separated categories
|
||||
pub reminder: String, // reminder type
|
||||
pub alarms: Vec<VAlarm>, // event alarms
|
||||
pub recurrence: String, // recurrence type
|
||||
pub recurrence_days: Vec<bool>, // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
|
||||
pub calendar_path: Option<String>, // Optional - use first calendar if not specified
|
||||
@@ -144,7 +145,7 @@ pub struct UpdateEventRequest {
|
||||
pub organizer: String, // organizer email
|
||||
pub attendees: String, // comma-separated attendee emails
|
||||
pub categories: String, // comma-separated categories
|
||||
pub reminder: String, // reminder type
|
||||
pub alarms: Vec<VAlarm>, // event alarms
|
||||
pub recurrence: String, // recurrence type
|
||||
pub recurrence_days: Vec<bool>, // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
|
||||
pub recurrence_interval: Option<u32>, // Every N days/weeks/months/years
|
||||
@@ -181,7 +182,7 @@ pub struct CreateEventSeriesRequest {
|
||||
pub organizer: String, // organizer email
|
||||
pub attendees: String, // comma-separated attendee emails
|
||||
pub categories: String, // comma-separated categories
|
||||
pub reminder: String, // reminder type
|
||||
pub alarms: Vec<VAlarm>, // event alarms
|
||||
|
||||
// Series-specific fields
|
||||
pub recurrence: String, // recurrence type (daily, weekly, monthly, yearly)
|
||||
@@ -219,7 +220,7 @@ pub struct UpdateEventSeriesRequest {
|
||||
pub organizer: String, // organizer email
|
||||
pub attendees: String, // comma-separated attendee emails
|
||||
pub categories: String, // comma-separated categories
|
||||
pub reminder: String, // reminder type
|
||||
pub alarms: Vec<VAlarm>, // event alarms
|
||||
|
||||
// Series-specific fields
|
||||
pub recurrence: String, // recurrence type (daily, weekly, monthly, yearly)
|
||||
|
||||
Reference in New Issue
Block a user