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
parent
87e1ad7115
commit
2dbc73c75b
|
@ -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)
|
||||
|
|
|
@ -60,6 +60,7 @@ export default function AppListCard(props: AppListCardProps) {
|
|||
timeoutRef.current = null;
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}}
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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>>;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ export default function Page() {
|
|||
callbackUrl: "/",
|
||||
code,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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`);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 } }),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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 } }),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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 } }),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
}) {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
(() => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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([]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { expect, vi, afterEach, test } from "vitest";
|
||||
|
||||
import CloseCom from "@calcom/lib/CloseCom";
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -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 ",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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([]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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([]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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([]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: "" };
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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>;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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",
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
BooleanToggleGroupField,
|
||||
SelectField,
|
||||
InputField,
|
||||
Input,
|
||||
showToast,
|
||||
Switch,
|
||||
} from "@calcom/ui";
|
||||
|
|
|
@ -29,7 +29,7 @@ export function UpgradeTip({
|
|||
const { isLoading, hasTeamPlan } = useHasTeamPlan();
|
||||
|
||||
if (hasTeamPlan) return children;
|
||||
|
||||
|
||||
if (isLoading) return <>{isParentLoading}</>;
|
||||
|
||||
return (
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ?? "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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: "",
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -44,7 +44,7 @@ export type TextEditorProps = {
|
|||
|
||||
const editorConfig = {
|
||||
theme: ExampleTheme,
|
||||
onError(error: any) {
|
||||
onError(error: Error) {
|
||||
throw error;
|
||||
},
|
||||
namespace: "",
|
||||
|
|
|
@ -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 && {
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue