chore: fix all Typescript warnings (#8618)

* [CAL-1517] fix all Typescript warnings

* solve conflicts

* Update stripeCheckoutSession.handler.ts

Parse is a guard, so even though the variable is unused the parse itself is needed.

* Update ToolbarPlugin.tsx

Don't change dependency tree

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
pull/9340/head
GitStart-Cal.com 2023-06-06 19:59:57 +08:00 committed by GitHub
parent 87e1ad7115
commit 2dbc73c75b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 425 additions and 319 deletions

View File

@ -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)

View File

@ -60,6 +60,7 @@ export default function AppListCard(props: AppListCardProps) {
timeoutRef.current = null;
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (

View File

@ -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"];
}

View File

@ -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
<InstallAppButton
type={data.type}
render={(installProps) => {
const props = { ...installProps } as any;
const props = { ...installProps } as FunctionComponent<SVGProps<SVGSVGElement>>;
return (
<DropdownItem {...props} color="minimal" type="button">
<span className="flex items-center gap-x-2">

View File

@ -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<typeof Shell>) {
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 (
<Shell {...rest} hideHeadingOnMobile>
<AppCategoryNavigation baseURL="/apps/installed" containerClassname="min-w-0 w-full">

View File

@ -65,7 +65,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
const [requiresConfirmation, setRequiresConfirmation] = useState(eventType.requiresConfirmation);
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
const seatsEnabled = formMethods.watch("seatsPerTimeSlotEnabled");
const noShowFeeEnabled = eventType.metadata.apps?.stripe?.paymentOption === "HOLD";
const noShowFeeEnabled = eventType.metadata?.apps?.stripe?.paymentOption === "HOLD";
useEffect(() => {
!hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0]?.id ?? team?.id));

View File

@ -115,7 +115,7 @@ export const EventSetupTab = (
const [showLocationModal, setShowLocationModal] = useState(false);
const [editingLocationType, setEditingLocationType] = useState<string>("");
const [selectedLocation, setSelectedLocation] = useState<LocationOption | undefined>(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;

View File

@ -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={
<div className="flex items-center justify-end">
{!eventType.metadata.managedEventConfig && (
{!eventType.metadata?.managedEventConfig && (
<>
<div
className={classNames(

View File

@ -39,6 +39,7 @@ export default function RequiresConfirmationController({
if (!requiresConfirmation) {
formMethods.setValue("metadata.requiresConfirmationThreshold", undefined);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [requiresConfirmation]);
const { shouldLockDisableProps } = useLockedFieldsManager(

View File

@ -24,7 +24,7 @@ interface IUserProfileProps {
const UserProfile = (props: IUserProfileProps) => {
const { user } = props;
const { t } = useLocale();
const avatarRef = useRef<HTMLInputElement>(null!);
const avatarRef = useRef<HTMLInputElement>(null);
const { setValue, handleSubmit, getValues } = useForm<FormData>({
defaultValues: { bio: user?.bio || "" },
});
@ -76,7 +76,7 @@ const UserProfile = (props: IUserProfileProps) => {
async function updateProfileHandler(event: FormEvent<HTMLFormElement>) {
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<HTMLFormElement>);
setImageSrc(newAvatar);
}}

View File

@ -66,6 +66,7 @@ export function QueryCell<TData, TError extends ErrorLike>(
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<TQuery>,
TOutput = inferProcedureOutput<TQuery>
>(
queryProcedure: DecorateProcedure<TQuery, any, any>,
queryProcedure: DecorateProcedure<TQuery, inferProcedureInput<TQuery>, inferProcedureOutput<TQuery>>,
input?: TInput,
params?: UseTRPCQueryOptions<any, TInput, TOutput, TOutput, TError>
params?: UseTRPCQueryOptions<TQuery, TInput, TOutput, TOutput, TError>
) => {
return function WithQuery(
opts: Omit<

View File

@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
type GetSSRResult<TProps> =
//
{ props: TProps } | { redirect: any } | { notFound: boolean };
{ props: TProps } | { redirect: { destination: string; permanent: boolean } } | { notFound: boolean };
type GetSSRFn<TProps> = (...args: any[]) => Promise<GetSSRResult<TProps>>;

View File

@ -19,6 +19,7 @@ export default function Page() {
callbackUrl: "/",
code,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;

View File

@ -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;
}
}
}
}

View File

@ -18,6 +18,7 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps<type
if (HOSTED_CAL_FEATURES) {
router.push("/auth/login");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
@ -29,6 +30,7 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps<type
},
{ tenant: samlTenantID, product: samlProductID }
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;

View File

@ -105,7 +105,8 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
);
}
const WithQuery = withQuery(trpc.viewer.availability.list);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const WithQuery = withQuery(trpc.viewer.availability.list as any);
export default function AvailabilityPage() {
const { t } = useLocale();

View File

@ -26,7 +26,7 @@ const AvailabilityView = ({ user }: { user: User }) => {
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,

View File

@ -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 {

View File

@ -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<FormValues>({
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;

View File

@ -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 ? (
<MobileTeamsTab eventTypeGroups={data.eventTypeGroups} />
) : (
data.eventTypeGroups.map((group, index) => (
data.eventTypeGroups.map((group: EventTypeGroup, index: number) => (
<div className="flex flex-col" key={group.profile.slug}>
<EventTypeListHeading
profile={group.profile}

View File

@ -46,7 +46,10 @@ interface GeneralViewProps {
user: RouterOutputs["viewer"]["me"];
}
const WithQuery = withQuery(trpc.viewer.public.i18n, undefined, { trpc: { context: { skipBatch: true } } });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const WithQuery = withQuery(trpc.viewer.public.i18n as any, undefined, {
trpc: { context: { skipBatch: true } },
});
const GeneralQueryView = () => {
const { t } = useLocale();

View File

@ -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);

View File

@ -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;

View File

@ -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"),

View File

@ -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");

View File

@ -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`);

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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 } }),
};
};

View File

@ -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 } }),
};
};

View File

@ -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<string, JSONValue>) => {
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 } }),
};
};

View File

@ -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");

View File

@ -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;
};
};
}) {

View File

@ -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) => {

View File

@ -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 {

View File

@ -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();

View File

@ -76,9 +76,7 @@ test.describe("Onboarding", () => {
const userComplete = await user.self();
const userCompleteBio = userComplete.bio ? userComplete.bio : "";
expect(userCompleteBio.replace("<p><br></p>", "").length).toBe(0);
expect(userComplete.bio?.replace("<p><br></p>", "").length).toBe(0);
});
});
});

View File

@ -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();
});

View File

@ -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

View File

@ -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;

View File

@ -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(
(() => {

View File

@ -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,

View File

@ -1,9 +1,10 @@
export function DynamicComponent<T extends Record<string, any>>(props: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function DynamicComponent<T extends Record<string, React.ComponentType<any>>>(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<T extends Record<string, any>>(props: {
const Component = componentMap[dirName];
return (
<div className={props.wrapperClassName || ""}>
<div className={wrapperClassName || ""}>
<Component {...rest} />
</div>
);

View File

@ -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,

View File

@ -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;

View File

@ -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",

View File

@ -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<any> {
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<EventBusyDate[]> {
return Promise.resolve([]);
}
async listCalendars(event?: CalendarEvent): Promise<IntegrationCalendar[]> {
async listCalendars(_event?: CalendarEvent): Promise<IntegrationCalendar[]> {
return Promise.resolve([]);
}
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { expect, vi, afterEach, test } from "vitest";
import CloseCom from "@calcom/lib/CloseCom";

View File

@ -78,7 +78,7 @@ export const fetcher = async (endpoint: string, init?: RequestInit | undefined)
}).then(handleErrorsJson);
};
function postToDailyAPI(endpoint: string, body: Record<string, any>) {
function postToDailyAPI(endpoint: string, body: Record<string, unknown>) {
return fetcher(endpoint, {
method: "POST",
body: JSON.stringify(body),

View File

@ -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,

View File

@ -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,

View File

@ -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<any> {
try {
const appointment = await Appointment.Bind(

View File

@ -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);
}
}}
/>
)}

View File

@ -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) => (
<div
className={classNames(
"flex cursor-pointer items-center border-b-2 p-2 text-sm ",

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { Prisma } from "@prisma/client";
import type { calendar_v3 } from "googleapis";
import { google } from "googleapis";
@ -71,7 +72,7 @@ export default class GoogleCalendarService implements Calendar {
};
async createEvent(calEventRaw: CalendarEvent): Promise<NewCalendarEventType> {
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<any> {
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,

View File

@ -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",

View File

@ -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<any> }>;
private auth: Promise<{ getToken: () => Promise<HubspotToken | void | never[]> }>;
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<any> {
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<EventBusyDate[]> {
return Promise.resolve([]);
}
async listCalendars(event?: CalendarEvent): Promise<IntegrationCalendar[]> {
async listCalendars(_event?: CalendarEvent): Promise<IntegrationCalendar[]> {
return Promise.resolve([]);
}
}

View File

@ -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<string, any>;
body: Record<string, DefaultBodyType>;
}
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<any> {
async updateEvent(uid: string, event: CalendarEvent): Promise<NewCalendarEventType> {
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<Response> => {
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

View File

@ -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;

View File

@ -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;

View File

@ -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",

View File

@ -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([]);
}
}

View File

@ -74,27 +74,28 @@ export default class CloseComCalendarService implements Calendar {
});
}
async updateEvent(uid: string, event: CalendarEvent): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async updateEvent(_uid: string, _event: CalendarEvent): Promise<any> {
// 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<void> {
async deleteEvent(_uid: string): Promise<void> {
// 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<EventBusyDate[]> {
return Promise.resolve([]);
}
async listCalendars(event?: CalendarEvent): Promise<IntegrationCalendar[]> {
async listCalendars(_event?: CalendarEvent): Promise<IntegrationCalendar[]> {
return Promise.resolve([]);
}
}

View File

@ -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: "" };

View File

@ -200,7 +200,7 @@ export class PaymentService implements IAbstractPaymentService {
}
}
async chargeCard(payment: Payment): Promise<Payment> {
async chargeCard(payment: Payment, _bookingId?: Booking["id"]): Promise<Payment> {
try {
const stripeAppKeys = await prisma?.app.findFirst({
select: {

View File

@ -3,7 +3,7 @@ import { loadStripe } from "@stripe/stripe-js/pure";
export type Maybe<T> = T | undefined | null;
const stripePublicKey = process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY!;
const stripePublicKey = process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY || "";
let stripePromise: Promise<Stripe | null>;
/**

View File

@ -28,7 +28,7 @@ export const stripeDataSchema = stripeOAuthTokenSchema.extend({
export type StripeData = z.infer<typeof stripeDataSchema>;
/** 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",
});

View File

@ -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<string, string>,
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

View File

@ -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) {

View File

@ -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;

View File

@ -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<any | NextApiResponse | void>
) {
function validate(handler: (req: NextApiRequest, res: NextApiResponse) => Promise<NextApiResponse | void>) {
return async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === "POST") {
try {

View File

@ -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";

View File

@ -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",

View File

@ -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");

View File

@ -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"]
}

View File

@ -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<string, any>;
responses?: Record<string, object>;
customInputs?: z.infer<typeof bookingCreateSchemaLegacyPropsForApi>["customInputs"];
},
eventTypeCustomInputs: Awaited<ReturnType<typeof getEventTypesFromDB>>["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();

View File

@ -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) => (
<li key={option.value} className={`flex py-2 px-3 ${index === value.length - 1 ? "" : "border-subtle border-b"}`}>
<li
key={option.value}
className={`flex py-2 px-3 ${index === value.length - 1 ? "" : "border-subtle border-b"}`}>
<Avatar size="sm" imageSrc={option.avatar} alt={option.label} />
<p className="text-emphasis ms-3 my-auto text-sm">{option.label}</p>
<X

View File

@ -19,7 +19,6 @@ import {
BooleanToggleGroupField,
SelectField,
InputField,
Input,
showToast,
Switch,
} from "@calcom/ui";

View File

@ -29,7 +29,7 @@ export function UpgradeTip({
const { isLoading, hasTeamPlan } = useHasTeamPlan();
if (hasTeamPlan) return children;
if (isLoading) return <>{isParentLoading}</>;
return (

View File

@ -32,8 +32,8 @@ const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2: Record<string, WebhookTriggerEve
core: [
{ value: WebhookTriggerEvents.BOOKING_CANCELLED, label: "booking_cancelled" },
{ value: WebhookTriggerEvents.BOOKING_CREATED, label: "booking_created" },
{ value: WebhookTriggerEvents.BOOKING_REJECTED, label: "booking_rejected"},
{ value: WebhookTriggerEvents.BOOKING_REQUESTED, label: "booking_requested"},
{ value: WebhookTriggerEvents.BOOKING_REJECTED, label: "booking_rejected" },
{ value: WebhookTriggerEvents.BOOKING_REQUESTED, label: "booking_requested" },
{ value: WebhookTriggerEvents.BOOKING_RESCHEDULED, label: "booking_rescheduled" },
{ value: WebhookTriggerEvents.MEETING_ENDED, label: "meeting_ended" },
{ value: WebhookTriggerEvents.RECORDING_READY, label: "recording_ready" },

View File

@ -5,6 +5,7 @@ export type CloseComLead = {
contactName?: string;
contactEmail?: string;
description?: string;
id?: string | PromiseLike<string>;
};
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>]: 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<T extends string> = `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<CloseComCustomActivityFieldGet["data"][number]> => {
return this._post({ urlPath: "/custom_field/activity/", data });
},
get: async ({ query }: { query: { [key: string]: any } }): Promise<CloseComCustomActivityFieldGet> => {
get: async ({ query }: { query: CloseComQuery }): Promise<CloseComCustomActivityFieldGet> => {
return this._get({ urlPath: "/custom_field/activity/", query });
},
},
@ -257,12 +296,12 @@ export default class CloseCom {
): Promise<CloseComCustomContactFieldGet["data"][number]> => {
return this._post({ urlPath: "/custom_field/contact/", data });
},
get: async ({ query }: { query: { [key: string]: any } }): Promise<CloseComCustomContactFieldGet> => {
get: async ({ query }: { query: CloseComQuery }): Promise<CloseComCustomContactFieldGet> => {
return this._get({ urlPath: "/custom_field/contact/", query });
},
},
shared: {
get: async ({ query }: { query: { [key: string]: any } }): Promise<CloseComCustomContactFieldGet> => {
get: async ({ query }: { query: CloseComQuery }): Promise<CloseComCustomContactFieldGet> => {
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<string, unknown> }) => {
@ -307,7 +346,7 @@ export default class CloseCom {
}: {
urlPath: string;
method: string;
query?: { [key: string]: any };
query?: CloseComQuery;
data?: Record<string, unknown>;
}) => {
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,

View File

@ -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<string> {
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 ?? "";
}
}

View File

@ -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<T> {
tw?: string;
}

View File

@ -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 = {

View File

@ -48,7 +48,7 @@ export function useTypedQuery<T extends z.AnyZodObject>(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]

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -23,19 +23,19 @@ export type ConsoleUserInfoType = UserInfo & {
};
export interface IUserDeletion<T> {
delete(info: T): Promise<any>;
delete(info: T): Promise<WebUserInfoType>;
}
export interface IUserCreation<T> {
create(info: T): Promise<any>;
update(info: T): Promise<any>;
create(info: T): Promise<WebUserInfoType>;
update(info: T): Promise<WebUserInfoType>;
upsert?: never;
}
export interface IUserUpsertion<T> {
create?: never;
update?: never;
upsert(info: T): Promise<any>;
upsert(info: T): Promise<WebUserInfoType>;
}
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;

View File

@ -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;

View File

@ -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: "",

View File

@ -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";

View File

@ -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,

View File

@ -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;

View File

@ -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({

View File

@ -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

View File

@ -44,7 +44,7 @@ export type TextEditorProps = {
const editorConfig = {
theme: ExampleTheme,
onError(error: any) {
onError(error: Error) {
throw error;
},
namespace: "",

View File

@ -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 && {

View File

@ -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;
},

Some files were not shown because too many files have changed in this diff Show More