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:
co-authored by
Somay Chauhan
Hariom
parent
fed3987028
commit
caf7943c91
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
Reference in New Issue
Block a user