fix: set conferencing apps as default (#15376)

* fix: set conferencing apps as default

* fix in other oauth conferencing apps

* creating default event-types should set the user's default location

* Update getDefaultLocations.ts

* fix: unit test

* default install only for first oauth app

* fix: type-check

* update default on success

* fix: pass callback prop

* chore: code cleanup

* Fix condition

* no longer needed

- as we reverted https://github.com/calcom/cal.com/commit/20fdb50081ae684723a5af78436068c0b09509a4

---------

Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com>
Co-authored-by: Hariom <hariombalhara@gmail.com>
This commit is contained in:
Amit Sharma
2024-07-10 11:00:59 +00:00
committed by GitHub
co-authored by Somay Chauhan Hariom
parent fed3987028
commit caf7943c91
7 changed files with 73 additions and 5 deletions
@@ -4,9 +4,9 @@ import type { TDependencyData } from "@calcom/app-store/_appRegistry";
import { InstallAppButtonWithoutPlanCheck } from "@calcom/app-store/components";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import type { App } from "@calcom/types/App";
import { Icon } from "@calcom/ui";
import { Button } from "@calcom/ui";
import { Badge, Button, Icon } from "@calcom/ui";
interface IAppConnectionItem {
title: string;
@@ -14,21 +14,33 @@ interface IAppConnectionItem {
logo: string;
type: App["type"];
installed?: boolean;
isDefault?: boolean;
defaultInstall?: boolean;
slug?: string;
dependencyData?: TDependencyData;
}
const AppConnectionItem = (props: IAppConnectionItem) => {
const { title, logo, type, installed } = props;
const { title, logo, type, installed, isDefault, defaultInstall, slug } = props;
const { t } = useLocale();
const setDefaultConferencingApp = trpc.viewer.appsRouter.setDefaultConferencingApp.useMutation();
const dependency = props.dependencyData?.find((data) => !data.installed);
return (
<div className="flex flex-row items-center justify-between p-5">
<div className="flex items-center space-x-3">
<img src={logo} alt={title} className="h-8 w-8" />
<p className="text-sm font-bold">{title}</p>
{isDefault && <Badge variant="green">{t("default")}</Badge>}
</div>
<InstallAppButtonWithoutPlanCheck
type={type}
options={{
onSuccess: () => {
if (defaultInstall && slug) {
setDefaultConferencingApp.mutate({ slug });
}
},
}}
render={(buttonProps) => (
<Button
{...buttonProps}
@@ -1,6 +1,8 @@
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { userMetadata } from "@calcom/prisma/zod-utils";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { Icon, List } from "@calcom/ui";
import { AppConnectionItem } from "../components/AppConnectionItem";
@@ -17,12 +19,16 @@ const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
onlyInstalled: false,
sortByMostPopular: true,
});
const { data } = useMeQuery();
const { t } = useLocale();
const metadata = userMetadata.parse(data?.metadata);
const hasAnyInstalledVideoApps = queryConnectedVideoApps?.items.some(
(item) => item.userCredentialIds.length > 0
);
const defaultConferencingApp = metadata?.defaultConferencingApp?.appSlug;
return (
<>
{!isPending && (
@@ -36,10 +42,15 @@ const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
<AppConnectionItem
type={item.type}
title={item.name}
isDefault={item.slug === defaultConferencingApp}
description={item.description}
dependencyData={item.dependencyData}
logo={item.logo}
slug={item.slug}
installed={item.userCredentialIds.length > 0}
defaultInstall={
!defaultConferencingApp && item.appData?.location?.linkType === "dynamic"
}
/>
)}
</li>
@@ -19,7 +19,7 @@ type CustomUseMutationOptions =
| undefined;
type AddAppMutationData = { setupPending: boolean } | void;
type UseAddAppMutationOptions = CustomUseMutationOptions & {
export type UseAddAppMutationOptions = CustomUseMutationOptions & {
onSuccess?: (data: AddAppMutationData) => void;
installGoogleVideo?: boolean;
returnTo?: string;
+3 -1
View File
@@ -2,6 +2,7 @@ import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useRef } from "react";
import type { UseAddAppMutationOptions } from "@calcom/app-store/_utils/useAddAppMutation";
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
import classNames from "@calcom/lib/classNames";
import { WEBAPP_URL } from "@calcom/lib/constants";
@@ -19,9 +20,10 @@ import type { InstallAppButtonProps } from "./types";
export const InstallAppButtonWithoutPlanCheck = (
props: {
type: App["type"];
options?: UseAddAppMutationOptions;
} & InstallAppButtonProps
) => {
const mutation = useAddAppMutation(null);
const mutation = useAddAppMutation(null, props.options);
const key = deriveAppDictKeyFromType(props.type, InstallAppButtonMap);
const InstallAppButtonComponent = InstallAppButtonMap[key as keyof typeof InstallAppButtonMap];
if (!InstallAppButtonComponent)
@@ -4,6 +4,7 @@ import { checkGlobalKeysSchema } from "./checkGlobalKeys.schema";
import { ZListLocalInputSchema } from "./listLocal.schema";
import { ZQueryForDependenciesInputSchema } from "./queryForDependencies.schema";
import { ZSaveKeysInputSchema } from "./saveKeys.schema";
import { ZSetDefaultConferencingAppSchema } from "./setDefaultConferencingApp.schema";
import { ZToggleInputSchema } from "./toggle.schema";
import { ZUpdateAppCredentialsInputSchema } from "./updateAppCredentials.schema";
@@ -15,6 +16,7 @@ type AppsRouterHandlerCache = {
updateAppCredentials?: typeof import("./updateAppCredentials.handler").updateAppCredentialsHandler;
queryForDependencies?: typeof import("./queryForDependencies.handler").queryForDependenciesHandler;
checkGlobalKeys?: typeof import("./checkGlobalKeys.handler").checkForGlobalKeysHandler;
setDefaultConferencingApp?: typeof import("./setDefaultConferencingApp.handler").setDefaultConferencingAppHandler;
};
const UNSTABLE_HANDLER_CACHE: AppsRouterHandlerCache = {};
@@ -87,6 +89,25 @@ export const appsRouter = router({
});
}),
setDefaultConferencingApp: authedProcedure
.input(ZSetDefaultConferencingAppSchema)
.mutation(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.setDefaultConferencingApp) {
UNSTABLE_HANDLER_CACHE.setDefaultConferencingApp = await import(
"./setDefaultConferencingApp.handler"
).then((mod) => mod.setDefaultConferencingAppHandler);
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.setDefaultConferencingApp) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.setDefaultConferencingApp({
ctx,
input,
});
}),
updateAppCredentials: authedProcedure
.input(ZUpdateAppCredentialsInputSchema)
.mutation(async ({ ctx, input }) => {
@@ -0,0 +1,15 @@
import setDefaultConferencingApp from "@calcom/app-store/_utils/setDefaultConferencingApp";
import type { TrpcSessionUser } from "../../../trpc";
import type { TSetDefaultConferencingAppSchema } from "./setDefaultConferencingApp.schema";
type SetDefaultConferencingAppOptions = {
ctx: {
user: NonNullable<TrpcSessionUser>;
};
input: TSetDefaultConferencingAppSchema;
};
export const setDefaultConferencingAppHandler = async ({ ctx, input }: SetDefaultConferencingAppOptions) => {
return await setDefaultConferencingApp(ctx.user.id, input.slug);
};
@@ -0,0 +1,7 @@
import { z } from "zod";
export const ZSetDefaultConferencingAppSchema = z.object({
slug: z.string(),
});
export type TSetDefaultConferencingAppSchema = z.infer<typeof ZSetDefaultConferencingAppSchema>;