diff --git a/apps/swagger/lib/snippets.ts b/apps/swagger/lib/snippets.ts index fdeb5ead3a..cbdc52d97f 100644 --- a/apps/swagger/lib/snippets.ts +++ b/apps/swagger/lib/snippets.ts @@ -30,7 +30,7 @@ export const SnippedGenerator = { // extend some internals to gain information about current path, method and spec in the generator function metioned later spec: { wrapSelectors: { - requestFor: (ori, system) => (state, path, method) => { + requestFor: (ori) => (state, path, method) => { return ori(path, method) ?.set("spec", state.get("json", {})) ?.setIn(["oasPathMethod", "path"], path) diff --git a/apps/web/components/AppListCard.tsx b/apps/web/components/AppListCard.tsx index 5d73bc6d2a..3887e29be4 100644 --- a/apps/web/components/AppListCard.tsx +++ b/apps/web/components/AppListCard.tsx @@ -60,6 +60,7 @@ export default function AppListCard(props: AppListCardProps) { timeoutRef.current = null; } }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( diff --git a/apps/web/components/PageWrapper.tsx b/apps/web/components/PageWrapper.tsx index ad7ad649de..fbefef723f 100644 --- a/apps/web/components/PageWrapper.tsx +++ b/apps/web/components/PageWrapper.tsx @@ -15,7 +15,7 @@ import { seoConfig } from "@lib/config/next-seo.config"; import I18nLanguageHandler from "@components/I18nLanguageHandler"; export interface CalPageWrapper { - (props?: any): JSX.Element; + (props?: AppProps): JSX.Element; PageWrapper?: AppProps["Component"]["PageWrapper"]; } diff --git a/apps/web/components/apps/AdditionalCalendarSelector.tsx b/apps/web/components/apps/AdditionalCalendarSelector.tsx index 762d4cde93..6fdd24ad9e 100644 --- a/apps/web/components/apps/AdditionalCalendarSelector.tsx +++ b/apps/web/components/apps/AdditionalCalendarSelector.tsx @@ -1,3 +1,5 @@ +import type { FunctionComponent, SVGProps } from "react"; + import { InstallAppButton } from "@calcom/app-store/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; @@ -55,7 +57,7 @@ const AdditionalCalendarSelector = ({ isLoading }: AdditionalCalendarSelectorPro { - const props = { ...installProps } as any; + const props = { ...installProps } as FunctionComponent>; return ( diff --git a/apps/web/components/apps/layouts/InstalledAppsLayout.tsx b/apps/web/components/apps/layouts/InstalledAppsLayout.tsx index 23107868e3..40b7f98ea1 100644 --- a/apps/web/components/apps/layouts/InstalledAppsLayout.tsx +++ b/apps/web/components/apps/layouts/InstalledAppsLayout.tsx @@ -2,60 +2,12 @@ import type { ComponentProps } from "react"; import React from "react"; import AppCategoryNavigation from "@calcom/app-store/_components/AppCategoryNavigation"; -import type { InstalledAppVariants } from "@calcom/app-store/utils"; import Shell from "@calcom/features/shell/Shell"; -import { trpc } from "@calcom/trpc/react"; -import type { HorizontalTabItemProps, VerticalTabItemProps } from "@calcom/ui"; -import { BarChart, Calendar, CreditCard, Grid, Share2, Video } from "@calcom/ui/components/icon"; - -const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [ - { - name: "calendar", - href: "/apps/installed/calendar", - icon: Calendar, - }, - { - name: "conferencing", - href: "/apps/installed/conferencing", - icon: Video, - }, - { - name: "payment", - href: "/apps/installed/payment", - icon: CreditCard, - }, - { - name: "automation", - href: "/apps/installed/automation", - icon: Share2, - }, - { - name: "analytics", - href: "/apps/installed/analytics", - icon: BarChart, - }, - { - name: "other", - href: "/apps/installed/other", - icon: Grid, - }, -]; export default function InstalledAppsLayout({ children, ...rest }: { children: React.ReactNode } & ComponentProps) { - const variant: (typeof InstalledAppVariants)[number] = "payment"; - - const query = trpc.viewer.integrations.useQuery({ - variant, - onlyInstalled: true, - }); - let actualTabs = tabs; - if (query.data?.items.length === 0) { - actualTabs = tabs.filter((tab) => tab.name !== variant); - } - return ( diff --git a/apps/web/components/eventtype/EventAdvancedTab.tsx b/apps/web/components/eventtype/EventAdvancedTab.tsx index 0c9720480c..0bdf52e309 100644 --- a/apps/web/components/eventtype/EventAdvancedTab.tsx +++ b/apps/web/components/eventtype/EventAdvancedTab.tsx @@ -65,7 +65,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick { !hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0]?.id ?? team?.id)); diff --git a/apps/web/components/eventtype/EventSetupTab.tsx b/apps/web/components/eventtype/EventSetupTab.tsx index 82ba7366da..82e46844b7 100644 --- a/apps/web/components/eventtype/EventSetupTab.tsx +++ b/apps/web/components/eventtype/EventSetupTab.tsx @@ -115,7 +115,7 @@ export const EventSetupTab = ( const [showLocationModal, setShowLocationModal] = useState(false); const [editingLocationType, setEditingLocationType] = useState(""); const [selectedLocation, setSelectedLocation] = useState(undefined); - const [multipleDuration, setMultipleDuration] = useState(eventType.metadata.multipleDuration); + const [multipleDuration, setMultipleDuration] = useState(eventType.metadata?.multipleDuration); const locationOptions = props.locationOptions.filter((option) => { return !team ? option.label !== "Conferencing" : true; diff --git a/apps/web/components/eventtype/EventTypeSingleLayout.tsx b/apps/web/components/eventtype/EventTypeSingleLayout.tsx index 5d441c78a7..dbea30e29d 100644 --- a/apps/web/components/eventtype/EventTypeSingleLayout.tsx +++ b/apps/web/components/eventtype/EventTypeSingleLayout.tsx @@ -75,8 +75,7 @@ function getNavigation(props: { installedAppsNumber: number; availability: AvailabilityOption | undefined; }) { - const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber, availability } = - props; + const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber } = props; const duration = eventType.metadata?.multipleDuration?.map((duration) => ` ${duration}`) || eventType.length; @@ -221,7 +220,18 @@ function EventTypeSingleLayout({ }); } return navigation; - }, [t, eventType, installedAppsNumber, enabledAppsNumber, enabledWorkflowsNumber, team, availability]); + }, [ + t, + eventType, + enabledAppsNumber, + installedAppsNumber, + enabledWorkflowsNumber, + availability, + isManagedEventType, + isChildrenManagedEventType, + team, + formMethods, + ]); const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${ eventType.slug @@ -237,7 +247,7 @@ function EventTypeSingleLayout({ heading={eventType.title} CTA={
- {!eventType.metadata.managedEventConfig && ( + {!eventType.metadata?.managedEventConfig && ( <>
{ const { user } = props; const { t } = useLocale(); - const avatarRef = useRef(null!); + const avatarRef = useRef(null); const { setValue, handleSubmit, getValues } = useForm({ defaultValues: { bio: user?.bio || "" }, }); @@ -76,7 +76,7 @@ const UserProfile = (props: IUserProfileProps) => { async function updateProfileHandler(event: FormEvent) { event.preventDefault(); - const enteredAvatar = avatarRef.current.value; + const enteredAvatar = avatarRef.current?.value; mutation.mutate({ avatar: enteredAvatar, }); @@ -127,14 +127,16 @@ const UserProfile = (props: IUserProfileProps) => { id="avatar-upload" buttonMsg={t("add_profile_photo")} handleAvatarChange={(newAvatar) => { - avatarRef.current.value = newAvatar; + if (avatarRef.current) { + avatarRef.current.value = newAvatar; + } const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLInputElement.prototype, "value" )?.set; nativeInputValueSetter?.call(avatarRef.current, newAvatar); const ev2 = new Event("input", { bubbles: true }); - avatarRef.current.dispatchEvent(ev2); + avatarRef.current?.dispatchEvent(ev2); updateProfileHandler(ev2 as unknown as FormEvent); setImageSrc(newAvatar); }} diff --git a/apps/web/lib/QueryCell.tsx b/apps/web/lib/QueryCell.tsx index aeeeedb007..be7ede4263 100644 --- a/apps/web/lib/QueryCell.tsx +++ b/apps/web/lib/QueryCell.tsx @@ -66,6 +66,7 @@ export function QueryCell( if ("empty" in opts && (query.data == null || (Array.isArray(query.data) && query.data.length === 0))) { return opts.empty(query); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any return opts.success(query as any); } @@ -88,9 +89,10 @@ const withQuery = < TInput = inferProcedureInput, TOutput = inferProcedureOutput >( - queryProcedure: DecorateProcedure, + queryProcedure: DecorateProcedure, inferProcedureOutput>, + input?: TInput, - params?: UseTRPCQueryOptions + params?: UseTRPCQueryOptions ) => { return function WithQuery( opts: Omit< diff --git a/apps/web/lib/types/inferSSRProps.ts b/apps/web/lib/types/inferSSRProps.ts index 3564b6c905..dcbab510e8 100644 --- a/apps/web/lib/types/inferSSRProps.ts +++ b/apps/web/lib/types/inferSSRProps.ts @@ -1,6 +1,7 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ type GetSSRResult = // - { props: TProps } | { redirect: any } | { notFound: boolean }; + { props: TProps } | { redirect: { destination: string; permanent: boolean } } | { notFound: boolean }; type GetSSRFn = (...args: any[]) => Promise>; diff --git a/apps/web/pages/auth/saml-idp.tsx b/apps/web/pages/auth/saml-idp.tsx index 153fffed41..21489f124b 100644 --- a/apps/web/pages/auth/saml-idp.tsx +++ b/apps/web/pages/auth/saml-idp.tsx @@ -19,6 +19,7 @@ export default function Page() { callbackUrl: "/", code, }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return null; diff --git a/apps/web/pages/auth/sso/[provider].tsx b/apps/web/pages/auth/sso/[provider].tsx index 6a68051cf5..a5d0c0341e 100644 --- a/apps/web/pages/auth/sso/[provider].tsx +++ b/apps/web/pages/auth/sso/[provider].tsx @@ -111,8 +111,10 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => const ret = await samlTenantProduct(prisma, emailParam); tenant = ret.tenant; product = ret.product; - } catch (e: any) { - error = e.message; + } catch (e) { + if (e instanceof Error) { + error = e.message; + } } } } diff --git a/apps/web/pages/auth/sso/direct.tsx b/apps/web/pages/auth/sso/direct.tsx index d1390a3043..66551c62d4 100644 --- a/apps/web/pages/auth/sso/direct.tsx +++ b/apps/web/pages/auth/sso/direct.tsx @@ -18,6 +18,7 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps { @@ -29,6 +30,7 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps { const { data, isLoading } = trpc.viewer.availability.user.useQuery( { - username: user.username!, + username: user.username || "", dateFrom: selectedDate.startOf("day").utc().format(), dateTo: selectedDate.endOf("day").utc().format(), withSource: true, diff --git a/apps/web/pages/booking/[uid].tsx b/apps/web/pages/booking/[uid].tsx index f66736cf79..87f9ab0315 100644 --- a/apps/web/pages/booking/[uid].tsx +++ b/apps/web/pages/booking/[uid].tsx @@ -102,7 +102,6 @@ export default function Success(props: SuccessProps) { allRemainingBookings, isSuccessBookingPage, cancel: isCancellationMode, - changes, formerTime, email, seatReferenceUid, @@ -222,6 +221,7 @@ export default function Success(props: SuccessProps) { setCalculatedDuration( dayjs(props.bookingInfo.endTime).diff(dayjs(props.bookingInfo.startTime), "minutes") ); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); function eventLink(): string { diff --git a/apps/web/pages/event-types/[type]/index.tsx b/apps/web/pages/event-types/[type]/index.tsx index 7c098997c0..ae2c399055 100644 --- a/apps/web/pages/event-types/[type]/index.tsx +++ b/apps/web/pages/event-types/[type]/index.tsx @@ -3,7 +3,7 @@ import { useAutoAnimate } from "@formkit/auto-animate/react"; import { zodResolver } from "@hookform/resolvers/zod"; import type { GetServerSidePropsContext } from "next"; import { Trans } from "next-i18next"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -184,17 +184,17 @@ const EventTypePage = (props: EventTypeSetupProps) => { const metadata = eventType.metadata; // fallback to !!eventType.schedule when 'useHostSchedulesForTeamEvent' is undefined - if (!!team) { + if (!!team && metadata !== null) { metadata.config = { ...metadata.config, useHostSchedulesForTeamEvent: - typeof eventType.metadata.config?.useHostSchedulesForTeamEvent !== "undefined" - ? eventType.metadata.config?.useHostSchedulesForTeamEvent === true + typeof eventType.metadata?.config?.useHostSchedulesForTeamEvent !== "undefined" + ? eventType.metadata?.config?.useHostSchedulesForTeamEvent === true : !!eventType.schedule, }; } else { // Make sure non-team events NEVER have this config key; - delete metadata.config?.useHostSchedulesForTeamEvent; + delete metadata?.config?.useHostSchedulesForTeamEvent; } const bookingFields: Prisma.JsonObject = {}; @@ -203,41 +203,43 @@ const EventTypePage = (props: EventTypeSetupProps) => { bookingFields[name] = name; }); - const defaultValues = { - title: eventType.title, - locations: eventType.locations || [], - recurringEvent: eventType.recurringEvent || null, - description: eventType.description ?? undefined, - schedule: eventType.schedule || undefined, - bookingLimits: eventType.bookingLimits || undefined, - durationLimits: eventType.durationLimits || undefined, - length: eventType.length, - offsetStart: eventType.offsetStart, - hidden: eventType.hidden, - periodDates: { - startDate: periodDates.startDate, - endDate: periodDates.endDate, - }, - bookingFields: eventType.bookingFields, - periodType: eventType.periodType, - periodCountCalendarDays: eventType.periodCountCalendarDays ? "1" : "0", - schedulingType: eventType.schedulingType, - minimumBookingNotice: eventType.minimumBookingNotice, - metadata, - hosts: eventType.hosts, - children: eventType.children.map((ch) => ({ - ...ch, - created: true, - owner: { - ...ch.owner, - eventTypeSlugs: - eventType.team?.members - .find((mem) => mem.user.id === ch.owner.id) - ?.user.eventTypes.map((evTy) => evTy.slug) - .filter((slug) => slug !== eventType.slug) ?? [], + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const defaultValues: any = useMemo(() => { + return { + title: eventType.title, + locations: eventType.locations || [], + recurringEvent: eventType.recurringEvent || null, + description: eventType.description ?? undefined, + schedule: eventType.schedule || undefined, + bookingLimits: eventType.bookingLimits || undefined, + durationLimits: eventType.durationLimits || undefined, + length: eventType.length, + hidden: eventType.hidden, + periodDates: { + startDate: periodDates.startDate, + endDate: periodDates.endDate, }, - })), - } as const; + bookingFields: eventType.bookingFields, + periodType: eventType.periodType, + periodCountCalendarDays: eventType.periodCountCalendarDays ? "1" : "0", + schedulingType: eventType.schedulingType, + minimumBookingNotice: eventType.minimumBookingNotice, + metadata, + hosts: eventType.hosts, + children: eventType.children.map((ch) => ({ + ...ch, + created: true, + owner: { + ...ch.owner, + eventTypeSlugs: + eventType.team?.members + .find((mem) => mem.user.id === ch.owner.id) + ?.user.eventTypes.map((evTy) => evTy.slug) + .filter((slug) => slug !== eventType.slug) ?? [], + }, + })), + }; + }, [eventType, periodDates, metadata]); const formMethods = useForm({ defaultValues, @@ -270,6 +272,7 @@ const EventTypePage = (props: EventTypeSetupProps) => { //TODO: What's the best way to sync the form with backend formMethods.setValue("bookingFields", defaultValues.bookingFields); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [defaultValues]); const appsMetadata = formMethods.getValues("metadata")?.apps; @@ -415,9 +418,6 @@ const EventTypePage = (props: EventTypeSetupProps) => { // We don't need to send send these values to the backend // eslint-disable-next-line @typescript-eslint/no-unused-vars seatsPerTimeSlotEnabled, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - minimumBookingNoticeInDurationType, - availability, ...input } = values; diff --git a/apps/web/pages/event-types/index.tsx b/apps/web/pages/event-types/index.tsx index 453bb5f4f8..32e72156e2 100644 --- a/apps/web/pages/event-types/index.tsx +++ b/apps/web/pages/event-types/index.tsx @@ -393,11 +393,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL className="relative top-1 right-3" size="sm" truncateAfter={4} - items={type.users.map((organizer: { name: any; username: any }) => ({ - alt: organizer.name || "", - image: `${WEBAPP_URL}/${organizer.username}/avatar.png`, - title: organizer.name || "", - }))} + items={type.users.map( + (organizer: { name: string | null; username: string | null }) => ({ + alt: organizer.name || "", + image: `${WEBAPP_URL}/${organizer.username}/avatar.png`, + title: organizer.name || "", + }) + )} /> )} {isManagedEventType && ( @@ -780,7 +782,8 @@ const CTA = () => { ); }; -const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer); +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer as any); const EventTypesPage = () => { const { t } = useLocale(); @@ -793,6 +796,7 @@ const EventTypesPage = () => { if (query?.openIntercom && query?.openIntercom === "true") { open(); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( @@ -816,7 +820,7 @@ const EventTypesPage = () => { {isMobile ? ( ) : ( - data.eventTypeGroups.map((group, index) => ( + data.eventTypeGroups.map((group: EventTypeGroup, index: number) => (
{ const { t } = useLocale(); diff --git a/apps/web/pages/settings/security/password.tsx b/apps/web/pages/settings/security/password.tsx index 33a09370d7..b73802bed5 100644 --- a/apps/web/pages/settings/security/password.tsx +++ b/apps/web/pages/settings/security/password.tsx @@ -34,7 +34,7 @@ const PasswordView = () => { onSettled: () => { utils.viewer.me.invalidate(); }, - onMutate: async ({ metadata }) => { + onMutate: async () => { await utils.viewer.me.cancel(); const previousValue = utils.viewer.me.getData(); const previousMetadata = userMetadata.parse(previousValue?.metadata); diff --git a/apps/web/pages/video/[uid].tsx b/apps/web/pages/video/[uid].tsx index c148a4bb05..36d3e6968c 100644 --- a/apps/web/pages/video/[uid].tsx +++ b/apps/web/pages/video/[uid].tsx @@ -64,6 +64,7 @@ export default function JoinCall(props: JoinCallPageProps) { return () => { callFrame.destroy(); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const onRecordingStopped = () => { @@ -169,6 +170,7 @@ function ProgressBar(props: ProgressBarProps) { intervalRef.current = null; } }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const prev = startDuration - duration; diff --git a/apps/web/playwright/auth/delete-account.e2e.ts b/apps/web/playwright/auth/delete-account.e2e.ts index 57d2b23a7f..7861cbdd00 100644 --- a/apps/web/playwright/auth/delete-account.e2e.ts +++ b/apps/web/playwright/auth/delete-account.e2e.ts @@ -15,10 +15,11 @@ test("Can delete user account", async ({ page, users }) => { await page.goto(`/settings/my-account/profile`); await page.waitForLoadState("networkidle"); await page.click("[data-testid=delete-account]"); - if (!user.username) throw Error(`Test user doesn't have a username`); + + expect(user.username).toBeTruthy(); const $passwordField = page.locator("[data-testid=password]"); - await $passwordField.fill(user.username); + await $passwordField.fill(String(user.username)); await Promise.all([ page.waitForURL((url) => url.pathname === "/auth/logout"), diff --git a/apps/web/playwright/auth/forgot-password.e2e.ts b/apps/web/playwright/auth/forgot-password.e2e.ts index e8d3eb224f..d43fb5c2cb 100644 --- a/apps/web/playwright/auth/forgot-password.e2e.ts +++ b/apps/web/playwright/auth/forgot-password.e2e.ts @@ -5,9 +5,10 @@ import { test } from "../lib/fixtures"; test.afterEach(({ users }) => users.deleteAll()); test("Can reset forgotten password", async ({ page, users }) => { + // eslint-disable-next-line playwright/no-skipped-test test.skip(process.env.NEXT_PUBLIC_IS_E2E !== "1", "It shouldn't if we can't skip email"); const user = await users.create(); - const newPassword = `${user.username!}-123`; + const newPassword = `${user.username}-123`; // Got to reset password flow await page.goto("/auth/forgot-password"); diff --git a/apps/web/playwright/change-password.e2e.ts b/apps/web/playwright/change-password.e2e.ts index 45f3de2d29..54da39da70 100644 --- a/apps/web/playwright/change-password.e2e.ts +++ b/apps/web/playwright/change-password.e2e.ts @@ -10,12 +10,13 @@ test.describe("Change Password Test", () => { await pro.login(); // Go to http://localhost:3000/settings/security await page.goto("/settings/security/password"); - if (!pro.username) throw Error("Test user doesn't have a username"); + + expect(pro.username).toBeTruthy(); await page.waitForLoadState("networkidle"); // Fill form - await page.locator('[name="oldPassword"]').fill(pro.username); + await page.locator('[name="oldPassword"]').fill(String(pro.username)); const $newPasswordField = page.locator('[name="newPassword"]'); $newPasswordField.fill(`${pro.username}Aa1111`); diff --git a/apps/web/playwright/change-username.e2e.ts b/apps/web/playwright/change-username.e2e.ts index 9f8b45412c..c21202109c 100644 --- a/apps/web/playwright/change-username.e2e.ts +++ b/apps/web/playwright/change-username.e2e.ts @@ -50,6 +50,7 @@ test.describe("Change username on settings", () => { test("User can update to PREMIUM username", async ({ page, users }, testInfo) => { // eslint-disable-next-line playwright/no-skipped-test test.skip(!IS_STRIPE_ENABLED, "It should only run if Stripe is installed"); + // eslint-disable-next-line playwright/no-skipped-test test.skip(IS_SELF_HOSTED, "It shouldn't run on self hosted"); const user = await users.create(); diff --git a/apps/web/playwright/dynamic-booking-pages.e2e.ts b/apps/web/playwright/dynamic-booking-pages.e2e.ts index 9f101760fa..095b64bfd3 100644 --- a/apps/web/playwright/dynamic-booking-pages.e2e.ts +++ b/apps/web/playwright/dynamic-booking-pages.e2e.ts @@ -11,6 +11,7 @@ test.afterEach(({ users }) => users.deleteAll()); // Due to some reason for Dynamic booking cancellation, daily video api_key is not set which causes cancellation to fail. // This test is skipped until the issue is resolved in GH actions. +// eslint-disable-next-line playwright/no-skipped-test test.skip("dynamic booking", async ({ page, users }) => { const pro = await users.create(); await pro.login(); diff --git a/apps/web/playwright/event-types.e2e.ts b/apps/web/playwright/event-types.e2e.ts index e2e5b1abca..c6f3f7b2b0 100644 --- a/apps/web/playwright/event-types.e2e.ts +++ b/apps/web/playwright/event-types.e2e.ts @@ -69,7 +69,7 @@ test.describe("Event Types tests", () => { '[data-testid="event-types"] a[href^="/event-types/"] >> nth=0' ); const href = await firstElement.getAttribute("href"); - if (!href) throw new Error("No href found for event type"); + expect(href).toBeTruthy(); const [eventTypeId] = new URL(WEBAPP_URL + href).pathname.split("/").reverse(); const firstTitle = await page.locator(`[data-testid=event-type-title-${eventTypeId}]`).innerText(); const firstFullSlug = await page.locator(`[data-testid=event-type-slug-${eventTypeId}]`).innerText(); diff --git a/apps/web/playwright/fixtures/bookings.ts b/apps/web/playwright/fixtures/bookings.ts index 900dece2fc..bdb5c8c20a 100644 --- a/apps/web/playwright/fixtures/bookings.ts +++ b/apps/web/playwright/fixtures/bookings.ts @@ -58,7 +58,7 @@ export const createBookingsFixture = (page: Page) => { status, }, }); - const bookingFixture = createBookingFixture(booking, store.page!); + const bookingFixture = createBookingFixture(booking, store.page); store.bookings.push(bookingFixture); return bookingFixture; }, @@ -80,7 +80,7 @@ const createBookingFixture = (booking: Booking, page: Page) => { return { id: store.booking.id, uid: store.booking.uid, - self: async () => (await prisma.booking.findUnique({ where: { id: store.booking.id } }))!, - delete: async () => (await prisma.booking.delete({ where: { id: store.booking.id } }))!, + self: async () => await prisma.booking.findUnique({ where: { id: store.booking.id } }), + delete: async () => await prisma.booking.delete({ where: { id: store.booking.id } }), }; }; diff --git a/apps/web/playwright/fixtures/payments.ts b/apps/web/playwright/fixtures/payments.ts index 19a634713f..7d85e38582 100644 --- a/apps/web/playwright/fixtures/payments.ts +++ b/apps/web/playwright/fixtures/payments.ts @@ -36,7 +36,7 @@ export const createPaymentsFixture = (page: Page) => { }, }, }); - const paymentFixture = createPaymentFixture(payment, store.page!); + const paymentFixture = createPaymentFixture(payment, store.page); store.payments.push(paymentFixture); return paymentFixture; }, @@ -57,7 +57,7 @@ const createPaymentFixture = (payment: Payment, page: Page) => { // self is a reflective method that return the Prisma object that references this fixture. return { id: store.payment.id, - self: async () => (await prisma.payment.findUnique({ where: { id: store.payment.id } }))!, - delete: async () => (await prisma.payment.delete({ where: { id: store.payment.id } }))!, + self: async () => await prisma.payment.findUnique({ where: { id: store.payment.id } }), + delete: async () => await prisma.payment.delete({ where: { id: store.payment.id } }), }; }; diff --git a/apps/web/playwright/fixtures/users.ts b/apps/web/playwright/fixtures/users.ts index 1b04e4fd96..4b10d76f81 100644 --- a/apps/web/playwright/fixtures/users.ts +++ b/apps/web/playwright/fixtures/users.ts @@ -233,7 +233,7 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => { }, }); } - const userFixture = createUserFixture(user, store.page!); + const userFixture = createUserFixture(user, store.page); store.users.push(userFixture); return userFixture; }, @@ -261,6 +261,7 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => { // self is a reflective method that return the Prisma object that references this fixture. const self = async () => + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion (await prisma.user.findUnique({ where: { id: store.user.id }, include: { eventTypes: true } }))!; return { id: user.id, @@ -277,7 +278,7 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => { debug: async (message: string | Record) => { await prisma.user.update({ where: { id: store.user.id }, data: { metadata: { debug: message } } }); }, - delete: async () => (await prisma.user.delete({ where: { id: store.user.id } }))!, + delete: async () => await prisma.user.delete({ where: { id: store.user.id } }), }; }; diff --git a/apps/web/playwright/integrations-stripe.e2e.ts b/apps/web/playwright/integrations-stripe.e2e.ts index cc81109d86..fcd9cb013d 100644 --- a/apps/web/playwright/integrations-stripe.e2e.ts +++ b/apps/web/playwright/integrations-stripe.e2e.ts @@ -38,12 +38,12 @@ test.describe("Stripe integration", () => { test("Can book a paid booking", async ({ page, users }) => { const user = await users.create(); - const eventType = user.eventTypes.find((e) => e.slug === "paid")!; + const eventType = user.eventTypes.find((e) => e.slug === "paid"); await user.login(); await page.goto("/apps/installed"); await user.getPaymentCredential(); - await page.goto(`${user.username}/${eventType.slug}`); + await page.goto(`${user.username}/${eventType?.slug}`); await selectFirstAvailableTimeSlotNextMonth(page); // --- fill form await page.fill('[name="name"]', "Stripe Stripeson"); diff --git a/apps/web/playwright/integrations.e2e.ts b/apps/web/playwright/integrations.e2e.ts index 0e8a6e90ea..5aea5a7f20 100644 --- a/apps/web/playwright/integrations.e2e.ts +++ b/apps/web/playwright/integrations.e2e.ts @@ -1,5 +1,6 @@ import type { Page, Route } from "@playwright/test"; import { expect } from "@playwright/test"; +import type { DefaultBodyType } from "msw"; import { rest } from "msw"; import { setupServer } from "msw/node"; import { v4 as uuidv4 } from "uuid"; @@ -42,7 +43,7 @@ const addOauthBasedIntegration = async function ({ // eslint-disable-next-line @typescript-eslint/no-explicit-any verify: (config: { requestHeaders: any; params: URLSearchParams; code: string }) => { status: number; - body: any; + body: DefaultBodyType; }; }; }) { diff --git a/apps/web/playwright/lib/teardown.ts b/apps/web/playwright/lib/teardown.ts index 0bcbb1a81c..413f6c922c 100644 --- a/apps/web/playwright/lib/teardown.ts +++ b/apps/web/playwright/lib/teardown.ts @@ -24,11 +24,11 @@ export const deleteAllBookingsByEmail = async ( }); export const deleteEventTypeByTitle = async (title: string) => { - const event = (await prisma.eventType.findFirst({ + const event = await prisma.eventType.findFirst({ select: { id: true }, where: { title: title }, - }))!; - await prisma.eventType.delete({ where: { id: event.id } }); + }); + await prisma.eventType.delete({ where: { id: event?.id } }); }; export const deleteAllWebhooksByEmail = async (email: string) => { diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts index ba8049f6f0..b292c9d35a 100644 --- a/apps/web/playwright/lib/testUtils.ts +++ b/apps/web/playwright/lib/testUtils.ts @@ -46,6 +46,7 @@ export function createHttpServer(opts: { requestHandler?: RequestHandler } = {}) // listen on random port server.listen(0); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const port: number = (server.address() as any).port; const url = `http://localhost:${port}`; return { diff --git a/apps/web/playwright/manage-booking-questions.e2e.ts b/apps/web/playwright/manage-booking-questions.e2e.ts index db70278def..4dae1c60b0 100644 --- a/apps/web/playwright/manage-booking-questions.e2e.ts +++ b/apps/web/playwright/manage-booking-questions.e2e.ts @@ -65,7 +65,7 @@ test.describe("Manage Booking Questions", () => { }, }); - const teamId = team?.id ?? 0; + const teamId = team?.id; const webhookReceiver = await addWebhook(undefined, teamId); await test.step("Go to First Team Event", async () => { @@ -86,7 +86,8 @@ async function runTestStepsCommonForTeamAndUserEventType( webhookReceiver: { port: number; close: () => import("http").Server; - requestList: (import("http").IncomingMessage & { body?: unknown })[]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + requestList: (import("http").IncomingMessage & { body?: any })[]; url: string; }, bookerVariant: BookerVariants @@ -175,7 +176,7 @@ async function runTestStepsCommonForTeamAndUserEventType( const [request] = webhookReceiver.requestList; - const payload = (request.body as any).payload as any; + const payload = request.body.payload; expect(payload.responses).toMatchObject({ email: { @@ -212,7 +213,9 @@ async function runTestStepsCommonForTeamAndUserEventType( await test.step("Do a reschedule and notice that we can't book without giving a value for rescheduleReason", async () => { const page = previewTabPage; - await rescheduleFromTheLinkOnPage({ page, bookerVariant }); + await rescheduleFromTheLinkOnPage({ page }); + // eslint-disable-next-line playwright/no-page-pause + await page.pause(); await expectErrorToBeThereFor({ page, name: "rescheduleReason" }); }); } @@ -368,7 +371,7 @@ async function rescheduleFromTheLinkOnPage({ bookerVariant, }: { page: Page; - bookerVariant: BookerVariants; + bookerVariant?: BookerVariants; }) { await page.locator('[data-testid="reschedule-link"]').click(); await page.waitForLoadState(); diff --git a/apps/web/playwright/onboarding.e2e.ts b/apps/web/playwright/onboarding.e2e.ts index 06c3fa4a2f..a36cc855a4 100644 --- a/apps/web/playwright/onboarding.e2e.ts +++ b/apps/web/playwright/onboarding.e2e.ts @@ -76,9 +76,7 @@ test.describe("Onboarding", () => { const userComplete = await user.self(); - const userCompleteBio = userComplete.bio ? userComplete.bio : ""; - - expect(userCompleteBio.replace("


", "").length).toBe(0); + expect(userComplete.bio?.replace("


", "").length).toBe(0); }); }); }); diff --git a/apps/web/playwright/reschedule.e2e.ts b/apps/web/playwright/reschedule.e2e.ts index ee2d9bb840..b67821b1ab 100644 --- a/apps/web/playwright/reschedule.e2e.ts +++ b/apps/web/playwright/reschedule.e2e.ts @@ -39,9 +39,9 @@ testBothBookers.describe("Reschedule Tests", async () => { const updatedBooking = await booking.self(); - expect(updatedBooking.rescheduled).toBe(true); - expect(updatedBooking.cancellationReason).toBe("I can't longer have it"); - expect(updatedBooking.status).toBe(BookingStatus.CANCELLED); + expect(updatedBooking?.rescheduled).toBe(true); + expect(updatedBooking?.cancellationReason).toBe("I can't longer have it"); + expect(updatedBooking?.status).toBe(BookingStatus.CANCELLED); await booking.delete(); }); diff --git a/apps/web/playwright/webhook.e2e.ts b/apps/web/playwright/webhook.e2e.ts index a0ed6e53c3..a75a1fc64f 100644 --- a/apps/web/playwright/webhook.e2e.ts +++ b/apps/web/playwright/webhook.e2e.ts @@ -14,7 +14,7 @@ test.describe("BOOKING_CREATED", async () => { test("add webhook & test that creating an event triggers a webhook call", async ({ page, users, - }, testInfo) => { + }, _testInfo) => { const webhookReceiver = createHttpServer(); const user = await users.create(); const [eventType] = user.eventTypes; @@ -51,7 +51,8 @@ test.describe("BOOKING_CREATED", async () => { }); const [request] = webhookReceiver.requestList; - const body = request.body as any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const body: any = request.body; // remove dynamic properties that differs depending on where you run the tests const dynamic = "[redacted/dynamic]"; @@ -305,6 +306,7 @@ test.describe("BOOKING_REQUESTED", async () => { expect(webhookReceiver.requestList.length).toBe(1); }); const [request] = webhookReceiver.requestList; + // eslint-disable-next-line @typescript-eslint/no-explicit-any const body = request.body as any; // remove dynamic properties that differs depending on where you run the tests diff --git a/apps/web/scripts/ts-check-changed-files.ts b/apps/web/scripts/ts-check-changed-files.ts index ec924d4c9e..5cbbef9cf0 100644 --- a/apps/web/scripts/ts-check-changed-files.ts +++ b/apps/web/scripts/ts-check-changed-files.ts @@ -1,5 +1,9 @@ import { execSync } from "child_process"; +type Err = { + stdout: string; +}; + const diff = execSync(`git diff --name-only origin/main HEAD`).toString(); const files = diff @@ -18,7 +22,7 @@ try { console.log("😻 No errors!"); } catch (_err) { - const err = _err as any; + const err = _err as Err; const output = err.stdout.toString() as string; diff --git a/apps/web/test/lib/getSchedule.test.ts b/apps/web/test/lib/getSchedule.test.ts index 9b45d7dbf0..906b05b542 100644 --- a/apps/web/test/lib/getSchedule.test.ts +++ b/apps/web/test/lib/getSchedule.test.ts @@ -492,6 +492,7 @@ describe("getSchedule", () => { }); // FIXME: Fix minimumBookingNotice is respected test + // eslint-disable-next-line playwright/no-skipped-test test.skip("minimumBookingNotice is respected", async () => { vi.useFakeTimers().setSystemTime( (() => { diff --git a/apps/web/test/lib/handleChildrenEventTypes.test.ts b/apps/web/test/lib/handleChildrenEventTypes.test.ts index 95a7ab0aac..35bbf2d688 100644 --- a/apps/web/test/lib/handleChildrenEventTypes.test.ts +++ b/apps/web/test/lib/handleChildrenEventTypes.test.ts @@ -295,16 +295,24 @@ describe("handleChildrenEventTypes", () => { describe("Workflows", () => { it("Links workflows to new and existing assigned members", async () => { - const { schedulingType, id, teamId, locations, timeZone, parentId, userId, ...evType } = - mockFindFirstEventType({ - metadata: { managedEventConfig: {} }, - locations: [], - workflows: [ - { - workflowId: 11, - } as CompleteWorkflowsOnEventTypes, - ], - }); + const { + schedulingType: _schedulingType, + id: _id, + teamId: _teamId, + locations: _locations, + timeZone: _timeZone, + parentId: _parentId, + userId: _userId, + ...evType + } = mockFindFirstEventType({ + metadata: { managedEventConfig: {} }, + locations: [], + workflows: [ + { + workflowId: 11, + } as CompleteWorkflowsOnEventTypes, + ], + }); prismaMock.$transaction.mockResolvedValue([{ id: 2 }]); await updateChildrenEventTypes({ eventTypeId: 1, diff --git a/packages/app-store/_components/DynamicComponent.tsx b/packages/app-store/_components/DynamicComponent.tsx index 6d216e9959..30e00222f8 100644 --- a/packages/app-store/_components/DynamicComponent.tsx +++ b/packages/app-store/_components/DynamicComponent.tsx @@ -1,9 +1,10 @@ -export function DynamicComponent>(props: { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function DynamicComponent>>(props: { componentMap: T; slug: string; wrapperClassName?: string; }) { - const { componentMap, slug, ...rest } = props; + const { componentMap, slug, wrapperClassName, ...rest } = props; const dirName = slug === "stripe" ? "stripepayment" : slug; // There can be apps with no matching component @@ -12,7 +13,7 @@ export function DynamicComponent>(props: { const Component = componentMap[dirName]; return ( -
+
); diff --git a/packages/app-store/applecalendar/api/add.ts b/packages/app-store/applecalendar/api/add.ts index a5e17893fe..321ca75a00 100644 --- a/packages/app-store/applecalendar/api/add.ts +++ b/packages/app-store/applecalendar/api/add.ts @@ -22,7 +22,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const data = { type: "apple_calendar", - key: symmetricEncrypt(JSON.stringify({ username, password }), process.env.CALENDSO_ENCRYPTION_KEY!), + key: symmetricEncrypt( + JSON.stringify({ username, password }), + process.env.CALENDSO_ENCRYPTION_KEY || "" + ), userId: user.id, appId: "apple-calendar", invalid: false, diff --git a/packages/app-store/around/api/_getAdd.ts b/packages/app-store/around/api/_getAdd.ts index 4564ade71b..00d4db0c0d 100644 --- a/packages/app-store/around/api/_getAdd.ts +++ b/packages/app-store/around/api/_getAdd.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; @@ -7,7 +7,7 @@ import getInstalledAppPath from "../../_utils/getInstalledAppPath"; import { checkInstalled, createDefaultInstallation } from "../../_utils/installation"; import appConfig from "../config.json"; -export async function getHandler(req: NextApiRequest, res: NextApiResponse) { +export async function getHandler(req: NextApiRequest) { const session = checkSession(req); const slug = appConfig.slug; const variant = appConfig.variant; diff --git a/packages/app-store/caldavcalendar/api/add.ts b/packages/app-store/caldavcalendar/api/add.ts index 600f0accac..b3e434b334 100644 --- a/packages/app-store/caldavcalendar/api/add.ts +++ b/packages/app-store/caldavcalendar/api/add.ts @@ -24,7 +24,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) type: "caldav_calendar", key: symmetricEncrypt( JSON.stringify({ username, password, url }), - process.env.CALENDSO_ENCRYPTION_KEY! + process.env.CALENDSO_ENCRYPTION_KEY || "" ), userId: user.id, appId: "caldav-calendar", diff --git a/packages/app-store/closecom/lib/CalendarService.ts b/packages/app-store/closecom/lib/CalendarService.ts index f707b46207..854eb3853c 100644 --- a/packages/app-store/closecom/lib/CalendarService.ts +++ b/packages/app-store/closecom/lib/CalendarService.ts @@ -113,6 +113,7 @@ export default class CloseComCalendarService implements Calendar { }); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any async updateEvent(uid: string, event: CalendarEvent): Promise { return await this.closeComUpdateCustomActivity(uid, event); } @@ -122,14 +123,14 @@ export default class CloseComCalendarService implements Calendar { } async getAvailability( - dateFrom: string, - dateTo: string, - selectedCalendars: IntegrationCalendar[] + _dateFrom: string, + _dateTo: string, + _selectedCalendars: IntegrationCalendar[] ): Promise { return Promise.resolve([]); } - async listCalendars(event?: CalendarEvent): Promise { + async listCalendars(_event?: CalendarEvent): Promise { return Promise.resolve([]); } } diff --git a/packages/app-store/closecom/test/lib/CalendarService.test.ts b/packages/app-store/closecom/test/lib/CalendarService.test.ts index da7c598c20..9425d9f9b0 100644 --- a/packages/app-store/closecom/test/lib/CalendarService.test.ts +++ b/packages/app-store/closecom/test/lib/CalendarService.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { expect, vi, afterEach, test } from "vitest"; import CloseCom from "@calcom/lib/CloseCom"; diff --git a/packages/app-store/dailyvideo/lib/VideoApiAdapter.ts b/packages/app-store/dailyvideo/lib/VideoApiAdapter.ts index e0a988f5e2..1ea83b6437 100644 --- a/packages/app-store/dailyvideo/lib/VideoApiAdapter.ts +++ b/packages/app-store/dailyvideo/lib/VideoApiAdapter.ts @@ -78,7 +78,7 @@ export const fetcher = async (endpoint: string, init?: RequestInit | undefined) }).then(handleErrorsJson); }; -function postToDailyAPI(endpoint: string, body: Record) { +function postToDailyAPI(endpoint: string, body: Record) { return fetcher(endpoint, { method: "POST", body: JSON.stringify(body), diff --git a/packages/app-store/exchange2013calendar/api/add.ts b/packages/app-store/exchange2013calendar/api/add.ts index 81964a8b6c..52c325e14b 100644 --- a/packages/app-store/exchange2013calendar/api/add.ts +++ b/packages/app-store/exchange2013calendar/api/add.ts @@ -31,7 +31,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { const data = { type: "exchange2013_calendar", - key: symmetricEncrypt(JSON.stringify(body), process.env.CALENDSO_ENCRYPTION_KEY!), + key: symmetricEncrypt(JSON.stringify(body), process.env.CALENDSO_ENCRYPTION_KEY || ""), userId: user.id, appId: "exchange2013-calendar", invalid: false, diff --git a/packages/app-store/exchange2016calendar/api/add.ts b/packages/app-store/exchange2016calendar/api/add.ts index f1ea1d9b79..683c9689c2 100644 --- a/packages/app-store/exchange2016calendar/api/add.ts +++ b/packages/app-store/exchange2016calendar/api/add.ts @@ -31,7 +31,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { const data = { type: "exchange2016_calendar", - key: symmetricEncrypt(JSON.stringify(body), process.env.CALENDSO_ENCRYPTION_KEY!), + key: symmetricEncrypt(JSON.stringify(body), process.env.CALENDSO_ENCRYPTION_KEY || ""), userId: user.id, appId: "exchange2016-calendar", invalid: false, diff --git a/packages/app-store/exchange2016calendar/lib/CalendarService.ts b/packages/app-store/exchange2016calendar/lib/CalendarService.ts index 3b96e59c85..3538fee521 100644 --- a/packages/app-store/exchange2016calendar/lib/CalendarService.ts +++ b/packages/app-store/exchange2016calendar/lib/CalendarService.ts @@ -97,6 +97,7 @@ export default class ExchangeCalendarService implements Calendar { } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any async updateEvent(uid: string, event: CalendarEvent): Promise { try { const appointment = await Appointment.Bind( diff --git a/packages/app-store/exchangecalendar/pages/setup/index.tsx b/packages/app-store/exchangecalendar/pages/setup/index.tsx index 128dbd73bb..32fd9ab9e7 100644 --- a/packages/app-store/exchangecalendar/pages/setup/index.tsx +++ b/packages/app-store/exchangecalendar/pages/setup/index.tsx @@ -121,8 +121,10 @@ export default function ExchangeSetup() { options={authenticationMethods} defaultValue={authenticationMethods[0]} onChange={async (authentication) => { - onChange(authentication?.value); - form.setValue("authenticationMethod", authentication!.value); + if (authentication) { + onChange(authentication.value); + form.setValue("authenticationMethod", authentication.value); + } }} /> )} @@ -137,7 +139,9 @@ export default function ExchangeSetup() { defaultValue={exchangeVersions[7]} onChange={async (version) => { onChange(version?.value); - form.setValue("exchangeVersion", version!.value); + if (version) { + form.setValue("exchangeVersion", version.value); + } }} /> )} diff --git a/packages/app-store/giphy/components/SearchDialog.tsx b/packages/app-store/giphy/components/SearchDialog.tsx index ed38fee5da..c2bf054c34 100644 --- a/packages/app-store/giphy/components/SearchDialog.tsx +++ b/packages/app-store/giphy/components/SearchDialog.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import type { SVGComponent } from "@calcom/types/SVGComponent"; import { Alert, Button, Dialog, DialogClose, DialogContent, DialogFooter, Input } from "@calcom/ui"; import { Link, Search } from "@calcom/ui/components/icon"; @@ -84,7 +85,7 @@ export const SearchDialog = (props: ISearchDialog) => { return null; }; - const renderTab = (Icon: any, text: string, mode: Mode) => ( + const renderTab = (Icon: SVGComponent, text: string, mode: Mode) => (
{ - const eventAttendees = calEventRaw.attendees.map(({ id, ...rest }) => ({ + const eventAttendees = calEventRaw.attendees.map(({ id: _id, ...rest }) => ({ ...rest, responseStatus: "accepted", })); @@ -175,7 +176,7 @@ export default class GoogleCalendarService implements Calendar { async updateEvent(uid: string, event: CalendarEvent, externalCalendarId: string): Promise { return new Promise(async (resolve, reject) => { const myGoogleAuth = await this.auth.getToken(); - const eventAttendees = event.attendees.map(({ id, ...rest }) => ({ + const eventAttendees = event.attendees.map(({ ...rest }) => ({ ...rest, responseStatus: "accepted", })); @@ -206,9 +207,8 @@ export default class GoogleCalendarService implements Calendar { ? event.destinationCalendar.externalId : event.organizer.email, }, - // eslint-disable-next-line - ...eventAttendees, - ...teamMembers, + ...(eventAttendees as any), + ...(teamMembers as any), ], reminders: { useDefault: true, diff --git a/packages/app-store/hubspot/api/callback.ts b/packages/app-store/hubspot/api/callback.ts index 80414cb736..4b02a07d23 100644 --- a/packages/app-store/hubspot/api/callback.ts +++ b/packages/app-store/hubspot/api/callback.ts @@ -49,6 +49,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await prisma.credential.create({ data: { type: "hubspot_other_calendar", + // eslint-disable-next-line @typescript-eslint/no-explicit-any key: hubspotToken as any, userId: req.session.user.id, appId: "hubspot", diff --git a/packages/app-store/hubspot/lib/CalendarService.ts b/packages/app-store/hubspot/lib/CalendarService.ts index 1ab601d124..b9817c6168 100644 --- a/packages/app-store/hubspot/lib/CalendarService.ts +++ b/packages/app-store/hubspot/lib/CalendarService.ts @@ -1,7 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import * as hubspot from "@hubspot/api-client"; import type { BatchInputPublicAssociation } from "@hubspot/api-client/lib/codegen/crm/associations"; import type { PublicObjectSearchRequest } from "@hubspot/api-client/lib/codegen/crm/contacts"; -import type { SimplePublicObjectInput } from "@hubspot/api-client/lib/codegen/crm/objects/meetings"; +import type { + SimplePublicObject, + SimplePublicObjectInput, +} from "@hubspot/api-client/lib/codegen/crm/objects/meetings"; import { getLocation } from "@calcom/lib/CalEventParser"; import { WEBAPP_URL } from "@calcom/lib/constants"; @@ -23,10 +27,14 @@ import type { HubspotToken } from "../api/callback"; const hubspotClient = new hubspot.Client(); +interface CustomPlublicObjectInput extends SimplePublicObjectInput { + id?: string; +} + export default class HubspotCalendarService implements Calendar { private url = ""; private integrationName = ""; - private auth: Promise<{ getToken: () => Promise }>; + private auth: Promise<{ getToken: () => Promise }>; private log: typeof logger; private client_id = ""; private client_secret = ""; @@ -113,9 +121,9 @@ export default class HubspotCalendarService implements Calendar { return hubspotClient.crm.objects.meetings.basicApi.create(simplePublicObjectInput); }; - private hubspotAssociate = async (meeting: any, contacts: any) => { + private hubspotAssociate = async (meeting: SimplePublicObject, contacts: Array<{ id: string }>) => { const batchInputPublicAssociation: BatchInputPublicAssociation = { - inputs: contacts.map((contact: any) => ({ + inputs: contacts.map((contact: { id: string }) => ({ _from: { id: meeting.id }, to: { id: contact.id }, type: "meeting_event_to_contact", @@ -197,11 +205,12 @@ export default class HubspotCalendarService implements Calendar { }; }; - async handleMeetingCreation(event: CalendarEvent, contacts: SimplePublicObjectInput[]) { + async handleMeetingCreation(event: CalendarEvent, contacts: CustomPlublicObjectInput[]) { + const contactIds: { id?: string }[] = contacts.map((contact) => ({ id: contact.id })); const meetingEvent = await this.hubspotCreateMeeting(event); if (meetingEvent) { this.log.debug("meeting:creation:ok", { meetingEvent }); - const associatedMeeting = await this.hubspotAssociate(meetingEvent, contacts); + const associatedMeeting = await this.hubspotAssociate(meetingEvent, contactIds as any); if (associatedMeeting) { this.log.debug("association:creation:ok", { associatedMeeting }); return Promise.resolve({ @@ -264,6 +273,7 @@ export default class HubspotCalendarService implements Calendar { return Promise.reject("Something went wrong when searching/creating the attendees in HubSpot"); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any async updateEvent(uid: string, event: CalendarEvent): Promise { const auth = await this.auth; await auth.getToken(); @@ -277,14 +287,14 @@ export default class HubspotCalendarService implements Calendar { } async getAvailability( - dateFrom: string, - dateTo: string, - selectedCalendars: IntegrationCalendar[] + _dateFrom: string, + _dateTo: string, + _selectedCalendars: IntegrationCalendar[] ): Promise { return Promise.resolve([]); } - async listCalendars(event?: CalendarEvent): Promise { + async listCalendars(_event?: CalendarEvent): Promise { return Promise.resolve([]); } } diff --git a/packages/app-store/office365calendar/lib/CalendarService.ts b/packages/app-store/office365calendar/lib/CalendarService.ts index 21fd11a85e..3af981fbc1 100644 --- a/packages/app-store/office365calendar/lib/CalendarService.ts +++ b/packages/app-store/office365calendar/lib/CalendarService.ts @@ -1,4 +1,5 @@ import type { Calendar as OfficeCalendar, User } from "@microsoft/microsoft-graph-types-beta"; +import type { DefaultBodyType } from "msw"; import { z } from "zod"; import dayjs from "@calcom/dayjs"; @@ -32,12 +33,18 @@ interface ISettledResponse { "Retry-After": string; "Content-Type": string; }; - body: Record; + body: Record; } interface IBatchResponse { responses: ISettledResponse[]; } +interface BodyValue { + showAs: string; + end: { dateTime: string }; + evt: { showAs: string }; + start: { dateTime: string }; +} const refreshTokenResponseSchema = z.object({ access_token: z.string(), @@ -83,7 +90,7 @@ export default class Office365CalendarService implements Calendar { } } - async updateEvent(uid: string, event: CalendarEvent): Promise { + async updateEvent(uid: string, event: CalendarEvent): Promise { try { const response = await this.fetcher(`/me/calendar/events/${uid}`, { method: "PATCH", @@ -326,7 +333,7 @@ export default class Office365CalendarService implements Calendar { alreadySuccess.push(response); } else { const nextLinkUrl = response.body["@odata.nextLink"] - ? response.body["@odata.nextLink"].replace(this.apiGraphUrl, "") + ? String(response.body["@odata.nextLink"]).replace(this.apiGraphUrl, "") : ""; if (nextLinkUrl) { // Saving link for later use @@ -406,16 +413,12 @@ export default class Office365CalendarService implements Calendar { }; private apiGraphBatchCall = async (requests: IRequest[]): Promise => { - try { - const response = await this.fetcher(`/$batch`, { - method: "POST", - body: JSON.stringify({ requests }), - }); + const response = await this.fetcher(`/$batch`, { + method: "POST", + body: JSON.stringify({ requests }), + }); - return response; - } catch (error: any) { - throw new Error(error); - } + return response; }; private handleTextJsonResponseWithHtmlInBody = (response: string): IBatchResponse => { @@ -443,7 +446,7 @@ export default class Office365CalendarService implements Calendar { private processBusyTimes = (responses: ISettledResponse[]) => { return responses.reduce( - (acc: BufferedBusyTime[], subResponse: { body: { value?: any[]; error?: any[] } }) => { + (acc: BufferedBusyTime[], subResponse: { body: { value?: BodyValue[]; error?: Error[] } }) => { if (!subResponse.body?.value) return acc; return acc.concat( subResponse.body.value diff --git a/packages/app-store/ping/api/_getAdd.ts b/packages/app-store/ping/api/_getAdd.ts index 3647aa85e0..a811671bf3 100644 --- a/packages/app-store/ping/api/_getAdd.ts +++ b/packages/app-store/ping/api/_getAdd.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; @@ -7,7 +7,7 @@ import getInstalledAppPath from "../../_utils/getInstalledAppPath"; import { checkInstalled, createDefaultInstallation } from "../../_utils/installation"; import appConfig from "../config.json"; -export async function getHandler(req: NextApiRequest, res: NextApiResponse) { +export async function getHandler(req: NextApiRequest) { const session = checkSession(req); const slug = appConfig.slug; const appType = appConfig.type; diff --git a/packages/app-store/riverside/api/_getAdd.ts b/packages/app-store/riverside/api/_getAdd.ts index 6bbd032cb9..41d7903648 100644 --- a/packages/app-store/riverside/api/_getAdd.ts +++ b/packages/app-store/riverside/api/_getAdd.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; @@ -7,7 +7,7 @@ import getInstalledAppPath from "../../_utils/getInstalledAppPath"; import { checkInstalled, createDefaultInstallation } from "../../_utils/installation"; import appConfig from "../config.json"; -export async function getHandler(req: NextApiRequest, res: NextApiResponse) { +export async function getHandler(req: NextApiRequest) { const session = checkSession(req); const slug = appConfig.slug; const appType = appConfig.type; diff --git a/packages/app-store/salesforce/api/callback.ts b/packages/app-store/salesforce/api/callback.ts index 2eadc25f21..51aed420ea 100644 --- a/packages/app-store/salesforce/api/callback.ts +++ b/packages/app-store/salesforce/api/callback.ts @@ -41,6 +41,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await prisma.credential.create({ data: { type: "salesforce_other_calendar", + // eslint-disable-next-line @typescript-eslint/no-explicit-any key: salesforceTokenInfo as any, userId: req.session.user.id, appId: "salesforce", diff --git a/packages/app-store/salesforce/lib/CalendarService.ts b/packages/app-store/salesforce/lib/CalendarService.ts index 93ce6762f0..4ab6c516b6 100644 --- a/packages/app-store/salesforce/lib/CalendarService.ts +++ b/packages/app-store/salesforce/lib/CalendarService.ts @@ -265,11 +265,11 @@ export default class SalesforceCalendarService implements Calendar { } } - async getAvailability(dateFrom: string, dateTo: string, selectedCalendars: IntegrationCalendar[]) { + async getAvailability(_dateFrom: string, _dateTo: string, _selectedCalendars: IntegrationCalendar[]) { return Promise.resolve([]); } - async listCalendars(event?: CalendarEvent) { + async listCalendars(_event?: CalendarEvent) { return Promise.resolve([]); } } diff --git a/packages/app-store/sendgrid/lib/CalendarService.ts b/packages/app-store/sendgrid/lib/CalendarService.ts index de1bd8cc02..c1d1443f09 100644 --- a/packages/app-store/sendgrid/lib/CalendarService.ts +++ b/packages/app-store/sendgrid/lib/CalendarService.ts @@ -74,27 +74,28 @@ export default class CloseComCalendarService implements Calendar { }); } - async updateEvent(uid: string, event: CalendarEvent): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async updateEvent(_uid: string, _event: CalendarEvent): Promise { // Unless we want to be able to support modifying an event to add more attendees // to have them created in Sendgrid, ignoring this use case for now return Promise.resolve(); } - async deleteEvent(uid: string): Promise { + async deleteEvent(_uid: string): Promise { // Unless we want to delete the contact in Sendgrid once the event // is deleted just ignoring this use case for now return Promise.resolve(); } async getAvailability( - dateFrom: string, - dateTo: string, - selectedCalendars: IntegrationCalendar[] + _dateFrom: string, + _dateTo: string, + _selectedCalendars: IntegrationCalendar[] ): Promise { return Promise.resolve([]); } - async listCalendars(event?: CalendarEvent): Promise { + async listCalendars(_event?: CalendarEvent): Promise { return Promise.resolve([]); } } diff --git a/packages/app-store/stripepayment/api/callback.ts b/packages/app-store/stripepayment/api/callback.ts index c89abc239e..7386d6c50e 100644 --- a/packages/app-store/stripepayment/api/callback.ts +++ b/packages/app-store/stripepayment/api/callback.ts @@ -33,7 +33,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const response = await stripe.oauth.token({ grant_type: "authorization_code", - code: code!.toString(), + code: code?.toString(), }); const data: StripeData = { ...response, default_currency: "" }; diff --git a/packages/app-store/stripepayment/lib/PaymentService.ts b/packages/app-store/stripepayment/lib/PaymentService.ts index 386e5ef028..547ce428fb 100644 --- a/packages/app-store/stripepayment/lib/PaymentService.ts +++ b/packages/app-store/stripepayment/lib/PaymentService.ts @@ -200,7 +200,7 @@ export class PaymentService implements IAbstractPaymentService { } } - async chargeCard(payment: Payment): Promise { + async chargeCard(payment: Payment, _bookingId?: Booking["id"]): Promise { try { const stripeAppKeys = await prisma?.app.findFirst({ select: { diff --git a/packages/app-store/stripepayment/lib/client/getStripe.ts b/packages/app-store/stripepayment/lib/client/getStripe.ts index b618bf5825..d3ac8151b3 100644 --- a/packages/app-store/stripepayment/lib/client/getStripe.ts +++ b/packages/app-store/stripepayment/lib/client/getStripe.ts @@ -3,7 +3,7 @@ import { loadStripe } from "@stripe/stripe-js/pure"; export type Maybe = T | undefined | null; -const stripePublicKey = process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY!; +const stripePublicKey = process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY || ""; let stripePromise: Promise; /** diff --git a/packages/app-store/stripepayment/lib/server.ts b/packages/app-store/stripepayment/lib/server.ts index 23a4555a61..1a05085e1b 100644 --- a/packages/app-store/stripepayment/lib/server.ts +++ b/packages/app-store/stripepayment/lib/server.ts @@ -28,7 +28,7 @@ export const stripeDataSchema = stripeOAuthTokenSchema.extend({ export type StripeData = z.infer; /** Figure out a way to get this from the DB without too much wreckage. */ -const stripePrivateKey = process.env.STRIPE_PRIVATE_KEY!; +const stripePrivateKey = process.env.STRIPE_PRIVATE_KEY || ""; const stripe = new Stripe(stripePrivateKey, { apiVersion: "2020-08-27", }); diff --git a/packages/app-store/vital/api/webhook.ts b/packages/app-store/vital/api/webhook.ts index 11406dd196..4602f650b4 100644 --- a/packages/app-store/vital/api/webhook.ts +++ b/packages/app-store/vital/api/webhook.ts @@ -13,6 +13,13 @@ import { BookingStatus } from "@calcom/prisma/enums"; import { Reschedule } from "../lib"; import { initVitalClient, vitalEnv } from "../lib/client"; +interface EventType { + event_type: string; + data: { + [key: string]: string | number; + }; +} + /* @Note: not being used anymore but left as example const getOuraSleepScore = async (user_id: string, bedtime_start: Date) => { const vitalClient = await initVitalClient(); @@ -47,11 +54,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const payload = JSON.stringify(req.body); - const event: any = vitalClient.Webhooks.constructWebhookEvent( + const event: EventType = vitalClient.Webhooks.constructWebhookEvent( payload, req.headers as Record, vitalEnv.webhook_secret as string - ); + ) as EventType; if (event.event_type == "daily.data.sleep.created") { // Carry out logic here to determine what to do if sleep is less @@ -97,7 +104,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) res.status(500).json({ message: "Selected param not available" }); return; } - const totalHoursSleep = event.data[parameterFilter] / 60 / 60; + const totalHoursSleep = Number(event.data[parameterFilter]) / 60 / 60; if (minimumSleepTime > 0 && parameterFilter !== "" && totalHoursSleep <= minimumSleepTime) { // Trigger reschedule diff --git a/packages/app-store/vital/components/AppConfiguration.tsx b/packages/app-store/vital/components/AppConfiguration.tsx index 19a73b85fd..fde7cdd3b0 100644 --- a/packages/app-store/vital/components/AppConfiguration.tsx +++ b/packages/app-store/vital/components/AppConfiguration.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Button, Select, showToast } from "@calcom/ui"; @@ -37,16 +37,14 @@ const AppConfiguration = (props: IAppConfigurationProps) => { const { t } = useTranslation(); const [credentialId] = props.credentialIds; - const options = [ - { - label: t("vital_app_total_label", { ns: "vital" }), - value: "total", - }, - { - label: t("vital_app_duration_label", { ns: "vital" }), - value: "duration", - }, - ]; + const options = useMemo( + () => [ + { label: t("vital_app_total_label", { ns: "vital" }), value: "total" }, + { label: t("vital_app_duration_label", { ns: "vital" }), value: "duration" }, + ], + [t] + ); + const [selectedParam, setSelectedParam] = useState<{ label: string; value: string }>(options[0]); const [touchedForm, setTouchedForm] = useState(false); const defaultSleepValue = 0; @@ -72,7 +70,9 @@ const AppConfiguration = (props: IAppConfigurationProps) => { setConnected(vitalSettings.connected); } if (vitalSettings.sleepValue && vitalSettings.parameter) { - const selectedParam = options.find((item) => item.value === vitalSettings.parameter); + const selectedParam = options.find( + (item: { value: string }) => item.value === vitalSettings.parameter + ); if (selectedParam) { setSelectedParam(selectedParam); } @@ -81,6 +81,7 @@ const AppConfiguration = (props: IAppConfigurationProps) => { } } getVitalsConfig(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (!credentialId) { diff --git a/packages/app-store/whereby/api/_getAdd.ts b/packages/app-store/whereby/api/_getAdd.ts index bdd1415324..677fa19ec0 100644 --- a/packages/app-store/whereby/api/_getAdd.ts +++ b/packages/app-store/whereby/api/_getAdd.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; @@ -7,7 +7,7 @@ import getInstalledAppPath from "../../_utils/getInstalledAppPath"; import { checkInstalled, createDefaultInstallation } from "../../_utils/installation"; import appConfig from "../config.json"; -export async function getHandler(req: NextApiRequest, res: NextApiResponse) { +export async function getHandler(req: NextApiRequest) { const session = checkSession(req); const slug = appConfig.slug; const appType = appConfig.type; diff --git a/packages/app-store/wipemycalother/api/wipe.ts b/packages/app-store/wipemycalother/api/wipe.ts index 005841c4b2..9a200c3914 100644 --- a/packages/app-store/wipemycalother/api/wipe.ts +++ b/packages/app-store/wipemycalother/api/wipe.ts @@ -63,9 +63,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { return res.status(200).json({ success: true }); }; -function validate( - handler: (req: NextApiRequest, res: NextApiResponse) => Promise -) { +function validate(handler: (req: NextApiRequest, res: NextApiResponse) => Promise) { return async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === "POST") { try { diff --git a/packages/app-store/zapier/pages/setup/index.tsx b/packages/app-store/zapier/pages/setup/index.tsx index 5a6b455d56..34797e1c33 100644 --- a/packages/app-store/zapier/pages/setup/index.tsx +++ b/packages/app-store/zapier/pages/setup/index.tsx @@ -9,7 +9,7 @@ import { Button, showToast, Tooltip } from "@calcom/ui"; import { Clipboard } from "@calcom/ui/components/icon"; export interface IZapierSetupProps { - inviteLink: string; + inviteLink?: string; } const ZAPIER = "zapier"; diff --git a/packages/app-store/zohocrm/api/callback.ts b/packages/app-store/zohocrm/api/callback.ts index c3d1eb7e23..a045455280 100644 --- a/packages/app-store/zohocrm/api/callback.ts +++ b/packages/app-store/zohocrm/api/callback.ts @@ -54,6 +54,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await prisma.credential.create({ data: { type: "zohocrm_other_calendar", + // eslint-disable-next-line @typescript-eslint/no-explicit-any key: zohoCrmTokenInfo.data as any, userId: req.session.user.id, appId: "zohocrm", diff --git a/packages/core/CalendarManager.ts b/packages/core/CalendarManager.ts index 592ff2cb5d..47e8c265ec 100644 --- a/packages/core/CalendarManager.ts +++ b/packages/core/CalendarManager.ts @@ -57,7 +57,7 @@ export const getConnectedCalendars = async ( } const cals = await calendar.listCalendars(); const calendars = sortBy( - cals.map((cal) => { + cals.map((cal: IntegrationCalendar) => { if (cal.externalId === destinationCalendarExternalId) destinationCalendar = cal; return { ...cal, @@ -164,7 +164,7 @@ export const getCachedResults = async ( "eventBusyDatesEnd" ); - return eventBusyDates.map((a) => ({ ...a, source: `${appId}` })); + return eventBusyDates.map((a: object) => ({ ...a, source: `${appId}` })); }); const awaitedResults = await Promise.all(results); performance.mark("getBusyCalendarTimesEnd"); @@ -173,7 +173,8 @@ export const getCachedResults = async ( "getBusyCalendarTimesStart", "getBusyCalendarTimesEnd" ); - return awaitedResults; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return awaitedResults as any; }; /** @@ -273,7 +274,7 @@ export const createEvent = async ( // TODO: Surface success/error messages coming from apps to improve end user visibility const creationResult = calendar - ? await calendar.createEvent(calEvent).catch(async (error) => { + ? await calendar.createEvent(calEvent).catch(async (error: { code: number; calError: string }) => { success = false; /** * There is a time when selectedCalendar externalId doesn't match witch certain credential @@ -321,15 +322,15 @@ export const updateEvent = async ( if (bookingRefUid === "") { log.error("updateEvent failed", "bookingRefUid is empty", calEvent, credential); } - const updatedResult = + const updatedResult: NewCalendarEventType | NewCalendarEventType[] | undefined = calendar && bookingRefUid ? await calendar .updateEvent(bookingRefUid, calEvent, externalCalendarId) - .then((event) => { + .then((event: NewCalendarEventType | NewCalendarEventType[]) => { success = true; return event; }) - .catch(async (e) => { + .catch(async (e: { calError: string }) => { // @TODO: This code will be off till we can investigate an error with it // @see https://github.com/calcom/cal.com/issues/3949 // await sendBrokenIntegrationEmail(calEvent, "calendar"); diff --git a/packages/embeds/embed-react/tsconfig.json b/packages/embeds/embed-react/tsconfig.json index 01a0b645bf..4a82423a1e 100644 --- a/packages/embeds/embed-react/tsconfig.json +++ b/packages/embeds/embed-react/tsconfig.json @@ -13,7 +13,7 @@ "@calcom/embed-snippet": ["../embed-snippet/src"] } }, - "include": ["**/*.ts","**/*.tsx", "env.d.ts"], + "include": ["**/*.ts", "**/*.tsx", "env.d.ts"], // Exclude "test" because that has `api.test.ts` which imports @calcom/embed-react which needs it to be built using this tsconfig.json first. Excluding it here prevents type-check from validating test folder "exclude": ["node_modules", "test"] } diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index c03eb63af4..617d6e4812 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -14,7 +14,7 @@ import type { LocationObject } from "@calcom/app-store/locations"; import { getLocationValueForDB } from "@calcom/app-store/locations"; import { MeetLocationType } from "@calcom/app-store/locations"; import type { EventTypeAppsList } from "@calcom/app-store/utils"; -import { getAppFromSlug, getEventTypeAppData } from "@calcom/app-store/utils"; +import { getAppFromSlug } from "@calcom/app-store/utils"; import { cancelScheduledJobs, scheduleTrigger } from "@calcom/app-store/zapier/lib/nodeScheduler"; import EventManager from "@calcom/core/EventManager"; import { getEventName } from "@calcom/core/event"; @@ -68,7 +68,13 @@ import { userMetadata as userMetadataSchema, } from "@calcom/prisma/zod-utils"; import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime"; -import type { AdditionalInformation, AppsStatus, CalendarEvent, Person } from "@calcom/types/Calendar"; +import type { + AdditionalInformation, + AppsStatus, + CalendarEvent, + IntervalLimit, + Person, +} from "@calcom/types/Calendar"; import type { EventResult, PartialReference } from "@calcom/types/EventManager"; import type { WorkingHours, TimeRange as DateOverride } from "@calcom/types/schedule"; @@ -556,7 +562,7 @@ function getBookingData({ function getCustomInputsResponses( reqBody: { - responses?: Record; + responses?: Record; customInputs?: z.infer["customInputs"]; }, eventTypeCustomInputs: Awaited>["customInputs"] @@ -760,10 +766,10 @@ async function handler( ) { const startAsDate = dayjs(reqBody.start).toDate(); if (eventType.bookingLimits) { - await checkBookingLimits(eventType.bookingLimits, startAsDate, eventType.id); + await checkBookingLimits(eventType.bookingLimits as IntervalLimit, startAsDate, eventType.id); } if (eventType.durationLimits) { - await checkDurationLimits(eventType.durationLimits, startAsDate, eventType.id); + await checkDurationLimits(eventType.durationLimits as IntervalLimit, startAsDate, eventType.id); } } @@ -952,7 +958,6 @@ async function handler( }, }); if (bookingSeat) { - bookingSeat = bookingSeat; rescheduleUid = bookingSeat.booking.uid; } originalRescheduledBooking = await getOriginalRescheduledBooking( @@ -1778,7 +1783,7 @@ async function handler( if (booking && booking.id && eventType.seatsPerTimeSlot) { const currentAttendee = booking.attendees.find( (attendee) => attendee.email === req.body.responses.email - )!; + ); // Save description to bookingSeat const uniqueAttendeeId = uuid(); diff --git a/packages/features/eventtypes/components/CheckedTeamSelect.tsx b/packages/features/eventtypes/components/CheckedTeamSelect.tsx index 80bab7eb38..c5e680ae5c 100644 --- a/packages/features/eventtypes/components/CheckedTeamSelect.tsx +++ b/packages/features/eventtypes/components/CheckedTeamSelect.tsx @@ -42,7 +42,9 @@ export const CheckedTeamSelect = ({ className={classNames("mt-3 rounded-md", value.length >= 1 && "border-subtle border")} ref={animationRef}> {value.map((option, index) => ( -
  • +
  • {option.label}

    {isParentLoading}; return ( diff --git a/packages/features/webhooks/components/WebhookForm.tsx b/packages/features/webhooks/components/WebhookForm.tsx index 07071845ed..580a8d21b9 100644 --- a/packages/features/webhooks/components/WebhookForm.tsx +++ b/packages/features/webhooks/components/WebhookForm.tsx @@ -32,8 +32,8 @@ const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2: Record; }; export type CloseComFieldOptions = [string, string, boolean, boolean][]; @@ -13,9 +14,9 @@ export type CloseComLeadCreateResult = { status_id: string; status_label: string; display_name: string; - addresses: { [key: string]: any }[]; + addresses: { [key: string]: string }[]; name: string; - contacts: { [key: string]: any }[]; + contacts: { [key: string]: string }[]; [key: CloseComCustomActivityCustomField]: string; id: string; }; @@ -119,7 +120,7 @@ export type CloseComCustomActivityCreate = { export type typeCloseComCustomActivityGet = { organization_id: string; - contact_id: any; + contact_id: string; date_updated: string; user_name: string; created_by_name: "Bruce Wayne"; @@ -127,7 +128,7 @@ export type typeCloseComCustomActivityGet = { created_by: string; status: string; user_id: string; - users: any[]; + users: string[]; lead_id: string; _type: string; updated_by: string; @@ -141,6 +142,44 @@ type CloseComCustomActivityCustomField = `custom.${T}`; const environmentApiKey = process.env.CLOSECOM_API_KEY || ""; +type CloseComQuery = { + negate?: boolean; + queries?: CloseComQuery[] | CloseComCondition[]; + object_type?: string; + related_object_type?: string; + related_query?: CloseComQuery; + this_object_type?: string; + type?: "object_type" | "has_related" | "and" | "or"; + _fields?: string[]; +}; + +type CloseComCondition = { + condition: { + mode: "full_words"; + type: "text"; + value: string; + }; + field: { + field_name: string; + object_type: string; + type: "regular_field"; + }; + negate: boolean; + type: "field_condition"; +}; + +export type CloseComCustomFieldCreateResponse = { + data: { + id: string; + name?: string; + type?: string; + required?: boolean; + accepts_multiple_values: boolean; + editable_with_roles: string[]; + custom_activity_type_id?: string; + }; +}; + /** * This class to instance communicating to Close.com APIs requires an API Key. * @@ -200,8 +239,8 @@ export default class CloseCom { list: async ({ query, }: { - query: { [key: string]: any }; - }): Promise<{ data: { [key: string]: any }[] }> => { + query: CloseComQuery; + }): Promise<{ data: { [key: string]: CloseComQuery }[] }> => { return this._get({ urlPath: "/lead", query }); }, status: async () => { @@ -247,7 +286,7 @@ export default class CloseCom { ): Promise => { return this._post({ urlPath: "/custom_field/activity/", data }); }, - get: async ({ query }: { query: { [key: string]: any } }): Promise => { + get: async ({ query }: { query: CloseComQuery }): Promise => { return this._get({ urlPath: "/custom_field/activity/", query }); }, }, @@ -257,12 +296,12 @@ export default class CloseCom { ): Promise => { return this._post({ urlPath: "/custom_field/contact/", data }); }, - get: async ({ query }: { query: { [key: string]: any } }): Promise => { + get: async ({ query }: { query: CloseComQuery }): Promise => { return this._get({ urlPath: "/custom_field/contact/", query }); }, }, shared: { - get: async ({ query }: { query: { [key: string]: any } }): Promise => { + get: async ({ query }: { query: CloseComQuery }): Promise => { return this._get({ urlPath: "/custom_field/shared/", query }); }, }, @@ -287,7 +326,7 @@ export default class CloseCom { }, }; - private _get = async ({ urlPath, query }: { urlPath: string; query?: { [key: string]: any } }) => { + private _get = async ({ urlPath, query }: { urlPath: string; query?: CloseComQuery }) => { return await this._request({ urlPath, method: "get", query }); }; private _post = async ({ urlPath, data }: { urlPath: string; data: Record }) => { @@ -307,7 +346,7 @@ export default class CloseCom { }: { urlPath: string; method: string; - query?: { [key: string]: any }; + query?: CloseComQuery; data?: Record; }) => { this.log.debug(method, urlPath, query, data); @@ -316,7 +355,7 @@ export default class CloseCom { Authorization: `Basic ${credentials}`, "Content-Type": "application/json", }; - const queryString = query ? `?${new URLSearchParams(query).toString()}` : ""; + const queryString = query ? `?${new URLSearchParams(String(query)).toString()}` : ""; return await fetch(`${this.apiUrl}${urlPath}${queryString}`, { headers, method, diff --git a/packages/lib/CloseComeUtils.ts b/packages/lib/CloseComeUtils.ts index d9f6dccdc0..467329fd05 100644 --- a/packages/lib/CloseComeUtils.ts +++ b/packages/lib/CloseComeUtils.ts @@ -4,6 +4,7 @@ import type { CloseComCustomActivityCreate, CloseComCustomActivityFieldGet, CloseComCustomContactFieldGet, + CloseComCustomFieldCreateResponse, CloseComFieldOptions, CloseComLead, } from "./CloseCom"; @@ -97,7 +98,7 @@ export async function getCustomFieldsIds( await closeCom.customField[entity].get({ query: { _fields: ["name", "id"].concat(entity === "activity" ? ["custom_activity_type_id"] : []) }, }); - let relevantFields: { [key: string]: any }[]; + let relevantFields: { id: string; name: string }[]; if (entity === "activity") { relevantFields = (allFields as CloseComCustomActivityFieldGet).data.filter( (fie) => fie.custom_activity_type_id === custom_activity_type_id @@ -108,10 +109,10 @@ export async function getCustomFieldsIds( const customFieldsNames = relevantFields.map((fie) => fie.name); const customFieldsExist = customFields.map((cusFie) => customFieldsNames.includes(cusFie[0])); return await Promise.all( - customFieldsExist.map(async (exist, idx) => { + customFieldsExist.flatMap(async (exist, idx) => { if (!exist && entity !== "shared") { const [name, type, required, multiple] = customFields[idx]; - let created: { [key: string]: any }; + let created: CloseComCustomFieldCreateResponse["data"]; if (entity === "activity" && custom_activity_type_id) { created = await closeCom.customField[entity].create({ name, @@ -142,8 +143,10 @@ export async function getCustomFieldsIds( throw Error("Couldn't find the field index"); } } + // Return an array with a single undefined value for the case where "exist" is true + return ""; }) - ); + ).then((results) => results.filter((id) => id)); } export async function getCloseComCustomActivityTypeFieldsIds( @@ -197,12 +200,14 @@ export async function getCloseComLeadId( } ): Promise { const closeComLeadNames = await closeCom.lead.list({ query: { _fields: ["name", "id"] } }); - const searchLeadFromCalCom = closeComLeadNames.data.filter((lead) => lead.name === leadInfo.companyName); + const searchLeadFromCalCom: CloseComLead[] = closeComLeadNames.data.filter( + (lead) => lead.name === leadInfo.companyName + ); if (searchLeadFromCalCom.length === 0) { // No Lead exists, create it const createdLeadFromCalCom = await closeCom.lead.create(leadInfo); - return createdLeadFromCalCom.id; + return createdLeadFromCalCom.id ?? ""; } else { - return searchLeadFromCalCom[0].id; + return searchLeadFromCalCom[0].id ?? ""; } } diff --git a/packages/lib/OgImages.tsx b/packages/lib/OgImages.tsx index d4be153fd4..71eb66de79 100644 --- a/packages/lib/OgImages.tsx +++ b/packages/lib/OgImages.tsx @@ -4,6 +4,7 @@ import { CAL_URL, LOGO } from "./constants"; // Ensures tw prop is typed. declare module "react" { + // eslint-disable-next-line @typescript-eslint/no-unused-vars interface HTMLAttributes { tw?: string; } diff --git a/packages/lib/getEventTypeById.ts b/packages/lib/getEventTypeById.ts index b73530c107..6f0646ea28 100644 --- a/packages/lib/getEventTypeById.ts +++ b/packages/lib/getEventTypeById.ts @@ -241,8 +241,8 @@ export default async function getEventTypeById({ }); const { locations, metadata, ...restEventType } = rawEventType; - const newMetadata = EventTypeMetaDataSchema.parse(metadata || {})!; - const apps = newMetadata.apps || {}; + const newMetadata = EventTypeMetaDataSchema.parse(metadata || {}) || {}; + const apps = newMetadata?.apps || {}; const eventTypeWithParsedMetadata = { ...rawEventType, metadata: newMetadata }; const stripeMetaData = getPaymentAppData(eventTypeWithParsedMetadata, true); newMetadata.apps = { diff --git a/packages/lib/hooks/useTypedQuery.ts b/packages/lib/hooks/useTypedQuery.ts index 44e3a6b074..e07099a946 100644 --- a/packages/lib/hooks/useTypedQuery.ts +++ b/packages/lib/hooks/useTypedQuery.ts @@ -48,7 +48,7 @@ export function useTypedQuery(schema: T) { // Remove old value by key so we can merge new value const { [key]: _, ...newQuery } = parsedQuery; const newValue = { ...newQuery, [key]: value }; - const search = new URLSearchParams(newValue as any).toString(); + const search = new URLSearchParams(newValue).toString(); router.replace({ query: search }, undefined, { shallow: true }); }, [parsedQuery, router] diff --git a/packages/lib/server/checkBookingLimits.ts b/packages/lib/server/checkBookingLimits.ts index ccfa31dae9..b3352c330d 100644 --- a/packages/lib/server/checkBookingLimits.ts +++ b/packages/lib/server/checkBookingLimits.ts @@ -6,7 +6,7 @@ import { HttpError } from "../http-error"; import { parseBookingLimit } from "../isBookingLimits"; export async function checkBookingLimits( - bookingLimits: any, + bookingLimits: IntervalLimit, eventStartDate: Date, eventId: number, returnBusyTimes?: boolean diff --git a/packages/lib/server/checkDurationLimits.ts b/packages/lib/server/checkDurationLimits.ts index b234fae729..98a2849321 100644 --- a/packages/lib/server/checkDurationLimits.ts +++ b/packages/lib/server/checkDurationLimits.ts @@ -1,10 +1,15 @@ import dayjs from "@calcom/dayjs"; +import type { IntervalLimit } from "@calcom/types/Calendar"; import { HttpError } from "../http-error"; import { parseDurationLimit } from "../isDurationLimits"; import { getTotalBookingDuration } from "./queries"; -export async function checkDurationLimits(durationLimits: any, eventStartDate: Date, eventId: number) { +export async function checkDurationLimits( + durationLimits: IntervalLimit, + eventStartDate: Date, + eventId: number +) { const parsedDurationLimits = parseDurationLimit(durationLimits); if (!parsedDurationLimits) { return false; diff --git a/packages/lib/serverConfig.ts b/packages/lib/serverConfig.ts index 46c6dca0a5..33684521ba 100644 --- a/packages/lib/serverConfig.ts +++ b/packages/lib/serverConfig.ts @@ -9,7 +9,7 @@ function detectTransport(): SendmailTransport.Options | SMTPConnection.Options | } if (process.env.EMAIL_SERVER_HOST) { - const port = parseInt(process.env.EMAIL_SERVER_PORT!); + const port = parseInt(process.env.EMAIL_SERVER_PORT || ""); const transport = { host: process.env.EMAIL_SERVER_HOST, port, diff --git a/packages/lib/sync/ISyncService.ts b/packages/lib/sync/ISyncService.ts index 8b2a17788c..46a6593d88 100644 --- a/packages/lib/sync/ISyncService.ts +++ b/packages/lib/sync/ISyncService.ts @@ -23,19 +23,19 @@ export type ConsoleUserInfoType = UserInfo & { }; export interface IUserDeletion { - delete(info: T): Promise; + delete(info: T): Promise; } export interface IUserCreation { - create(info: T): Promise; - update(info: T): Promise; + create(info: T): Promise; + update(info: T): Promise; upsert?: never; } export interface IUserUpsertion { create?: never; update?: never; - upsert(info: T): Promise; + upsert(info: T): Promise; } export interface ISyncService { @@ -50,9 +50,10 @@ export interface ISyncService { export default class SyncServiceCore { protected serviceName: string; - protected service: any; + protected service: unknown; protected log: typeof logger; + // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(serviceName: string, service: any, log: typeof logger) { this.serviceName = serviceName; this.log = log; diff --git a/packages/lib/sync/services/index.ts b/packages/lib/sync/services/index.ts index 3b5b0af93b..256c9ba8a0 100644 --- a/packages/lib/sync/services/index.ts +++ b/packages/lib/sync/services/index.ts @@ -3,7 +3,8 @@ import SendgridService from "./SendgridService"; const services: ISyncServices[] = [ //CloseComService, This service gets a special treatment after deciding it shouldn't get the same treatment as Sendgrid - SendgridService, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + SendgridService as any, ]; export default services; diff --git a/packages/lib/telemetry.ts b/packages/lib/telemetry.ts index fab7f8a9fc..c2059aaafc 100644 --- a/packages/lib/telemetry.ts +++ b/packages/lib/telemetry.ts @@ -88,14 +88,14 @@ export const nextCollectBasicSettings: CollectOpts = { export const extendEventData = ( req: NextRequest | NextApiRequest, res: NextResponse | NextApiResponse, - original: any + original: { page_url: string; isTeamBooking: boolean } ) => { const onVercel = typeof req.headers?.get === "function" ? !!req.headers.get("x-vercel-id") - : !!(req.headers as any)?.["x-vercel-id"]; + : !!(req.headers as { [key: string]: string })?.["x-vercel-id"]; const pageUrl = original?.page_url || req.url || undefined; - const cookies = req.cookies as { [key: string]: any }; + const cookies = req.cookies as { [key: string]: string }; return { title: "", ipAddress: "", diff --git a/packages/trpc/server/createContext.ts b/packages/trpc/server/createContext.ts index 9030a5c829..eee4d65acc 100644 --- a/packages/trpc/server/createContext.ts +++ b/packages/trpc/server/createContext.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from "next"; import type { Session } from "next-auth"; import type { serverSideTranslations } from "next-i18next/serverSideTranslations"; diff --git a/packages/trpc/server/routers/loggedInViewer/eventTypeOrder.handler.ts b/packages/trpc/server/routers/loggedInViewer/eventTypeOrder.handler.ts index 6f9dd4ea62..d92b5f2eab 100644 --- a/packages/trpc/server/routers/loggedInViewer/eventTypeOrder.handler.ts +++ b/packages/trpc/server/routers/loggedInViewer/eventTypeOrder.handler.ts @@ -1,5 +1,3 @@ -import { reverse } from "lodash"; - import { prisma } from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/trpc"; @@ -55,7 +53,7 @@ export const eventTypeOrderHandler = async ({ ctx, input }: EventTypeOrderOption }); } await Promise.all( - reverse(input.ids).map((id, position) => { + input.ids.reverse().map((id, position) => { return prisma.eventType.update({ where: { id, diff --git a/packages/trpc/server/routers/publicViewer/stripeCheckoutSession.handler.ts b/packages/trpc/server/routers/publicViewer/stripeCheckoutSession.handler.ts index fcaf642d0b..c317a0b22a 100644 --- a/packages/trpc/server/routers/publicViewer/stripeCheckoutSession.handler.ts +++ b/packages/trpc/server/routers/publicViewer/stripeCheckoutSession.handler.ts @@ -11,7 +11,7 @@ export const stripeCheckoutSessionHandler = async ({ input }: StripeCheckoutSess const { checkoutSessionId, stripeCustomerId } = input; // Moved the following data checks to superRefine - const validationResult = ZStripeCheckoutSessionInputSchema.parse(input); + ZStripeCheckoutSessionInputSchema.parse(input); let customerId: string; let isPremiumUsername = false; diff --git a/packages/trpc/server/routers/viewer/webhook/edit.handler.ts b/packages/trpc/server/routers/viewer/webhook/edit.handler.ts index 783a1d2c80..fc92ac1791 100644 --- a/packages/trpc/server/routers/viewer/webhook/edit.handler.ts +++ b/packages/trpc/server/routers/viewer/webhook/edit.handler.ts @@ -10,7 +10,7 @@ type EditOptions = { input: TEditInputSchema; }; -export const editHandler = async ({ ctx, input }: EditOptions) => { +export const editHandler = async ({ input }: EditOptions) => { const { id, ...data } = input; const webhook = await prisma.webhook.findFirst({ diff --git a/packages/ui/components/apps/AllApps.tsx b/packages/ui/components/apps/AllApps.tsx index 6d13d50bb8..29c5c2eabc 100644 --- a/packages/ui/components/apps/AllApps.tsx +++ b/packages/ui/components/apps/AllApps.tsx @@ -146,6 +146,7 @@ export function AllApps({ apps, searchText, categories }: AllAppsPropsType) { ? router.query.category : null; setSelectedCategory(queryCategory); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [router.query.category]); const filteredApps = apps diff --git a/packages/ui/components/editor/Editor.tsx b/packages/ui/components/editor/Editor.tsx index 017978f4b7..260cc8fe8f 100644 --- a/packages/ui/components/editor/Editor.tsx +++ b/packages/ui/components/editor/Editor.tsx @@ -44,7 +44,7 @@ export type TextEditorProps = { const editorConfig = { theme: ExampleTheme, - onError(error: any) { + onError(error: Error) { throw error; }, namespace: "", diff --git a/packages/ui/components/editor/plugins/AutoLinkPlugin.tsx b/packages/ui/components/editor/plugins/AutoLinkPlugin.tsx index 95375dc3ce..d1818ff1dc 100644 --- a/packages/ui/components/editor/plugins/AutoLinkPlugin.tsx +++ b/packages/ui/components/editor/plugins/AutoLinkPlugin.tsx @@ -7,7 +7,7 @@ const EMAIL_MATCHER = /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/; const MATCHERS = [ - (text: any) => { + (text: string) => { const match = URL_MATCHER.exec(text); return ( match && { @@ -18,7 +18,7 @@ const MATCHERS = [ } ); }, - (text: any) => { + (text: string) => { const match = EMAIL_MATCHER.exec(text); return ( match && { diff --git a/packages/ui/components/editor/plugins/ToolbarPlugin.tsx b/packages/ui/components/editor/plugins/ToolbarPlugin.tsx index 5e254d32a1..9ec9bb5c6c 100644 --- a/packages/ui/components/editor/plugins/ToolbarPlugin.tsx +++ b/packages/ui/components/editor/plugins/ToolbarPlugin.tsx @@ -358,6 +358,7 @@ export default function ToolbarPlugin(props: TextEditorProps) { } }); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.updateTemplate]); useEffect(() => { @@ -381,6 +382,7 @@ export default function ToolbarPlugin(props: TextEditorProps) { }); }); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { @@ -392,7 +394,7 @@ export default function ToolbarPlugin(props: TextEditorProps) { }), editor.registerCommand( SELECTION_CHANGE_COMMAND, - (_payload, newEditor) => { + (_payload, _newEditor) => { updateToolbar(); return false; }, diff --git a/packages/ui/components/form/checkbox/MultiSelectCheckboxes.tsx b/packages/ui/components/form/checkbox/MultiSelectCheckboxes.tsx index b7f677fb79..3aaf68e8ab 100644 --- a/packages/ui/components/form/checkbox/MultiSelectCheckboxes.tsx +++ b/packages/ui/components/form/checkbox/MultiSelectCheckboxes.tsx @@ -14,13 +14,12 @@ export type Option = { label: string; }; -const InputOption: React.FC>> = ({ +const InputOption: React.FC>> = ({ isDisabled, isFocused, isSelected, children, innerProps, - className, ...rest }) => { const props = { @@ -52,7 +51,7 @@ type MultiSelectionCheckboxesProps = { setValue: (s: Option[]) => unknown; }; -const MultiValue = ({ index, getValue }: { index: number; getValue: any }) => { +const MultiValue = ({ index, getValue }: { index: number; getValue: () => { length: number } }) => { const { t } = useLocale(); return <>{!index &&
    {t("nr_event_type", { count: getValue().length })}
    }; @@ -72,6 +71,7 @@ export default function MultiSelectCheckboxes({ return (