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",
|
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;
|
freq: string;
|
||||||
interval?: number;
|
interval?: number;
|
||||||
selectedDays?: string[];
|
selectedDays?: string[];
|
||||||
|
byday?: string[] | null;
|
||||||
occurrences?: number;
|
occurrences?: number;
|
||||||
endDate?: string;
|
endDate?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Calendars } from "../Calendars/CalendarTypes";
|
|
||||||
import { userAttendee } from "../User/userDataTypes";
|
import { userAttendee } from "../User/userDataTypes";
|
||||||
import { AlarmObject, CalendarEvent } from "./EventsTypes";
|
import { AlarmObject, CalendarEvent } from "./EventsTypes";
|
||||||
import ICAL from "ical.js";
|
import ICAL from "ical.js";
|
||||||
@@ -16,7 +15,7 @@ export function parseCalendarEvent(
|
|||||||
let recurrenceId;
|
let recurrenceId;
|
||||||
const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
|
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()) {
|
switch (key.toLowerCase()) {
|
||||||
case "uid":
|
case "uid":
|
||||||
event.uid = value;
|
event.uid = value;
|
||||||
@@ -86,7 +85,7 @@ export function parseCalendarEvent(
|
|||||||
case "rrule":
|
case "rrule":
|
||||||
event.repetition = { freq: value.freq.toLowerCase() };
|
event.repetition = { freq: value.freq.toLowerCase() };
|
||||||
if (value.byday) {
|
if (value.byday) {
|
||||||
event.repetition.selectedDays = value.byday;
|
event.repetition.byday = value.byday;
|
||||||
}
|
}
|
||||||
if (value.until) {
|
if (value.until) {
|
||||||
event.repetition.endDate = value.until;
|
event.repetition.endDate = value.until;
|
||||||
@@ -106,7 +105,7 @@ export function parseCalendarEvent(
|
|||||||
|
|
||||||
if (valarm) {
|
if (valarm) {
|
||||||
event.alarm = {} as AlarmObject;
|
event.alarm = {} as AlarmObject;
|
||||||
for (const [key, params, type, value] of valarm[1]) {
|
for (const [key, , , value] of valarm[1]) {
|
||||||
switch (key.toLowerCase()) {
|
switch (key.toLowerCase()) {
|
||||||
case "action":
|
case "action":
|
||||||
event.alarm.action = value;
|
event.alarm.action = value;
|
||||||
@@ -175,14 +174,20 @@ export function calendarEventToJCal(
|
|||||||
vevent.push([]);
|
vevent.push([]);
|
||||||
|
|
||||||
if (event.end) {
|
if (event.end) {
|
||||||
if (event.allday && event.end.getTime() === event.start.getTime()) {
|
const startDate = new Date(event.start);
|
||||||
event.end.setDate(event.start.getDate() + 1);
|
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([
|
vevent[1].push([
|
||||||
"dtend",
|
"dtend",
|
||||||
{ tzid },
|
{ tzid },
|
||||||
event.allday ? "date" : "date-time",
|
event.allday ? "date" : "date-time",
|
||||||
formatDateToICal(new Date(event.end), event.allday ?? false),
|
formatDateToICal(finalEndDate, event.allday ?? false),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (event.organizer) {
|
if (event.organizer) {
|
||||||
@@ -210,8 +215,11 @@ export function calendarEventToJCal(
|
|||||||
if (event.repetition.endDate) {
|
if (event.repetition.endDate) {
|
||||||
repetitionRule["until"] = event.repetition.endDate;
|
repetitionRule["until"] = event.repetition.endDate;
|
||||||
}
|
}
|
||||||
if (event.repetition.selectedDays) {
|
if (
|
||||||
repetitionRule["byday"] = event.repetition.selectedDays;
|
event.repetition.byday !== null &&
|
||||||
|
event.repetition.byday !== undefined
|
||||||
|
) {
|
||||||
|
repetitionRule["byday"] = event.repetition.byday;
|
||||||
}
|
}
|
||||||
vevent[1].push(["rrule", {}, "recur", repetitionRule]);
|
vevent[1].push(["rrule", {}, "recur", repetitionRule]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user