fix: Duplicate calls syncing Calendar integrations (#26858)
* fix: Duplicate calls syncing Calendar integrations * fix: TS error in handler * Minor fixup * Set cacheUpdatedAt at correct depth of array * Import RouterOutputs
This commit is contained in:
@@ -1,27 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, Suspense } from "react";
|
||||
|
||||
import { InstallAppButton } from "@calcom/app-store/InstallAppButton";
|
||||
import { DestinationCalendarSettingsWebWrapper } from "./DestinationCalendarSettingsWebWrapper";
|
||||
import { SelectedCalendarsSettingsWebWrapper } from "@calcom/web/modules/calendars/components/SelectedCalendarsSettingsWebWrapper";
|
||||
import AppListCard from "@calcom/web/modules/apps/components/AppListCard";
|
||||
import { SkeletonLoader } from "@calcom/web/modules/apps/components/SkeletonLoader";
|
||||
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
|
||||
import { ShellSubHeading } from "@calcom/ui/components/layout";
|
||||
import { List } from "@calcom/ui/components/list";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { revalidateSettingsCalendars } from "@calcom/web/app/cache/path/settings/my-account";
|
||||
|
||||
import { QueryCell } from "@lib/QueryCell";
|
||||
import AppListCard from "@calcom/web/modules/apps/components/AppListCard";
|
||||
import { SkeletonLoader } from "@calcom/web/modules/apps/components/SkeletonLoader";
|
||||
import { SelectedCalendarsSettingsWebWrapper } from "@calcom/web/modules/calendars/components/SelectedCalendarsSettingsWebWrapper";
|
||||
import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections";
|
||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
|
||||
import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections";
|
||||
import { QueryCell } from "@lib/QueryCell";
|
||||
import { Suspense, useEffect } from "react";
|
||||
import { DestinationCalendarSettingsWebWrapper } from "./DestinationCalendarSettingsWebWrapper";
|
||||
|
||||
type CalendarListContainerProps = {
|
||||
connectedCalendars: RouterOutputs["viewer"]["calendars"]["connectedCalendars"];
|
||||
installedCalendars: RouterOutputs["viewer"]["apps"]["integrations"];
|
||||
heading?: boolean;
|
||||
fromOnboarding?: boolean;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
onChanged: () => unknown | Promise<unknown>;
|
||||
@@ -30,7 +35,7 @@ type Props = {
|
||||
isPending?: boolean;
|
||||
};
|
||||
|
||||
function CalendarList(props: Props) {
|
||||
function CalendarList(props: Props): JSX.Element {
|
||||
const { t } = useLocale();
|
||||
const query = trpc.viewer.apps.integrations.useQuery({ variant: "calendar", onlyInstalled: false });
|
||||
|
||||
@@ -66,18 +71,16 @@ function CalendarList(props: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
const AddCalendarButton = () => {
|
||||
const AddCalendarButton = (): JSX.Element => {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<>
|
||||
<Button color="secondary" StartIcon="plus" href="/apps/categories/calendar">
|
||||
{t("add_calendar")}
|
||||
</Button>
|
||||
</>
|
||||
<Button color="secondary" StartIcon="plus" href="/apps/categories/calendar">
|
||||
{t("add_calendar")}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export const CalendarListContainerSkeletonLoader = () => {
|
||||
export const CalendarListContainerSkeletonLoader = (): JSX.Element => {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<SettingsHeader
|
||||
@@ -89,19 +92,12 @@ export const CalendarListContainerSkeletonLoader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
type CalendarListContainerProps = {
|
||||
connectedCalendars: RouterOutputs["viewer"]["calendars"]["connectedCalendars"];
|
||||
installedCalendars: RouterOutputs["viewer"]["apps"]["integrations"];
|
||||
heading?: boolean;
|
||||
fromOnboarding?: boolean;
|
||||
};
|
||||
|
||||
export function CalendarListContainer({
|
||||
connectedCalendars: data,
|
||||
installedCalendars,
|
||||
heading = true,
|
||||
fromOnboarding,
|
||||
}: CalendarListContainerProps) {
|
||||
}: CalendarListContainerProps): JSX.Element {
|
||||
const { t } = useLocale();
|
||||
const { error, setQuery: setError } = useRouterQuery("error");
|
||||
|
||||
@@ -113,7 +109,7 @@ export function CalendarListContainer({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
const utils = trpc.useUtils();
|
||||
const onChanged = () =>
|
||||
const onChanged = (): void => {
|
||||
Promise.allSettled([
|
||||
utils.viewer.apps.integrations.invalidate(
|
||||
{ variant: "calendar", onlyInstalled: true },
|
||||
@@ -124,7 +120,7 @@ export function CalendarListContainer({
|
||||
utils.viewer.calendars.connectedCalendars.invalidate(),
|
||||
revalidateSettingsCalendars(),
|
||||
]);
|
||||
|
||||
};
|
||||
const mutation = trpc.viewer.calendars.setDestinationCalendar.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.viewer.calendars.connectedCalendars.invalidate();
|
||||
@@ -132,51 +128,61 @@ export function CalendarListContainer({
|
||||
},
|
||||
});
|
||||
|
||||
let content = null;
|
||||
if (!!data.connectedCalendars.length || !!installedCalendars?.items.length) {
|
||||
let headingContent = null;
|
||||
if (heading) {
|
||||
headingContent = (
|
||||
<>
|
||||
<DestinationCalendarSettingsWebWrapper connectedCalendars={data} />
|
||||
<Suspense fallback={<SkeletonLoader />}>
|
||||
<SelectedCalendarsSettingsWebWrapper
|
||||
onChanged={onChanged}
|
||||
fromOnboarding={fromOnboarding}
|
||||
destinationCalendarId={data.destinationCalendar?.externalId}
|
||||
isPending={mutation.isPending}
|
||||
connectedCalendars={data}
|
||||
/>
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
}
|
||||
content = headingContent;
|
||||
} else if (fromOnboarding) {
|
||||
content = (
|
||||
<>
|
||||
{!!data?.connectedCalendars.length && (
|
||||
<ShellSubHeading
|
||||
className="mt-4"
|
||||
title={<SubHeadingTitleWithConnections title={t("connect_additional_calendar")} />}
|
||||
/>
|
||||
)}
|
||||
<CalendarList onChanged={onChanged} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<EmptyScreen
|
||||
Icon="calendar"
|
||||
headline={t("no_category_apps", {
|
||||
category: t("calendar").toLowerCase(),
|
||||
})}
|
||||
description={t(`no_category_apps_description_calendar`)}
|
||||
buttonRaw={
|
||||
<Button color="secondary" data-testid="connect-calendar-apps" href="/apps/categories/calendar">
|
||||
{t(`connect_calendar_apps`)}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsHeader
|
||||
title={t("calendars")}
|
||||
description={t("calendars_description")}
|
||||
CTA={<AddCalendarButton />}>
|
||||
{!!data.connectedCalendars.length || !!installedCalendars?.items.length ? (
|
||||
<>
|
||||
{heading && (
|
||||
<>
|
||||
<DestinationCalendarSettingsWebWrapper />
|
||||
<Suspense fallback={<SkeletonLoader />}>
|
||||
<SelectedCalendarsSettingsWebWrapper
|
||||
onChanged={onChanged}
|
||||
fromOnboarding={fromOnboarding}
|
||||
destinationCalendarId={data.destinationCalendar?.externalId}
|
||||
isPending={mutation.isPending}
|
||||
/>
|
||||
</Suspense>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : fromOnboarding ? (
|
||||
<>
|
||||
{!!data?.connectedCalendars.length && (
|
||||
<ShellSubHeading
|
||||
className="mt-4"
|
||||
title={<SubHeadingTitleWithConnections title={t("connect_additional_calendar")} />}
|
||||
/>
|
||||
)}
|
||||
<CalendarList onChanged={onChanged} />
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreen
|
||||
Icon="calendar"
|
||||
headline={t("no_category_apps", {
|
||||
category: t("calendar").toLowerCase(),
|
||||
})}
|
||||
description={t(`no_category_apps_description_calendar`)}
|
||||
buttonRaw={
|
||||
<Button color="secondary" data-testid="connect-calendar-apps" href="/apps/categories/calendar">
|
||||
{t(`connect_calendar_apps`)}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{content}
|
||||
</SettingsHeader>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
reminderSchema,
|
||||
type ReminderMinutes,
|
||||
reminderSchema,
|
||||
} from "@calcom/trpc/server/routers/viewer/calendars/setDestinationReminder.schema";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import { AtomsWrapper } from "../../../../packages/platform/atoms/src/components/atoms-wrapper";
|
||||
import { DestinationCalendarSettings } from "../../../../packages/platform/atoms/destination-calendar/DestinationCalendar";
|
||||
|
||||
export const DestinationCalendarSettingsWebWrapper = () => {
|
||||
import { AtomsWrapper } from "../../../../packages/platform/atoms/src/components/atoms-wrapper";
|
||||
export const DestinationCalendarSettingsWebWrapper = ({
|
||||
connectedCalendars,
|
||||
}: {
|
||||
connectedCalendars?: RouterOutputs["viewer"]["calendars"]["connectedCalendars"];
|
||||
}): JSX.Element | null => {
|
||||
const { t } = useLocale();
|
||||
const calendars = trpc.viewer.calendars.connectedCalendars.useQuery();
|
||||
const calendars = trpc.viewer.calendars.connectedCalendars.useQuery(undefined, {
|
||||
initialData: connectedCalendars,
|
||||
});
|
||||
const utils = trpc.useUtils();
|
||||
const mutation = trpc.viewer.calendars.setDestinationCalendar.useMutation({
|
||||
onSuccess: () => {
|
||||
@@ -33,7 +38,7 @@ export const DestinationCalendarSettingsWebWrapper = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleReminderChange = (value: ReminderMinutes) => {
|
||||
const handleReminderChange = (value: ReminderMinutes): void => {
|
||||
const destCal = calendars.data.destinationCalendar;
|
||||
if (destCal?.credentialId) {
|
||||
reminderMutation.mutate({
|
||||
@@ -47,9 +52,10 @@ export const DestinationCalendarSettingsWebWrapper = () => {
|
||||
const validatedReminderValue = reminderSchema.safeParse(
|
||||
calendars.data.destinationCalendar.customCalendarReminder
|
||||
);
|
||||
const reminderValue: ReminderMinutes = validatedReminderValue.success
|
||||
? validatedReminderValue.data
|
||||
: null;
|
||||
let reminderValue: ReminderMinutes = null;
|
||||
if (validatedReminderValue.success) {
|
||||
reminderValue = validatedReminderValue.data;
|
||||
}
|
||||
|
||||
return (
|
||||
<AtomsWrapper>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
|
||||
import AppListCard from "@calcom/web/modules/apps/components/AppListCard";
|
||||
import CredentialActionsDropdown from "@calcom/web/modules/apps/components/CredentialActionsDropdown";
|
||||
import { SelectedCalendarsSettings } from "@calcom/atoms/selected-calendars/SelectedCalendarsSettings";
|
||||
import AdditionalCalendarSelector from "@calcom/features/calendars/AdditionalCalendarSelector";
|
||||
import { CalendarSwitch } from "@calcom/features/calendars/CalendarSwitch";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -11,8 +7,10 @@ import { trpc } from "@calcom/trpc/react";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
import { Select } from "@calcom/ui/components/form";
|
||||
import { List } from "@calcom/ui/components/list";
|
||||
|
||||
import { SelectedCalendarsSettings } from "@calcom/atoms/selected-calendars/SelectedCalendarsSettings";
|
||||
import AppListCard from "@calcom/web/modules/apps/components/AppListCard";
|
||||
import CredentialActionsDropdown from "@calcom/web/modules/apps/components/CredentialActionsDropdown";
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
|
||||
export enum SelectedCalendarSettingsScope {
|
||||
User = "user",
|
||||
@@ -30,6 +28,7 @@ type SelectedCalendarsSettingsWebWrapperProps = {
|
||||
scope?: SelectedCalendarSettingsScope;
|
||||
setScope?: (scope: SelectedCalendarSettingsScope) => void;
|
||||
disableConnectionModification?: boolean;
|
||||
connectedCalendars?: RouterOutputs["viewer"]["calendars"]["connectedCalendars"];
|
||||
};
|
||||
|
||||
const ConnectedCalendarList = ({
|
||||
@@ -92,7 +91,12 @@ const ConnectedCalendarList = ({
|
||||
isChecked={cal.isSelected}
|
||||
destination={cal.externalId === destinationCalendarId}
|
||||
credentialId={cal.credentialId}
|
||||
eventTypeId={shouldUseEventTypeScope ? eventTypeId : null}
|
||||
eventTypeId={(() => {
|
||||
if (shouldUseEventTypeScope) {
|
||||
return eventTypeId;
|
||||
}
|
||||
return null;
|
||||
})()}
|
||||
delegationCredentialId={connectedCalendar.delegationCredentialId || null}
|
||||
/>
|
||||
))}
|
||||
@@ -145,19 +149,30 @@ export const SelectedCalendarsSettingsWebWrapper = (props: SelectedCalendarsSett
|
||||
eventTypeId = null,
|
||||
} = props;
|
||||
|
||||
const query = trpc.viewer.calendars.connectedCalendars.useQuery(
|
||||
{
|
||||
eventTypeId: scope === SelectedCalendarSettingsScope.EventType ? eventTypeId! : null,
|
||||
},
|
||||
{
|
||||
suspense: true,
|
||||
refetchOnWindowFocus: false,
|
||||
}
|
||||
);
|
||||
let queryInput: { eventTypeId: number } | undefined;
|
||||
if (scope === SelectedCalendarSettingsScope.EventType) {
|
||||
queryInput = { eventTypeId: eventTypeId! };
|
||||
}
|
||||
|
||||
const { isPending } = props;
|
||||
let initialData: RouterOutputs["viewer"]["calendars"]["connectedCalendars"] | undefined;
|
||||
if (scope === SelectedCalendarSettingsScope.User && props.connectedCalendars) {
|
||||
initialData = props.connectedCalendars;
|
||||
}
|
||||
|
||||
const query = trpc.viewer.calendars.connectedCalendars.useQuery(queryInput, {
|
||||
initialData,
|
||||
suspense: true,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
const isPending = props.isPending;
|
||||
const showScopeSelector = !!props.eventTypeId;
|
||||
const isDisabled = disabledScope ? disabledScope === scope : false;
|
||||
|
||||
let isDisabled = false;
|
||||
if (disabledScope) {
|
||||
isDisabled = disabledScope === scope;
|
||||
}
|
||||
|
||||
const shouldDisableConnectionModification = isDisabled || disableConnectionModification;
|
||||
return (
|
||||
<div>
|
||||
@@ -170,7 +185,7 @@ export const SelectedCalendarsSettingsWebWrapper = (props: SelectedCalendarsSett
|
||||
scope={scope}
|
||||
shouldDisableConnectionModification={shouldDisableConnectionModification}
|
||||
/>
|
||||
{query.data?.connectedCalendars && query.data?.connectedCalendars.length > 0 ? (
|
||||
{!!(query.data?.connectedCalendars && query.data?.connectedCalendars.length > 0) && (
|
||||
<ConnectedCalendarList
|
||||
fromOnboarding={props.fromOnboarding}
|
||||
scope={scope}
|
||||
@@ -180,7 +195,7 @@ export const SelectedCalendarsSettingsWebWrapper = (props: SelectedCalendarsSett
|
||||
items={query.data.connectedCalendars}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</SelectedCalendarsSettings>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
|
||||
import type { Dayjs } from "@calcom/dayjs";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
@@ -10,16 +7,14 @@ import {
|
||||
getBusyTimesFromTeamLimits,
|
||||
} from "@calcom/features/busyTimes/lib/getBusyTimesFromLimits";
|
||||
import { getBusyTimesService } from "@calcom/features/di/containers/BusyTimes";
|
||||
import { EventTypeRepository } from "@calcom/features/eventtypes/repositories/eventTypeRepository";
|
||||
import type { EventTypeRepository } from "@calcom/features/eventtypes/repositories/eventTypeRepository";
|
||||
import type { PrismaHolidayRepository } from "@calcom/features/holidays/repositories/PrismaHolidayRepository";
|
||||
import type { PrismaOOORepository } from "@calcom/features/ooo/repositories/PrismaOOORepository";
|
||||
import type { IRedisService } from "@calcom/features/redis/IRedisService";
|
||||
import type { WorkingHours as WorkingHoursWithUserId } from "@calcom/types/schedule";
|
||||
import type { DateOverride, WorkingHours } from "@calcom/features/schedules/lib/date-ranges";
|
||||
import { buildDateRanges, subtract } from "@calcom/features/schedules/lib/date-ranges";
|
||||
import { getWorkingHours } from "@calcom/lib/availability";
|
||||
import { stringToDayjsZod } from "@calcom/lib/dayjs";
|
||||
import { detectEventTypeScheduleForUser } from "./detectEventTypeScheduleForUser";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { getHolidayService } from "@calcom/lib/holidays";
|
||||
import { getHolidayEmoji } from "@calcom/lib/holidays/getHolidayEmoji";
|
||||
@@ -31,20 +26,23 @@ import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { withReporting } from "@calcom/lib/sentryWrapper";
|
||||
import type {
|
||||
Availability,
|
||||
Booking,
|
||||
User,
|
||||
OutOfOfficeEntry,
|
||||
OutOfOfficeReason,
|
||||
EventType as PrismaEventType,
|
||||
Availability,
|
||||
SelectedCalendar,
|
||||
TravelSchedule,
|
||||
User,
|
||||
} from "@calcom/prisma/client";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { CalendarFetchMode, EventBusyDetails, IntervalLimitUnit } from "@calcom/types/Calendar";
|
||||
import type { TimeRange } from "@calcom/types/schedule";
|
||||
import type { CredentialForCalendarService } from "@calcom/types/Credential";
|
||||
import type { TimeRange, WorkingHours as WorkingHoursWithUserId } from "@calcom/types/schedule";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { z } from "zod";
|
||||
import { detectEventTypeScheduleForUser } from "./detectEventTypeScheduleForUser";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["getUserAvailability"] });
|
||||
|
||||
@@ -407,7 +405,7 @@ export class UserAvailabilityService {
|
||||
const getBusyTimesEnd = dateTo.toISOString();
|
||||
|
||||
const selectedCalendars = eventType?.useEventLevelSelectedCalendars
|
||||
? EventTypeRepository.getSelectedCalendarsFromUser({ user, eventTypeId: eventType.id })
|
||||
? user.allSelectedCalendars.filter((calendar) => calendar.eventTypeId === eventType.id)
|
||||
: user.userLevelSelectedCalendars;
|
||||
|
||||
let calendarTimezone: string | null = null;
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
getConnectedCalendars,
|
||||
} from "@calcom/features/calendars/lib/CalendarManager";
|
||||
import { DestinationCalendarRepository } from "@calcom/features/calendars/repositories/DestinationCalendarRepository";
|
||||
import { EventTypeRepository } from "@calcom/features/eventtypes/repositories/eventTypeRepository";
|
||||
import { isDelegationCredential } from "@calcom/lib/delegationCredential";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
||||
@@ -44,7 +43,7 @@ const _ensureNoConflictingNonDelegatedConnectedCalendar = <
|
||||
integration: { slug: string };
|
||||
primary?: { email?: string | null | undefined } | undefined;
|
||||
delegationCredentialId?: string | null | undefined;
|
||||
}
|
||||
},
|
||||
>({
|
||||
connectedCalendars,
|
||||
loggedInUser,
|
||||
@@ -216,7 +215,7 @@ function findMatchingCalendar({
|
||||
calendar: DestinationCalendar;
|
||||
}) {
|
||||
// Check if destinationCalendar exists in connectedCalendars
|
||||
const allCals = connectedCalendars.map((cal) => cal.calendars ?? []).flat();
|
||||
const allCals = connectedCalendars.flatMap((cal) => cal.calendars ?? []);
|
||||
const matchingCalendar = allCals.find(
|
||||
(cal) => cal.externalId === calendar.externalId && cal.integration === calendar.integration
|
||||
);
|
||||
@@ -255,14 +254,10 @@ function getSelectedCalendars({
|
||||
}: {
|
||||
user: UserWithCalendars;
|
||||
eventTypeId: number | null;
|
||||
}) {
|
||||
}): Pick<SelectedCalendar, "externalId" | "integration" | "eventTypeId" | "updatedAt" | "googleChannelId">[] {
|
||||
if (eventTypeId) {
|
||||
return EventTypeRepository.getSelectedCalendarsFromUser({
|
||||
user,
|
||||
eventTypeId: eventTypeId ?? null,
|
||||
});
|
||||
return user.allSelectedCalendars.filter((calendar) => calendar.eventTypeId === eventTypeId);
|
||||
}
|
||||
|
||||
return user.userLevelSelectedCalendars;
|
||||
}
|
||||
|
||||
|
||||
@@ -1408,16 +1408,6 @@ export class EventTypeRepository {
|
||||
};
|
||||
}
|
||||
|
||||
static getSelectedCalendarsFromUser<TSelectedCalendar extends { eventTypeId: number | null }>({
|
||||
user,
|
||||
eventTypeId,
|
||||
}: {
|
||||
user: UserWithSelectedCalendars<TSelectedCalendar>;
|
||||
eventTypeId: number;
|
||||
}) {
|
||||
return user.allSelectedCalendars.filter((calendar) => calendar.eventTypeId === eventTypeId);
|
||||
}
|
||||
|
||||
async findByIdForUserAvailability({ id }: { id: number }) {
|
||||
const eventType = await this.prismaClient.eventType.findUnique({
|
||||
where: { id },
|
||||
|
||||
@@ -11,7 +11,21 @@ type ConnectedCalendarsOptions = {
|
||||
input: TConnectedCalendarsInputSchema;
|
||||
};
|
||||
|
||||
export const connectedCalendarsHandler = async ({ ctx, input }: ConnectedCalendarsOptions) => {
|
||||
type GetConnectedDestinationCalendarsAndEnsureDefaultsInDbResult = Awaited<
|
||||
ReturnType<typeof getConnectedDestinationCalendarsAndEnsureDefaultsInDb>
|
||||
>;
|
||||
|
||||
type ConnectedCalendarsHandlerResult = {
|
||||
destinationCalendar: GetConnectedDestinationCalendarsAndEnsureDefaultsInDbResult["destinationCalendar"];
|
||||
connectedCalendars: (GetConnectedDestinationCalendarsAndEnsureDefaultsInDbResult["connectedCalendars"][number] & {
|
||||
cacheUpdatedAt: null;
|
||||
})[];
|
||||
};
|
||||
|
||||
export const connectedCalendarsHandler = async ({
|
||||
ctx,
|
||||
input,
|
||||
}: ConnectedCalendarsOptions): Promise<ConnectedCalendarsHandlerResult> => {
|
||||
const { user } = ctx;
|
||||
const onboarding = input?.onboarding || false;
|
||||
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ZConnectedCalendarsInputSchema = z
|
||||
export type TConnectedCalendarsInputSchema =
|
||||
| {
|
||||
onboarding?: boolean;
|
||||
// Fetches the calendars for this event-type only if present
|
||||
// Otherwise, fetches the calendars for the authenticated user
|
||||
eventTypeId?: number | null;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
export const ZConnectedCalendarsInputSchema: z.ZodType<TConnectedCalendarsInputSchema> = z
|
||||
.object({
|
||||
onboarding: z.boolean().optional(),
|
||||
// Fetches the calendars for this event-type only if present
|
||||
// Otherwise, fetches the calendars for the authenticated user
|
||||
eventTypeId: z.number().nullable(),
|
||||
eventTypeId: z.number().nullish(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
export type TConnectedCalendarsInputSchema = z.infer<typeof ZConnectedCalendarsInputSchema>;
|
||||
|
||||
Reference in New Issue
Block a user