2023-03-09 09:07:23 +00:00
|
|
|
import Link from "next/link";
|
2022-07-14 12:40:53 +00:00
|
|
|
import { useRouter } from "next/router";
|
2022-09-15 09:33:34 +00:00
|
|
|
import { useEffect, useRef } from "react";
|
2022-03-23 22:00:30 +00:00
|
|
|
|
2023-03-09 09:07:23 +00:00
|
|
|
import classNames from "@calcom/lib/classNames";
|
2022-04-06 12:37:06 +00:00
|
|
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
2023-03-09 09:07:23 +00:00
|
|
|
import { CAL_URL } from "@calcom/lib/constants";
|
2022-06-07 06:13:32 +00:00
|
|
|
import { deriveAppDictKeyFromType } from "@calcom/lib/deriveAppDictKeyFromType";
|
2023-03-09 09:07:23 +00:00
|
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
2022-07-22 17:27:06 +00:00
|
|
|
import { trpc } from "@calcom/trpc/react";
|
2023-03-09 09:07:23 +00:00
|
|
|
import type { RouterOutputs } from "@calcom/trpc/react";
|
2022-03-23 22:00:30 +00:00
|
|
|
import type { App } from "@calcom/types/App";
|
2023-03-09 09:07:23 +00:00
|
|
|
import { FiAlertCircle, FiArrowRight, FiCheck } from "@calcom/ui/components/icon";
|
2022-03-23 22:00:30 +00:00
|
|
|
|
2022-06-07 06:13:32 +00:00
|
|
|
import { InstallAppButtonMap } from "./apps.browser.generated";
|
2022-11-23 02:55:25 +00:00
|
|
|
import type { InstallAppButtonProps } from "./types";
|
2022-03-23 22:00:30 +00:00
|
|
|
|
2022-09-06 22:58:16 +00:00
|
|
|
export const InstallAppButtonWithoutPlanCheck = (
|
2022-07-14 12:40:53 +00:00
|
|
|
props: {
|
|
|
|
type: App["type"];
|
|
|
|
} & InstallAppButtonProps
|
2022-09-06 22:58:16 +00:00
|
|
|
) => {
|
2022-07-14 12:40:53 +00:00
|
|
|
const key = deriveAppDictKeyFromType(props.type, InstallAppButtonMap);
|
|
|
|
const InstallAppButtonComponent = InstallAppButtonMap[key as keyof typeof InstallAppButtonMap];
|
2023-03-09 09:07:23 +00:00
|
|
|
if (!InstallAppButtonComponent)
|
|
|
|
return <>{props.render({ useDefaultComponent: true, disabled: props.disableInstall })}</>;
|
2022-07-14 12:40:53 +00:00
|
|
|
|
2023-03-09 09:07:23 +00:00
|
|
|
return (
|
|
|
|
<InstallAppButtonComponent
|
|
|
|
render={props.render}
|
|
|
|
onChanged={props.onChanged}
|
|
|
|
disableInstall={props.disableInstall}
|
|
|
|
/>
|
|
|
|
);
|
2022-09-06 22:58:16 +00:00
|
|
|
};
|
|
|
|
|
2022-03-23 22:00:30 +00:00
|
|
|
export const InstallAppButton = (
|
|
|
|
props: {
|
2022-07-14 12:40:53 +00:00
|
|
|
isProOnly?: App["isProOnly"];
|
2022-03-23 22:00:30 +00:00
|
|
|
type: App["type"];
|
2022-09-15 19:53:09 +00:00
|
|
|
wrapperClassName?: string;
|
2023-03-09 09:07:23 +00:00
|
|
|
disableInstall?: boolean;
|
2022-03-23 22:00:30 +00:00
|
|
|
} & InstallAppButtonProps
|
|
|
|
) => {
|
2022-11-10 23:40:01 +00:00
|
|
|
const { isLoading, data: user } = trpc.viewer.me.useQuery();
|
2022-07-14 12:40:53 +00:00
|
|
|
const router = useRouter();
|
|
|
|
const proProtectionElementRef = useRef<HTMLDivElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
|
|
const el = proProtectionElementRef.current;
|
|
|
|
if (!el) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
el.addEventListener(
|
|
|
|
"click",
|
|
|
|
(e) => {
|
|
|
|
if (!user) {
|
|
|
|
router.push(
|
|
|
|
`${WEBAPP_URL}/auth/login?callbackUrl=${WEBAPP_URL + location.pathname + location.search}`
|
|
|
|
);
|
|
|
|
e.stopPropagation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
true
|
2022-03-23 22:00:30 +00:00
|
|
|
);
|
2022-07-14 12:40:53 +00:00
|
|
|
}, [isLoading, user, router, props.isProOnly]);
|
|
|
|
|
|
|
|
if (isLoading) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2022-09-15 19:53:09 +00:00
|
|
|
<div ref={proProtectionElementRef} className={props.wrapperClassName}>
|
2022-07-14 12:40:53 +00:00
|
|
|
<InstallAppButtonWithoutPlanCheck {...props} />
|
|
|
|
</div>
|
|
|
|
);
|
2022-03-23 22:00:30 +00:00
|
|
|
};
|
2022-05-06 17:21:30 +00:00
|
|
|
|
|
|
|
export { AppConfiguration } from "./_components/AppConfiguration";
|
2023-03-09 09:07:23 +00:00
|
|
|
|
|
|
|
export const AppDependencyComponent = ({
|
|
|
|
appName,
|
|
|
|
dependencyData,
|
|
|
|
}: {
|
|
|
|
appName: string;
|
|
|
|
dependencyData: RouterOutputs["viewer"]["appsRouter"]["queryForDependencies"];
|
|
|
|
}) => {
|
|
|
|
const { t } = useLocale();
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={classNames(
|
|
|
|
"rounded-md py-3 px-4",
|
|
|
|
dependencyData && dependencyData.some((dependency) => !dependency.installed)
|
|
|
|
? "bg-blue-100"
|
|
|
|
: "bg-gray-100"
|
|
|
|
)}>
|
|
|
|
{dependencyData &&
|
|
|
|
dependencyData.map((dependency) => {
|
|
|
|
return dependency.installed ? (
|
|
|
|
<div className="items-start space-x-2.5">
|
|
|
|
<div className="flex items-start">
|
|
|
|
<div>
|
|
|
|
<FiCheck className="mt-1 mr-2 font-semibold" />
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<span className="font-semibold">
|
|
|
|
{t("app_is_connected", { dependencyName: dependency.name })}
|
|
|
|
</span>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<span>
|
|
|
|
{t("this_app_requires_connected_account", {
|
|
|
|
appName,
|
|
|
|
dependencyName: dependency.name,
|
|
|
|
})}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div className="items-start space-x-2.5">
|
|
|
|
<div className="flex items-start text-blue-900">
|
|
|
|
<div>
|
|
|
|
<FiAlertCircle className="mt-1 mr-2 font-semibold" />
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<span className="font-semibold">
|
|
|
|
{t("this_app_requires_connected_account", { appName, dependencyName: dependency.name })}
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<>
|
|
|
|
<Link
|
|
|
|
href={`${CAL_URL}/apps/${dependency.slug}`}
|
|
|
|
className="flex items-center text-blue-900 underline">
|
|
|
|
<span className="mr-1">
|
|
|
|
{t("connect_app", { dependencyName: dependency.name })}
|
|
|
|
</span>
|
|
|
|
<FiArrowRight />
|
|
|
|
</Link>
|
|
|
|
</>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|