11import type { Calendar as OfficeCalendar , User , Event } from "@microsoft/microsoft-graph-types-beta" ;
22import type { DefaultBodyType } from "msw" ;
33
4+ import { MSTeamsLocationType } from "@calcom/app-store/locations" ;
45import dayjs from "@calcom/dayjs" ;
5- import { getLocation } from "@calcom/lib/CalEventParser" ;
6+ import { getLocation , getRichDescriptionHTML } from "@calcom/lib/CalEventParser" ;
67import {
78 CalendarAppDelegationCredentialInvalidGrantError ,
89 CalendarAppDelegationCredentialConfigurationError ,
@@ -254,7 +255,13 @@ export default class Office365CalendarService implements Calendar {
254255 body : JSON . stringify ( this . translateEvent ( event ) ) ,
255256 } ) ;
256257
257- const responseJson = await handleErrorsJson < NewCalendarEventType & { iCalUId : string } > ( response ) ;
258+ const responseJson = await handleErrorsJson <
259+ NewCalendarEventType & { iCalUId : string ; onlineMeeting ?: { joinUrl ?: string } }
260+ > ( response ) ;
261+
262+ if ( responseJson ?. onlineMeeting ?. joinUrl ) {
263+ responseJson . url = responseJson ?. onlineMeeting ?. joinUrl ;
264+ }
258265
259266 return { ...responseJson , iCalUID : responseJson . iCalUId } ;
260267 } catch ( error ) {
@@ -266,12 +273,28 @@ export default class Office365CalendarService implements Calendar {
266273
267274 async updateEvent ( uid : string , event : CalendarServiceEvent ) : Promise < NewCalendarEventType > {
268275 try {
276+ let rescheduledEvent : Event | undefined ;
277+ if ( event . location === MSTeamsLocationType ) {
278+ // Extract the existing body content to preserve the meeting blob, otherwise it breaks and converts it into non-onlineMeeting
279+ const response = await this . fetcher ( `${ await this . getUserEndpoint ( ) } /calendar/events/${ uid } ` , {
280+ method : "GET" ,
281+ } ) ;
282+
283+ rescheduledEvent = await handleErrorsJson < Event > ( response ) ;
284+ }
285+
269286 const response = await this . fetcher ( `${ await this . getUserEndpoint ( ) } /calendar/events/${ uid } ` , {
270287 method : "PATCH" ,
271- body : JSON . stringify ( this . translateEvent ( event ) ) ,
288+ body : JSON . stringify ( this . translateEvent ( event , rescheduledEvent ) ) ,
272289 } ) ;
273290
274- const responseJson = await handleErrorsJson < NewCalendarEventType & { iCalUId : string } > ( response ) ;
291+ const responseJson = await handleErrorsJson <
292+ NewCalendarEventType & { iCalUId : string ; onlineMeeting ?: { joinUrl ?: string } }
293+ > ( response ) ;
294+
295+ if ( responseJson ?. onlineMeeting ?. joinUrl ) {
296+ responseJson . url = responseJson ?. onlineMeeting ?. joinUrl ;
297+ }
275298
276299 return { ...responseJson , iCalUID : responseJson . iCalUId } ;
277300 } catch ( error ) {
@@ -401,12 +424,30 @@ export default class Office365CalendarService implements Calendar {
401424 } ) ;
402425 }
403426
404- private translateEvent = ( event : CalendarServiceEvent ) => {
427+ private translateEvent = ( event : CalendarServiceEvent , rescheduledEvent ?: Event ) => {
428+ const isOnlineMeeting = event . location === MSTeamsLocationType ;
429+ const isRescheduledOnlineMeeting = rescheduledEvent ? rescheduledEvent . isOnlineMeeting : false ;
430+ const existingBody =
431+ rescheduledEvent ?. body ?. contentType === "html" ? rescheduledEvent . body . content : undefined ;
432+
433+ let content = "" ;
434+ if ( isOnlineMeeting ) {
435+ if ( isRescheduledOnlineMeeting && existingBody ) {
436+ content = `
437+ ${ getRichDescriptionHTML ( event ) } <hr>
438+ ${ existingBody } ` . trim ( ) ;
439+ } else {
440+ content = getRichDescriptionHTML ( event ) ;
441+ }
442+ } else {
443+ content = event . calendarDescription ;
444+ }
445+
405446 const office365Event : Event = {
406447 subject : event . title ,
407448 body : {
408- contentType : "text" ,
409- content : event . calendarDescription ,
449+ contentType : isOnlineMeeting ? "html" : "text" ,
450+ content,
410451 } ,
411452 start : {
412453 dateTime : dayjs ( event . startTime ) . tz ( event . organizer . timeZone ) . format ( "YYYY-MM-DDTHH:mm:ss" ) ,
@@ -456,6 +497,17 @@ export default class Office365CalendarService implements Calendar {
456497 if ( event . hideCalendarEventDetails ) {
457498 office365Event . sensitivity = "private" ;
458499 }
500+ if ( isOnlineMeeting ) {
501+ office365Event . isOnlineMeeting = true ;
502+ office365Event . allowNewTimeProposals = true ;
503+ office365Event . onlineMeetingProvider = "teamsForBusiness" ;
504+ // MSTeams sets location as 'Microsoft Teams Meeting' by default, if location is undefined.
505+ // For backward compatibility, setting explicitly.
506+ office365Event . location =
507+ rescheduledEvent && ! isRescheduledOnlineMeeting
508+ ? { displayName : "Microsoft Teams Meeting" }
509+ : undefined ;
510+ }
459511 return office365Event ;
460512 } ;
461513
0 commit comments