import type { DateArray, ParticipationRole, EventStatus, ParticipationStatus } from "ics"; import { createEvent } from "ics"; import type { TFunction } from "next-i18next"; import { RRule } from "rrule"; import dayjs from "@calcom/dayjs"; import { getRichDescription } from "@calcom/lib/CalEventParser"; import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; export enum BookingAction { Create = "create", Cancel = "cancel", Reschedule = "reschedule", RequestReschedule = "request_reschedule", LocationChange = "location_change", } export type ICSCalendarEvent = Pick< CalendarEvent, | "uid" | "iCalUID" | "iCalSequence" | "startTime" | "endTime" | "title" | "organizer" | "attendees" | "location" | "recurringEvent" | "team" | "type" | "hideCalendarEventDetails" >; const generateIcsString = ({ event, status, partstat = "ACCEPTED", t, }: { event: ICSCalendarEvent; status: EventStatus; partstat?: ParticipationStatus; t?: TFunction; }) => { const location = getVideoCallUrlFromCalEvent(event) || event.location; // Taking care of recurrence rule let recurrenceRule: string | undefined = undefined; const icsRole: ParticipationRole = "REQ-PARTICIPANT"; if (event.recurringEvent?.count) { // ics appends "RRULE:" already, so removing it from RRule generated string recurrenceRule = new RRule(event.recurringEvent).toString().replace("RRULE:", ""); } const icsEvent = createEvent({ uid: event.iCalUID || event.uid!, sequence: event.iCalSequence || 0, start: dayjs(event.startTime) .utc() .toArray() .slice(0, 6) .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, startInputType: "utc", productId: "calcom/ics", title: event.title, description: getRichDescription(event, t), duration: { minutes: dayjs(event.endTime).diff(dayjs(event.startTime), "minute") }, organizer: { name: event.organizer.name, email: event.organizer.email }, ...{ recurrenceRule }, attendees: [ ...event.attendees.map((attendee: Person) => ({ name: attendee.name, email: attendee.email, partstat, role: icsRole, rsvp: true, })), ...(event.team?.members ? event.team?.members.map((member: Person) => ({ name: member.name, email: member.email, partstat, role: icsRole, rsvp: true, })) : []), ], location: location ?? undefined, method: "REQUEST", status, ...(event.hideCalendarEventDetails ? { classification: "PRIVATE" } : {}), }); if (icsEvent.error) { throw icsEvent.error; } return icsEvent.value; }; export default generateIcsString;