Commit Graph

20 Commits

Author SHA1 Message Date
Connor Johnstone
efbaea5ac1 Add current time indicator to week view
- Add real-time current time indicator that updates every 5 seconds
- Display horizontal line with dot and time label on current day only
- Position indicator accurately based on time increment mode (15/30 min)
- Use theme-aware colors with subdued gray styling for dark mode
- Include subtle shadows and proper z-indexing for visibility

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-05 10:33:07 -04:00
Connor Johnstone
f88c238b0a Fix external calendar timezone conversion and styling
- Add comprehensive Windows timezone support for global external calendars
  - Map Windows timezone names (e.g. "Mountain Standard Time") to IANA zones (e.g. "America/Denver")
  - Support 60+ timezone mappings across North America, Europe, Asia, Asia Pacific, Africa, South America
  - Add chrono-tz dependency for proper timezone handling
- Fix external calendar event colors by setting calendar_path for color lookup
- Add visual distinction for external calendar events with dashed borders and calendar emoji
- Update timezone parsing to extract TZID parameters from iCalendar DTSTART/DTEND properties
- Pass external calendar data through component hierarchy for color matching

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 19:11:57 -04:00
Connor Johnstone
289284a532 Fix all-day event date display bug: events created 9/4-9/6 now show correctly instead of 9/3-9/5
All checks were successful
Build and Push Docker Image / docker (push) Successful in 1m9s
- Backend: Store all-day events at noon UTC instead of midnight to avoid timezone boundary issues
- Backend: Remove local timezone conversion for all-day events in series handler
- Frontend: Skip timezone conversion when extracting dates from all-day events for display
- Frontend: Extract dates directly from UTC for all-day events in event_spans_date function

The issue was that timezone conversion of UTC midnight could shift dates backward in western timezones.
Now all-day events use noon UTC storage and pure date extraction without timezone conversion.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 17:35:29 -04:00
Connor Johnstone
53c4a99697 Fix multi-day all-day events to display across all days they span
All-day events spanning multiple days were only showing on their start date.
For example, a "Vacation (Dec 20-25)" event would only appear on Dec 20th.

Root cause: Logic only checked events stored in each day's HashMap entry,
missing events that span into other days.

Solution:
- Modified all-day event collection to search all events across all days
- Added event_spans_date() helper function to check if event spans given date
- Properly handles iCalendar dtend convention (day after event ends)
- Added deduplication to prevent duplicate events from multiple day buckets
- Removed unused day_events variable

Result: Multi-day all-day events now correctly appear on every day they span,
while single-day events continue to work as before.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 16:31:25 -04:00
Connor Johnstone
5ea33b7d0a Fix event width bug: timed events showing half-width when all-day events exist
Timed events were incorrectly displaying at half-width when all-day events
existed on the same day, even though all-day events display separately at
the top of the calendar and don't visually overlap with timed events.

Root cause: The overlap calculation logic was including all-day events when
determining width splits for timed events.

Solution:
- Modified calculate_event_layout() to exclude all-day events from filtering
- Updated events_overlap() to return false if either event is all-day
- All-day events now don't participate in timed event width calculations

Result: Timed events display at full width unless they actually overlap
with other timed events, while all-day events continue to display correctly
in their separate section.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 16:27:32 -04:00
Connor Johnstone
2b98c4d229 Hide event time display for single-slot events
Hide time display for events with duration <= 30px (single time slots)
to maximize space for event titles in compact event boxes.

- Single-slot events show title only for better readability
- Applies to both 15-minute and 30-minute time increment modes
- Consistent behavior across static events and drag previews
- Improves UX for short duration events where time display crowds the title

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 15:39:15 -04:00
Connor Johnstone
ceae654a39 Implement dynamic 15-minute time grid density and remove final boundary
- Scale time grid height dynamically based on time increment (1530px/2970px)
- Add quarter-mode CSS classes for 15-minute blocks (30px each, same as 30-min blocks)
- Update pixel-to-time conversion functions with 2px:1min scaling in 15-min mode
- Generate correct number of time slots (4 per hour in 15-min mode)
- Remove unnecessary final boundary time label and related CSS
- Fix CSS grid layout by removing malformed CSS syntax
- All time-related containers scale properly between 30-minute and 15-minute modes

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 15:35:50 -04:00
Connor Johnstone
b576cd8c4a Add context menus to all-day event boxes
All-day events now have the same right-click context menu functionality
as regular timed events, allowing users to edit, delete, and perform
other actions on all-day events.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 11:37:36 -04:00
Connor Johnstone
3662f117f5 Fix overlapping events to only split columns for overlapping event groups
Implemented clustering algorithm in calculate_event_layout that:
- Only creates column splits for events that actually overlap
- Non-overlapping events maintain full width display
- Uses greedy column assignment for overlapping groups
- Preserves proper column indices for each event

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 11:20:37 -04:00
Connor Johnstone
0899a84b42 Fix all-day events: validation and proper header positioning
Backend fixes:
- Fix all-day event creation validation error
- Allow same start/end date for all-day events (single-day events)
- Maintain strict validation for timed events (end must be after start)

Frontend improvements:
- Move all-day events from time grid to day headers
- Add dedicated all-day events container that stacks vertically
- Filter all-day events out of main time-based events area
- Add proper CSS styling for all-day event display and interaction
- Maintain event click handling and color themes

All-day events now appear in the correct location at the top of each
day column and properly stack when multiple events exist.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 11:13:54 -04:00
Connor Johnstone
57e434e4ff Fix drag interaction issues in week view
- Fix drag-to-create being blocked by existing events
- Add creating-event CSS class that disables pointer events on existing events
- Fix single clicks creating temporary event boxes
- Add mouse button state check to prevent post-mouseup movement being treated as drag
- Ensure temp event boxes only appear during actual drag operations (has_moved=true)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 10:55:39 -04:00
Connor Johnstone
7c2901f453 Implement side-by-side rendering for overlapping events in week view
- Add overlap detection algorithm to identify overlapping events
- Implement layout calculation to arrange events in columns
- Update event positioning to use dynamic left/width instead of fixed right
- Events now render side-by-side when they overlap in time
- Maintains proper spacing and margins for all event arrangements

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 10:44:32 -04:00
Connor Johnstone
e2e5813b54 Fix week view time grid display and late night event rendering
- Remove unnecessary boundary slot from week view time grid
- Adjust container heights to display full 11 PM - midnight time slot
- Fix timezone issue preventing events at 8 PM or later from rendering
- Update date matching logic to handle UTC-4 timezone offset correctly

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 10:36:26 -04:00
Connor Johnstone
79f287ed61 Fix calendar event fetching to use visible date range
Some checks failed
Build and Push Docker Image / docker (push) Failing after 1m7s
Moved event fetching logic from CalendarView to Calendar component to properly
use the visible date range instead of hardcoded current month. The Calendar
component already tracks the current visible date through navigation, so events
now load correctly for August and other months when navigating.

Changes:
- Calendar component now manages its own events state and fetching
- Event fetching responds to current_date changes from navigation
- CalendarView simplified to just render Calendar component
- Fixed cargo fmt/clippy formatting across codebase

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-01 18:31:51 -04:00
Connor Johnstone
b9e8778f8f Fix this_only concurrent request cancellation issue
Resolves the same "Failed to fetch" cancellation issue that was occurring
in the "modify single event in a series" flow by eliminating concurrent
HTTP requests from the frontend.

## Problem:
The RecurringEditAction::ThisEvent handler was making two concurrent requests:
1. UPDATE request via update_callback.emit()
2. CREATE request via create_callback.emit()

This caused the same race condition and HTTP cancellation (~700-900ms) that
we previously fixed in the "this_and_future" flow.

## Solution:
- **Remove concurrent CREATE request** from frontend
- **Use single UPDATE request** with "this_only" scope
- **Backend handles both operations** atomically:
  1. Add EXDATE to original series (exclude occurrence)
  2. Create exception event with RECURRENCE-ID (user modifications)

## Implementation:
- Frontend sends single request with occurrence_date and dragged times
- Backend update_single_occurrence() already handled both operations
- Added comprehensive RFC 5545 documentation for single occurrence modification
- Cleaned up unused imports and variables

## Benefits:
- No more HTTP request cancellation for single event modifications
- Proper RFC 5545 EXDATE + RECURRENCE-ID exception handling
- Atomic operations ensure data consistency
- Matches the pattern used in this_and_future fix

The "modify single event" drag operations now work reliably without
network errors, completing the fix for all recurring event modification flows.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 20:29:02 -04:00
Connor Johnstone
9536158f58 Clean up debug logs and add comprehensive documentation for this_and_future logic
This commit improves code maintainability by:

1. **Removing excessive debug logging**:
   - Cleaned up verbose datetime parsing and CalDAV operation logs
   - Kept essential error logging and status messages
   - Simplified request flow logging for better readability

2. **Adding comprehensive documentation**:
   - Detailed RFC 5545 compliant series splitting explanation
   - Clear operation overview with real-world examples
   - Frontend/backend interaction documentation
   - CalDAV operation sequencing and race condition prevention
   - Error handling and parameter validation details

The documentation explains how "this and future events" works:
- **Backend**: Creates comprehensive function-level docs with examples
- **Frontend**: Explains the user interaction flow and technical implementation
- **Integration**: Documents the atomic request handling and parameter passing

This makes the codebase more maintainable and helps future developers
understand the complex recurring event modification logic.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 20:23:48 -04:00
Connor Johnstone
783e13eb10 Fix recurring event series modification via drag and drop operations
This commit resolves the "Failed to fetch" errors when updating recurring
event series through drag operations by implementing proper request
sequencing and fixing time parameter handling.

Key fixes:
- Eliminate HTTP request cancellation by sequencing operations properly
- Add global mutex to prevent CalDAV HTTP race conditions
- Implement complete RFC 5545-compliant series splitting for "this_and_future"
- Fix frontend to pass dragged times instead of original times
- Add comprehensive error handling and request timing logs
- Backend now handles both UPDATE (add UNTIL) and CREATE (new series) in single request

Technical changes:
- Frontend: Remove concurrent CREATE request, pass dragged times to backend
- Backend: Implement full this_and_future logic with sequential operations
- CalDAV: Add mutex serialization and detailed error tracking
- Series: Create new series with occurrence date + dragged times

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 20:17:36 -04:00
Connor Johnstone
ee1c6ee299 Fix single event deletion functionality with proper recurring vs non-recurring handling
This commit resolves multiple issues with event deletion:

Backend fixes:
- Fix CalDAV URL construction for DELETE requests (missing slash separator)
- Improve event lookup by href with exact matching and fallback to UID extraction
- Add support for both RFC3339 and simple YYYY-MM-DD date formats in occurrence parsing
- Implement proper logic to distinguish recurring vs non-recurring events in delete_this action
- For non-recurring events: delete entire event from CalDAV server
- For recurring events: add EXDATE to exclude specific occurrences
- Add comprehensive debug logging for troubleshooting deletion issues

Frontend fixes:
- Update callback signatures to support series endpoint parameters (7-parameter tuples)
- Add update_series method to CalendarService for series-specific operations
- Route single occurrence modifications through series endpoint with proper scoping
- Fix all component prop definitions to use new callback signature
- Update all emit calls to pass correct number of parameters

The deletion process now works correctly:
- Single events are completely removed from the calendar
- Recurring event occurrences are properly excluded via EXDATE
- Debug logging helps identify and resolve CalDAV communication issues

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 18:40:48 -04:00
Connor Johnstone
a6aac42c78 Fix frontend to use series endpoint for single occurrence modifications
- Extended update callback signature to include update_scope and occurrence_date parameters
- Modified app.rs to detect when series endpoint should be used vs regular endpoint
- Updated calendar_service to automatically set occurrence_date for "this_only" updates
- Modified all callback emit calls throughout frontend to include new parameters
- Week_view now properly calls series endpoint with "this_only" scope for single occurrence edits

This ensures that single occurrence modifications (RecurringEditAction::ThisEvent)
now go through the proper series endpoint which will:
- Add EXDATE to the original recurring series
- Create exception event with RECURRENCE-ID
- Show proper debug logging in backend

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 14:01:30 -04:00
Connor Johnstone
15f2d0c6d9 Implement shared RFC 5545 VEvent library with workspace restructuring
- Created calendar-models/ shared library with RFC 5545-compliant VEvent structures
- Migrated backend to use shared VEvent with proper field mappings (dtstart/dtend, rrule, exdate, etc.)
- Converted CalDAV client to parse into VEvent structures with structured types
- Updated all CRUD handlers to use VEvent with CalendarUser, Attendee, VAlarm types
- Restructured project as Cargo workspace with frontend/, backend/, calendar-models/
- Updated Trunk configuration for new directory structure
- Fixed all compilation errors and field references throughout codebase
- Updated documentation and build instructions for workspace structure

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 11:45:58 -04:00