From db5b802a157e4e4abdf5cb55149eb9a4d4e19a12 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:47:21 -0500 Subject: [PATCH] Add destination calendar name to DestinationCalendarSelector (#6701) * Add destination calendar name * Type fix * Search through calendars only for destination calendar credential * Refactor get connected calendars * Clean up --------- Co-authored-by: zomars --- packages/core/CalendarManager.ts | 42 ++++++++++++++----- .../calendars/DestinationCalendarSelector.tsx | 11 ++--- packages/trpc/server/routers/viewer.tsx | 33 ++++----------- .../trpc/server/routers/viewer/bookings.tsx | 2 +- packages/types/Calendar.d.ts | 3 ++ 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/packages/core/CalendarManager.ts b/packages/core/CalendarManager.ts index c5172c0f61..ea01c57f0f 100644 --- a/packages/core/CalendarManager.ts +++ b/packages/core/CalendarManager.ts @@ -9,7 +9,12 @@ import { getUid } from "@calcom/lib/CalEventParser"; import { WEBAPP_URL } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { performance } from "@calcom/lib/server/perfObserver"; -import type { CalendarEvent, EventBusyDate, NewCalendarEventType } from "@calcom/types/Calendar"; +import type { + CalendarEvent, + EventBusyDate, + IntegrationCalendar, + NewCalendarEventType, +} from "@calcom/types/Calendar"; import type { CredentialPayload, CredentialWithAppName } from "@calcom/types/Credential"; import type { EventResult } from "@calcom/types/EventManager"; @@ -31,12 +36,15 @@ export const getCalendarCredentials = (credentials: Array) => export const getConnectedCalendars = async ( calendarCredentials: ReturnType, - selectedCalendars: { externalId: string }[] + selectedCalendars: { externalId: string }[], + destinationCalendarExternalId?: string ) => { + let destinationCalendar: IntegrationCalendar | undefined; const connectedCalendars = await Promise.all( calendarCredentials.map(async (item) => { try { const { calendar, integration, credential } = item; + let primary!: IntegrationCalendar; // Don't leak credentials to the client const credentialId = credential.id; @@ -48,16 +56,28 @@ export const getConnectedCalendars = async ( } const cals = await calendar.listCalendars(); const calendars = _(cals) - .map((cal) => ({ - ...cal, - readOnly: cal.readOnly || false, - primary: cal.primary || null, - isSelected: selectedCalendars.some((selected) => selected.externalId === cal.externalId), - credentialId, - })) + .map((cal) => { + if (cal.primary) { + primary = { ...cal, credentialId }; + } + if (cal.externalId === destinationCalendarExternalId) { + destinationCalendar = cal; + } + return { + ...cal, + readOnly: cal.readOnly || false, + primary: cal.primary || null, + isSelected: selectedCalendars.some((selected) => selected.externalId === cal.externalId), + credentialId, + }; + }) .sortBy(["primary"]) .value(); - const primary = calendars.find((item) => item.primary) ?? calendars.find((cal) => cal !== undefined); + + if (primary && destinationCalendar) { + destinationCalendar.primaryEmail = primary.email; + destinationCalendar.integrationTitle = integration.title; + } if (!primary) { return { integration, @@ -95,7 +115,7 @@ export const getConnectedCalendars = async ( }) ); - return connectedCalendars; + return { connectedCalendars, destinationCalendar }; }; /** diff --git a/packages/features/calendars/DestinationCalendarSelector.tsx b/packages/features/calendars/DestinationCalendarSelector.tsx index 7b05f36bc1..550655b42b 100644 --- a/packages/features/calendars/DestinationCalendarSelector.tsx +++ b/packages/features/calendars/DestinationCalendarSelector.tsx @@ -1,9 +1,10 @@ import classNames from "classnames"; import { useEffect, useState } from "react"; -import { components, OptionProps, SingleValueProps } from "react-select"; +import type { OptionProps, SingleValueProps } from "react-select"; +import { components } from "react-select"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import type { DestinationCalendar } from "@calcom/prisma/client"; import { trpc } from "@calcom/trpc/react"; import { Select } from "@calcom/ui"; @@ -117,10 +118,6 @@ const DestinationCalendarSelector = ({ })), })) ?? []; - // Get primary calendar, which is shown in the placeholder since this is the calendar that will - // be used when no destination calendar is selected. - const primaryCalendar = query.data.destinationCalendarEmail; - const queryDestinationCalendar = query.data.destinationCalendar; return ( @@ -134,7 +131,7 @@ const DestinationCalendarSelector = ({ {t("default_calendar_selected")}{" "} {queryDestinationCalendar.name && - `(${queryDestinationCalendar?.integration} - ${queryDestinationCalendar.name})`} + `| ${queryDestinationCalendar.name} (${queryDestinationCalendar?.integrationTitle} - ${queryDestinationCalendar.primaryEmail})`} ) } diff --git a/packages/trpc/server/routers/viewer.tsx b/packages/trpc/server/routers/viewer.tsx index e4a7f9ec6c..de3e0ba4b1 100644 --- a/packages/trpc/server/routers/viewer.tsx +++ b/packages/trpc/server/routers/viewer.tsx @@ -1,4 +1,5 @@ -import { AppCategories, BookingStatus, DestinationCalendar, IdentityProvider, Prisma } from "@prisma/client"; +import type { DestinationCalendar, Prisma } from "@prisma/client"; +import { AppCategories, BookingStatus, IdentityProvider } from "@prisma/client"; import _ from "lodash"; import { authenticator } from "otplib"; import z from "zod"; @@ -321,10 +322,11 @@ const loggedInViewerRouter = router({ const calendarCredentials = getCalendarCredentials(userCredentials); // get all the connected integrations' calendars (from third party) - const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars); - - // store email of the destination calendar to display - let destinationCalendarEmail = null; + const { connectedCalendars, destinationCalendar } = await getConnectedCalendars( + calendarCredentials, + user.selectedCalendars, + user.destinationCalendar?.externalId + ); if (connectedCalendars.length === 0) { /* As there are no connected calendars, delete the destination calendar if it exists */ @@ -348,7 +350,6 @@ const loggedInViewerRouter = router({ credentialId, }, }); - destinationCalendarEmail = email ?? user.destinationCalendar?.externalId; } else { /* There are connected calendars and a destination calendar */ @@ -371,32 +372,14 @@ const loggedInViewerRouter = router({ }, }); } - destinationCalendarEmail = destinationCal?.email ?? user.destinationCalendar?.externalId; - } - - let destinationCalendarName = user.destinationCalendar?.externalId || ""; - let destinationCalendarIntegration = ""; - - for (const integration of connectedCalendars) { - if (integration.calendars) { - for (const calendar of integration.calendars) { - if (calendar.externalId === user.destinationCalendar?.externalId) { - destinationCalendarName = calendar.name || calendar.externalId; - destinationCalendarIntegration = integration.integration.title || ""; - break; - } - } - } } return { connectedCalendars, destinationCalendar: { ...(user.destinationCalendar as DestinationCalendar), - name: destinationCalendarName, - integration: destinationCalendarIntegration, + ...destinationCalendar, }, - destinationCalendarEmail, }; }), setDestinationCalendar: authedProcedure diff --git a/packages/trpc/server/routers/viewer/bookings.tsx b/packages/trpc/server/routers/viewer/bookings.tsx index 48387f7eb7..572bd1bd76 100644 --- a/packages/trpc/server/routers/viewer/bookings.tsx +++ b/packages/trpc/server/routers/viewer/bookings.tsx @@ -304,7 +304,7 @@ export const bookingsRouter = router({ const recurringInfo = recurringInfoBasic.map( ( - info: (typeof recurringInfoBasic)[number] + info: typeof recurringInfoBasic[number] ): { recurringEventId: string | null; count: number; diff --git a/packages/types/Calendar.d.ts b/packages/types/Calendar.d.ts index 605e633274..6d33ae2b3a 100644 --- a/packages/types/Calendar.d.ts +++ b/packages/types/Calendar.d.ts @@ -181,6 +181,9 @@ export interface IntegrationCalendar extends Ensure, " readOnly?: boolean; // For displaying the connected email address email?: string; + primaryEmail?: string; + credentialId?: number; + integrationTitle?: string; } export interface Calendar {