77 sendCodingCatEmailDetailed ,
88} from "@/lib/email" ;
99import {
10+ cancelGoogleCalendarBookingEvent ,
1011 createGoogleCalendarBookingEvent ,
1112 STREAMYARD_STUDIO_URL ,
1213} from "@/lib/google-calendar" ;
@@ -232,10 +233,34 @@ export const POST: APIRoute = async ({ request, url }) => {
232233 }
233234 }
234235
236+ const wasAlreadyApproved =
237+ existingBookingDoc ?. status === "approved" ||
238+ existingBookingDoc ?. status === "confirmed" ||
239+ existingBookingDoc ?. status === "scheduled" ;
240+
241+ // If rescheduling an existing 15m Pre-Meeting or 45m Recording, cancel the previous Google Calendar event first
242+ // so the old time slot is freed and the guest receives a clean replacement invite.
243+ if ( isKickoff && existingBookingDoc ?. preMeetingGoogleEventId ) {
244+ await cancelGoogleCalendarBookingEvent ( {
245+ eventId : existingBookingDoc . preMeetingGoogleEventId ,
246+ startAt : existingBookingDoc . preMeetingSlotStartAt ,
247+ durationMinutes : 15 ,
248+ guestName,
249+ } ) . catch ( ( ) => null ) ;
250+ } else if ( ! isKickoff && existingBookingDoc ?. googleCalendarEventId ) {
251+ await cancelGoogleCalendarBookingEvent ( {
252+ eventId : existingBookingDoc . googleCalendarEventId ,
253+ startAt : existingBookingDoc . slotStartAt ,
254+ durationMinutes : 60 ,
255+ guestName,
256+ } ) . catch ( ( ) => null ) ;
257+ }
258+
235259 // Create live Google Calendar event:
236260 // - 15m Pre-Meetings get a confirmed Google Meet invite immediately.
237261 // - 45m Recording slots create an OPAQUE (Busy) placeholder hold on Alex's calendars
238- // so nothing can jump them; StreamYard (https://streamyard.com/c4kv26is93) is revealed once approved.
262+ // so nothing can jump them; StreamYard (https://streamyard.com/c4kv26is93) is revealed once approved
263+ // (or kept revealed if rescheduling an already-approved recording).
239264 const calendarEvent = await createGoogleCalendarBookingEvent ( {
240265 guestName,
241266 guestEmail,
@@ -246,7 +271,7 @@ export const POST: APIRoute = async ({ request, url }) => {
246271 topics,
247272 portalUrl,
248273 isPreMeeting : isKickoff ,
249- autoApproveRecording : false ,
274+ autoApproveRecording : ! isKickoff && wasAlreadyApproved ,
250275 } ) ;
251276
252277 if ( calendarEvent . conflictDetected ) {
@@ -297,9 +322,14 @@ export const POST: APIRoute = async ({ request, url }) => {
297322
298323 if ( canWrite ) {
299324 try {
300- if ( data . preMeetingForBookingId && isKickoff ) {
325+ const targetPreMeetingDocId =
326+ data . preMeetingForBookingId ||
327+ ( isKickoff && existingBookingDoc ?. _id
328+ ? existingBookingDoc . _id
329+ : undefined ) ;
330+ if ( targetPreMeetingDocId && isKickoff ) {
301331 await client
302- . patch ( data . preMeetingForBookingId )
332+ . patch ( targetPreMeetingDocId )
303333 . set ( {
304334 preMeetingStatus : "scheduled" ,
305335 preMeetingSlotStartAt : slotStartAt ,
@@ -321,7 +351,11 @@ export const POST: APIRoute = async ({ request, url }) => {
321351 ...( socialUrl ? { socialUrl } : { } ) ,
322352 track,
323353 sessionType,
324- status : isKickoff ? "scheduled" : "pending" ,
354+ status : isKickoff
355+ ? "scheduled"
356+ : wasAlreadyApproved
357+ ? existingBookingDoc . status
358+ : "pending" ,
325359 slotStartAt,
326360 recordingUrl : STREAMYARD_STUDIO_URL ,
327361 topics,
0 commit comments