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 <zomars@me.com>pull/7207/head^2
parent
0ec71e52ef
commit
b9064b1f72
|
@ -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<CredentialPayload>) =>
|
|||
|
||||
export const getConnectedCalendars = async (
|
||||
calendarCredentials: ReturnType<typeof getCalendarCredentials>,
|
||||
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 };
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 = ({
|
|||
<span className="min-w-0 overflow-hidden truncate whitespace-nowrap">
|
||||
{t("default_calendar_selected")}{" "}
|
||||
{queryDestinationCalendar.name &&
|
||||
`(${queryDestinationCalendar?.integration} - ${queryDestinationCalendar.name})`}
|
||||
`| ${queryDestinationCalendar.name} (${queryDestinationCalendar?.integrationTitle} - ${queryDestinationCalendar.primaryEmail})`}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -181,6 +181,9 @@ export interface IntegrationCalendar extends Ensure<Partial<SelectedCalendar>, "
|
|||
readOnly?: boolean;
|
||||
// For displaying the connected email address
|
||||
email?: string;
|
||||
primaryEmail?: string;
|
||||
credentialId?: number;
|
||||
integrationTitle?: string;
|
||||
}
|
||||
|
||||
export interface Calendar {
|
||||
|
|
Loading…
Reference in New Issue