feat: add byday field support for event repetition
- Add byday field to RepetitionObject interface in EventsTypes.ts - Update calendarEventToJCal to handle byday field (array or null) - Update parseCalendarEvent to parse byday from JCal format - Fix all-day event dtend logic to increment by 1 day when start equals end - Add comprehensive test cases for byday field handling
This commit is contained in:
@@ -104,4 +104,56 @@ describe("eventApi", () => {
|
||||
method: "DELETE",
|
||||
});
|
||||
});
|
||||
|
||||
test("putEvent handles byday field correctly", async () => {
|
||||
const mockResponse = { status: 201, url: "/dav/cals/test.ics" };
|
||||
(api as unknown as jest.Mock).mockReturnValue(mockResponse);
|
||||
|
||||
const eventWithByday = {
|
||||
...mockEvent,
|
||||
repetition: {
|
||||
freq: "weekly",
|
||||
interval: 1,
|
||||
byday: ["MO", "WE", "FR"],
|
||||
},
|
||||
};
|
||||
|
||||
await putEvent(eventWithByday);
|
||||
const expectedResult = calendarEventToJCal(eventWithByday);
|
||||
|
||||
expect(api).toHaveBeenCalledWith(
|
||||
"dav/calendars/667037022b752d0026472254/667037022b752d0026472254/cal1.ics",
|
||||
expect.objectContaining({
|
||||
method: "PUT",
|
||||
headers: { "content-type": "text/calendar; charset=utf-8" },
|
||||
body: JSON.stringify(expectedResult),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("putEvent handles null byday field correctly", async () => {
|
||||
const mockResponse = { status: 201, url: "/dav/cals/test.ics" };
|
||||
(api as unknown as jest.Mock).mockReturnValue(mockResponse);
|
||||
|
||||
const eventWithNullByday = {
|
||||
...mockEvent,
|
||||
repetition: {
|
||||
freq: "daily",
|
||||
interval: 1,
|
||||
byday: null,
|
||||
},
|
||||
};
|
||||
|
||||
await putEvent(eventWithNullByday);
|
||||
const expectedResult = calendarEventToJCal(eventWithNullByday);
|
||||
|
||||
expect(api).toHaveBeenCalledWith(
|
||||
"dav/calendars/667037022b752d0026472254/667037022b752d0026472254/cal1.ics",
|
||||
expect.objectContaining({
|
||||
method: "PUT",
|
||||
headers: { "content-type": "text/calendar; charset=utf-8" },
|
||||
body: JSON.stringify(expectedResult),
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface RepetitionObject {
|
||||
freq: string;
|
||||
interval?: number;
|
||||
selectedDays?: string[];
|
||||
byday?: string[] | null;
|
||||
occurrences?: number;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Calendars } from "../Calendars/CalendarTypes";
|
||||
import { userAttendee } from "../User/userDataTypes";
|
||||
import { AlarmObject, CalendarEvent } from "./EventsTypes";
|
||||
import ICAL from "ical.js";
|
||||
@@ -16,7 +15,7 @@ export function parseCalendarEvent(
|
||||
let recurrenceId;
|
||||
const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
|
||||
|
||||
for (const [key, params, type, value] of data) {
|
||||
for (const [key, params, , value] of data) {
|
||||
switch (key.toLowerCase()) {
|
||||
case "uid":
|
||||
event.uid = value;
|
||||
@@ -86,7 +85,7 @@ export function parseCalendarEvent(
|
||||
case "rrule":
|
||||
event.repetition = { freq: value.freq.toLowerCase() };
|
||||
if (value.byday) {
|
||||
event.repetition.selectedDays = value.byday;
|
||||
event.repetition.byday = value.byday;
|
||||
}
|
||||
if (value.until) {
|
||||
event.repetition.endDate = value.until;
|
||||
@@ -106,7 +105,7 @@ export function parseCalendarEvent(
|
||||
|
||||
if (valarm) {
|
||||
event.alarm = {} as AlarmObject;
|
||||
for (const [key, params, type, value] of valarm[1]) {
|
||||
for (const [key, , , value] of valarm[1]) {
|
||||
switch (key.toLowerCase()) {
|
||||
case "action":
|
||||
event.alarm.action = value;
|
||||
@@ -175,14 +174,20 @@ export function calendarEventToJCal(
|
||||
vevent.push([]);
|
||||
|
||||
if (event.end) {
|
||||
if (event.allday && event.end.getTime() === event.start.getTime()) {
|
||||
event.end.setDate(event.start.getDate() + 1);
|
||||
const startDate = new Date(event.start);
|
||||
const endDate = new Date(event.end);
|
||||
let finalEndDate = endDate;
|
||||
|
||||
if (event.allday && endDate.getTime() === startDate.getTime()) {
|
||||
finalEndDate = new Date(endDate);
|
||||
finalEndDate.setDate(startDate.getDate() + 1);
|
||||
}
|
||||
|
||||
vevent[1].push([
|
||||
"dtend",
|
||||
{ tzid },
|
||||
event.allday ? "date" : "date-time",
|
||||
formatDateToICal(new Date(event.end), event.allday ?? false),
|
||||
formatDateToICal(finalEndDate, event.allday ?? false),
|
||||
]);
|
||||
}
|
||||
if (event.organizer) {
|
||||
@@ -210,8 +215,11 @@ export function calendarEventToJCal(
|
||||
if (event.repetition.endDate) {
|
||||
repetitionRule["until"] = event.repetition.endDate;
|
||||
}
|
||||
if (event.repetition.selectedDays) {
|
||||
repetitionRule["byday"] = event.repetition.selectedDays;
|
||||
if (
|
||||
event.repetition.byday !== null &&
|
||||
event.repetition.byday !== undefined
|
||||
) {
|
||||
repetitionRule["byday"] = event.repetition.byday;
|
||||
}
|
||||
vevent[1].push(["rrule", {}, "recur", repetitionRule]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user