# Scheduler Recurrence Integration Guide ## How to Add Recurrence Support to EventModal in Scheduler.tsx This guide shows exactly how to integrate the RecurrenceEditor component into the existing Scheduler event modal. ## Step 1: Import RecurrenceEditor Add to imports at the top of `Scheduler.tsx`: ```typescript import { RecurrenceEditor } from "../RecurrenceEditor"; import type { IcsRecurrenceRule } from "ts-ics"; ``` ## Step 2: Add Recurrence State In the `EventModal` component, add recurrence state after the existing useState declarations: ```typescript // Around line 110, after: const [attendees, setAttendees] = useState([]); const [showAttendees, setShowAttendees] = useState(false); // Add: const [recurrence, setRecurrence] = useState( event?.recurrenceRule ); const [showRecurrence, setShowRecurrence] = useState(() => { return !!event?.recurrenceRule; }); ``` ## Step 3: Reset Recurrence When Event Changes In the `useEffect` that resets form state, add recurrence reset: ```typescript // Around line 121-161, in the useEffect(() => { ... }, [event, calendarUrl]) useEffect(() => { setTitle(event?.summary || ""); setDescription(event?.description || ""); setLocation(event?.location || ""); setSelectedCalendarUrl(calendarUrl); // Initialize attendees from event if (event?.attendees && event.attendees.length > 0) { setAttendees(event.attendees); setShowAttendees(true); } else { setAttendees([]); setShowAttendees(false); } // ADD THIS: Initialize recurrence from event if (event?.recurrenceRule) { setRecurrence(event.recurrenceRule); setShowRecurrence(true); } else { setRecurrence(undefined); setShowRecurrence(false); } // ... rest of the useEffect }, [event, calendarUrl]); ``` ## Step 4: Include Recurrence in Save In the `handleSave` function, add recurrence to the IcsEvent object: ```typescript // Around line 200-227, when creating the icsEvent const icsEvent: IcsEvent = { ...eventWithoutDuration, uid: event?.uid || crypto.randomUUID(), summary: title, description: description || undefined, location: location || undefined, start: { date: fakeUtcStart, local: { timezone: BROWSER_TIMEZONE, tzoffset: adapter.getTimezoneOffset(startDate, BROWSER_TIMEZONE), }, }, end: { date: fakeUtcEnd, local: { timezone: BROWSER_TIMEZONE, tzoffset: adapter.getTimezoneOffset(endDate, BROWSER_TIMEZONE), }, }, organizer: organizer, attendees: attendees.length > 0 ? attendees : undefined, recurrenceRule: recurrence, // ADD THIS LINE }; ``` ## Step 5: Add RecurrenceEditor to UI In the modal JSX, add a button to show/hide recurrence and the RecurrenceEditor component. ### Add Feature Button (like the attendees button) Around line 350-360, after the attendees button: ```tsx {/* Existing code */} {/* ADD THIS: Recurrence button */} ``` ### Add RecurrenceEditor Component Around line 370, after the AttendeesInput: ```tsx {/* Existing attendees input */} {showAttendees && (
)} {/* ADD THIS: Recurrence editor */} {showRecurrence && (
)} ``` ## Step 6: Add CSS for Recurrence Section In `Scheduler.scss`, add styling for the recurrence section: ```scss .event-modal { // ... existing styles &__recurrence-editor { padding: 1rem; background-color: #f8f9fa; border-radius: 4px; margin-top: 1rem; } // Ensure feature tags wrap properly &__features { display: flex; gap: 0.5rem; flex-wrap: wrap; // Add this if not present } } ``` ## Complete EventModal Component Structure Here's the complete structure with recurrence integrated: ```typescript const EventModal = ({ isOpen, mode, event, calendarUrl, calendars, adapter, onSave, onDelete, onClose, }: EventModalProps) => { const { t } = useTranslation(); const { user } = useAuth(); // Form state const [title, setTitle] = useState(event?.summary || ""); const [description, setDescription] = useState(event?.description || ""); const [location, setLocation] = useState(event?.location || ""); const [startDateTime, setStartDateTime] = useState(""); const [endDateTime, setEndDateTime] = useState(""); const [selectedCalendarUrl, setSelectedCalendarUrl] = useState(calendarUrl); const [isLoading, setIsLoading] = useState(false); // Features state const [attendees, setAttendees] = useState([]); const [showAttendees, setShowAttendees] = useState(false); const [recurrence, setRecurrence] = useState(); const [showRecurrence, setShowRecurrence] = useState(false); // Calculate organizer const organizer: IcsOrganizer | undefined = event?.organizer || ...; // Reset form when event changes useEffect(() => { // Reset basic fields setTitle(event?.summary || ""); setDescription(event?.description || ""); setLocation(event?.location || ""); setSelectedCalendarUrl(calendarUrl); // Reset attendees if (event?.attendees && event.attendees.length > 0) { setAttendees(event.attendees); setShowAttendees(true); } else { setAttendees([]); setShowAttendees(false); } // Reset recurrence if (event?.recurrenceRule) { setRecurrence(event.recurrenceRule); setShowRecurrence(true); } else { setRecurrence(undefined); setShowRecurrence(false); } // Reset dates // ... existing date reset logic }, [event, calendarUrl]); const handleSave = async () => { // ... create icsEvent with recurrence const icsEvent: IcsEvent = { // ... all fields recurrenceRule: recurrence, }; await onSave(icsEvent, selectedCalendarUrl); }; return ( {/* Title, Calendar selector, Dates */} {/* Feature tags */}
{/* Location, Description */} {/* Attendees section */} {showAttendees && ( )} {/* Recurrence section */} {showRecurrence && ( )} {/* Save/Cancel buttons */}
); }; ``` ## Material Icons The recurrence button uses the `repeat` Material icon. Make sure Material Icons are loaded: ```html ``` ## Testing the Integration 1. **Create new recurring event:** - Click "Create" in calendar - Click "Repeat" button (🔁 icon) - Select "Weekly", check "Monday" and "Wednesday" - Save 2. **Edit recurring event:** - Click on a recurring event - Modal should show recurrence with "Repeat" button active - Modify recurrence pattern - Save 3. **Remove recurrence:** - Open recurring event - Click "Repeat" button to expand - Select "None" from dropdown - Save ## Expected Behavior - ✅ Recurrence button toggles RecurrenceEditor visibility - ✅ Active button shows blue background (like attendees) - ✅ RecurrenceEditor state persists when toggling visibility - ✅ Saving event includes recurrence in IcsEvent - ✅ Opening existing recurring event loads recurrence correctly - ✅ Calendar displays recurring event instances ## Troubleshooting ### Recurrence not saving - Check that `recurrenceRule: recurrence` is in the icsEvent object - Verify ts-ics is correctly serializing the RRULE ### Recurrence not loading when editing - Check the useEffect includes recurrence reset - Verify event?.recurrenceRule is being passed from EventCalendarAdapter ### UI not showing properly - Ensure RecurrenceEditor.scss is imported in globals.scss - Check that Material Icons font is loaded ### Events not appearing as recurring - Verify CalDAV server supports RRULE - Check browser console for errors - Inspect .ics file content in network tab ## Next Steps After integration, consider: 1. Adding recurrence summary text (e.g., "Repeats weekly on Monday") 2. Handle editing single instance vs series 3. Add "Delete series" vs "Delete this occurrence" options 4. Show recurrence icon in calendar event display