I’m using FullCalendar with Vue 3 and the rrule plugin to handle recurring events. However, I’m encountering an issue where events set to recur weekly (or with any other frequency) display every day instead. Here is the relevant part of my code:
Problem Description:
Despite setting the rrule correctly, events that should recur weekly (e.g., every Monday) appear daily instead. Here’s a summary of the data I’m working with:
import FullCalendar from '@fullcalendar/vue3';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import rrulePlugin from '@fullcalendar/rrule';
import type { DateClickArg } from '@fullcalendar/interaction';
import type { CalendarOptions, EventApi, ViewApi } from '@fullcalendar/core';
import { Frequency, Weekday, RRule } from 'rrule';
import type { Options, WeekdayStr } from 'rrule';
interface EventData {
title: string;
start?: string;
end?: string;
extendedProps?: Record<string, unknown>;
allDay?: boolean;
rrule?: {
freq: string;
interval: number;
byweekday: Weekday[];
dtstart: string;
until: string | null;
};
}
const handleDateClick = (info: DateClickArg) => {
const calendarApi = info.view?.calendar;
if (!calendarApi) return;
if (isCopying.value && copiedEventData.value) {
calendarApi.addEvent({
...copiedEventData.value,
start: new Date(
info.date.getTime() - info.date.getTimezoneOffset() * 60000,
).toISOString(),
allDay: info.allDay,
});
isCopying.value = false;
copiedEventData.value = null;
} else {
const title = prompt('Enter Event Title:');
if (title) {
const eventData: EventData = {
title: title.trim(),
start: new Date(
info.date.getTime() - info.date.getTimezoneOffset() * 60000,
).toISOString(),
end: new Date(
info.date.getTime() - info.date.getTimezoneOffset() * 60000,
).toISOString(),
allDay: info.allDay,
};
if (eventForm.isRecurring) {
eventData.rrule = {
freq: eventForm.recurrenceFreq.toString(),
interval: eventForm.recurrenceInterval,
byweekday: eventForm.recurrenceByWeekday.map((day) =>
Weekday.fromStr(day),
),
dtstart: new Date(eventForm.startDate).toISOString(),
until: eventForm.endDate ? new Date(eventForm.endDate).toISOString() : null,
};
}
calendarApi.addEvent(eventData);
}
}
};
const handleEventClick = (info: EventClickArg) => {
currentEvent.value = info.event;
eventForm.eventTitle = info.event.title.trim();
if (info.event.start) {
const start = new Date(
info.event.start.getTime() - info.event.start.getTimezoneOffset() * 60000,
);
eventForm.startDate = start.toISOString().split('T')[0] ?? '';
eventForm.startTime =
start.toISOString().split('T')[1]?.substring(0, 5) ?? '';
} else {
eventForm.startDate = '';
eventForm.startTime = '';
}
if (info.event.end) {
const end = new Date(
info.event.end.getTime() - info.event.end.getTimezoneOffset() * 60000,
);
eventForm.endDate = end.toISOString().split('T')[0] ?? '';
eventForm.endTime = end.toISOString().split('T')[1]?.substring(0, 5) ?? '';
} else {
eventForm.endDate = '';
eventForm.endTime = '';
}
const rrule = info.event.extendedProps.rrule as
| Partial<Options>
| undefined;
eventForm.isRecurring = !!rrule;
eventForm.recurrenceFreq = rrule?.freq ? rrule.freq : Frequency.WEEKLY;
eventForm.recurrenceInterval = rrule?.interval ?? 1;
eventForm.recurrenceByWeekday = (rrule?.byweekday as WeekdayStr[]) ?? ['MO'];
showModal.value = true;
};
const updateEvent = () => {
if (!currentEvent.value) {
closeModal();
return;
}
currentEvent.value.setProp('title', eventForm.eventTitle.trim());
const startDateTime = new Date(
`${eventForm.startDate}T${eventForm.startTime}`,
);
const endDateTime = eventForm.endDate
? new Date(`${eventForm.endDate}T${eventForm.endTime}`)
: null;
if (eventForm.isRecurring) {
const selectedWeekdays = eventForm.recurrenceByWeekday
.map((day) => {
const weekdayObj = weekdays.find((weekday) => weekday.value === day);
return weekdayObj ? weekdayObj.weekday : null;
})
.filter((day) => day !== null);
const recurrenceRule = {
freq: eventForm.recurrenceFreq,
interval: eventForm.recurrenceInterval,
byweekday: selectedWeekdays,
dtstart: startDateTime,
until: endDateTime ?? undefined,
};
console.log('Updated Recurrence Rule:', recurrenceRule);
console.log('Mapped Weekdays:', recurrenceRule.byweekday);
currentEvent.value.setExtendedProp('rrule', recurrenceRule);
} else {
currentEvent.value.setExtendedProp('rrule', null);
}
currentEvent.value.setDates(
startDateTime.toISOString(),
endDateTime?.toISOString() ?? null,
);
closeModal();
};