Reusable Upgrade component for teams only features (#6473)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>pull/6483/head
parent
443329b99f
commit
1376f0991f
|
@ -7,7 +7,6 @@ import { APP_NAME } from "@calcom/lib/constants";
|
|||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
ColorPicker,
|
||||
Form,
|
||||
|
@ -17,6 +16,7 @@ import {
|
|||
SkeletonContainer,
|
||||
SkeletonText,
|
||||
Switch,
|
||||
UpgradeTeamsBadge,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
@ -49,6 +49,7 @@ const AppearanceView = () => {
|
|||
const session = useSession();
|
||||
const utils = trpc.useContext();
|
||||
const { data: user, isLoading } = trpc.viewer.me.useQuery();
|
||||
const { data: dataHasTeamPlan, isLoading: isLoadingHasTeamPlan } = trpc.viewer.teams.hasTeamPlan.useQuery();
|
||||
|
||||
const formMethods = useForm({
|
||||
defaultValues: {
|
||||
|
@ -73,7 +74,8 @@ const AppearanceView = () => {
|
|||
},
|
||||
});
|
||||
|
||||
if (isLoading) return <SkeletonLoader title={t("appearance")} description={t("appearance_description")} />;
|
||||
if (isLoading || isLoadingHasTeamPlan)
|
||||
return <SkeletonLoader title={t("appearance")} description={t("appearance_description")} />;
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
|
@ -180,18 +182,18 @@ const AppearanceView = () => {
|
|||
<p className="font-semibold ltr:mr-2 rtl:ml-2">
|
||||
{t("disable_cal_branding", { appName: APP_NAME })}
|
||||
</p>
|
||||
<Badge variant="gray">{t("pro")}</Badge>
|
||||
{!dataHasTeamPlan?.hasTeamPlan && <UpgradeTeamsBadge />}
|
||||
</div>
|
||||
<p className="mt-0.5 text-gray-600">{t("removes_cal_branding", { appName: APP_NAME })}</p>
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Switch
|
||||
id="hideBranding"
|
||||
disabled={!session.data?.user.belongsToActiveTeam}
|
||||
disabled={!dataHasTeamPlan?.hasTeamPlan}
|
||||
onCheckedChange={(checked) =>
|
||||
formMethods.setValue("hideBranding", checked, { shouldDirty: true })
|
||||
}
|
||||
checked={!session.data?.user.belongsToActiveTeam ? false : value}
|
||||
checked={!dataHasTeamPlan?.hasTeamPlan ? false : value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1509,5 +1509,6 @@
|
|||
"using_meet_requires_calendar": "Using Google Meet requires a connected Google Calendar",
|
||||
"continue_to_install_google_calendar": "Continue to install Google Calendar",
|
||||
"install_google_meet": "Install Google Meet",
|
||||
"install_google_calendar": "Install Google Calendar"
|
||||
"install_google_calendar": "Install Google Calendar",
|
||||
"no_recordings_found": "No recordings found"
|
||||
}
|
||||
|
|
|
@ -7,7 +7,14 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||
import { RecordingItemSchema } from "@calcom/prisma/zod-utils";
|
||||
import { RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import type { PartialReference } from "@calcom/types/EventManager";
|
||||
import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui";
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
UpgradeTeamsBadge,
|
||||
} from "@calcom/ui";
|
||||
import { Button, showToast, Icon } from "@calcom/ui";
|
||||
|
||||
import RecordingListSkeleton from "./components/RecordingListSkeleton";
|
||||
|
@ -58,9 +65,7 @@ export const ViewRecordingsDialog = (props: IViewRecordingsDialog) => {
|
|||
const { t, i18n } = useLocale();
|
||||
const { isOpenDialog, setIsOpenDialog, booking, timeFormat } = props;
|
||||
const [downloadingRecordingId, setRecordingId] = useState<string | null>(null);
|
||||
const session = useSession();
|
||||
const belongsToActiveTeam = session?.data?.user?.belongsToActiveTeam ?? false;
|
||||
const [showUpgradeBanner, setShowUpgradeBanner] = useState<boolean>(false);
|
||||
const { data: dataHasTeamPlan, isLoading: isLoadingHasTeamPlan } = trpc.viewer.teams.hasTeamPlan.useQuery();
|
||||
const roomName =
|
||||
booking?.references?.find((reference: PartialReference) => reference.type === "daily_video")?.meetingId ??
|
||||
undefined;
|
||||
|
@ -103,57 +108,48 @@ export const ViewRecordingsDialog = (props: IViewRecordingsDialog) => {
|
|||
<DialogContent>
|
||||
<DialogHeader title={t("recordings_title")} subtitle={subtitle} />
|
||||
<LicenseRequired>
|
||||
{showUpgradeBanner && <UpgradeRecordingBanner />}
|
||||
{!showUpgradeBanner && (
|
||||
<>
|
||||
{isLoading && <RecordingListSkeleton />}
|
||||
{recordings && "data" in recordings && recordings?.data?.length > 0 && (
|
||||
<div className="flex flex-col gap-3">
|
||||
{recordings.data.map((recording: RecordingItemSchema, index: number) => {
|
||||
return (
|
||||
<div
|
||||
className="flex w-full items-center justify-between rounded-md border py-2 px-4"
|
||||
key={recording.id}>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="text-sm font-semibold">
|
||||
{t("recording")} {index + 1}
|
||||
</h1>
|
||||
<p className="text-sm font-normal text-gray-500">
|
||||
{convertSecondsToMs(recording.duration)}
|
||||
</p>
|
||||
</div>
|
||||
{belongsToActiveTeam ? (
|
||||
<Button
|
||||
StartIcon={Icon.FiDownload}
|
||||
className="ml-4 lg:ml-0"
|
||||
loading={downloadingRecordingId === recording.id}
|
||||
onClick={() => handleDownloadClick(recording.id)}>
|
||||
{t("download")}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
color="secondary"
|
||||
tooltip={t("recordings_are_part_of_the_teams_plan")}
|
||||
className="ml-4 lg:ml-0"
|
||||
onClick={() => setShowUpgradeBanner(true)}>
|
||||
{t("upgrade")}
|
||||
</Button>
|
||||
)}
|
||||
<>
|
||||
{isLoading && isLoadingHasTeamPlan && <RecordingListSkeleton />}
|
||||
{recordings && "data" in recordings && recordings?.data?.length > 0 && (
|
||||
<div className="flex flex-col gap-3">
|
||||
{recordings.data.map((recording: RecordingItemSchema, index: number) => {
|
||||
return (
|
||||
<div
|
||||
className="flex w-full items-center justify-between rounded-md border px-4 py-2"
|
||||
key={recording.id}>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="text-sm font-semibold">
|
||||
{t("recording")} {index + 1}
|
||||
</h1>
|
||||
<p className="text-sm font-normal text-gray-500">
|
||||
{convertSecondsToMs(recording.duration)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{dataHasTeamPlan?.hasTeamPlan ? (
|
||||
<Button
|
||||
StartIcon={Icon.FiDownload}
|
||||
className="ml-4 lg:ml-0"
|
||||
loading={downloadingRecordingId === recording.id}
|
||||
onClick={() => handleDownloadClick(recording.id)}>
|
||||
{t("download")}
|
||||
</Button>
|
||||
) : (
|
||||
<UpgradeTeamsBadge />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{!isLoading &&
|
||||
(!recordings ||
|
||||
(recordings && "total_count" in recordings && recordings?.total_count === 0)) && (
|
||||
<h1 className="font-semibold">{t("no_recordings_found")}</h1>
|
||||
)}
|
||||
{!isLoading &&
|
||||
(!recordings ||
|
||||
(recordings && "total_count" in recordings && recordings?.total_count === 0)) && (
|
||||
<h1 className="font-semibold">No Recordings Found</h1>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</LicenseRequired>
|
||||
<DialogFooter>
|
||||
<DialogClose onClick={() => setShowUpgradeBanner(false)} className="border" />
|
||||
<DialogClose className="border" />
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import Link from "next/link";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
||||
import { Tooltip } from "../tooltip";
|
||||
import { Badge } from "./Badge";
|
||||
|
||||
export const UpgradeTeamsBadge = function UpgradeTeamsBadge() {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<Tooltip content={t("upgrade_to_enable_feature")}>
|
||||
<Link href="/teams">
|
||||
<Badge variant="gray">{t("upgrade")}</Badge>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
|
@ -1,2 +1,4 @@
|
|||
export { Badge } from "./Badge";
|
||||
export { UpgradeTeamsBadge } from "./UpgradeTeamsBadge";
|
||||
|
||||
export type { BadgeProps } from "./Badge";
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useRouter } from "next/router";
|
||||
import {
|
||||
components as reactSelectComponents,
|
||||
ControlProps,
|
||||
|
@ -13,11 +12,9 @@ import {
|
|||
} from "react-select";
|
||||
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
||||
import { Icon } from "../../../components/icon";
|
||||
import { Badge } from "../../badge";
|
||||
import { Tooltip } from "../../tooltip";
|
||||
import { UpgradeTeamsBadge } from "../../badge";
|
||||
|
||||
export const InputComponent = <
|
||||
Option,
|
||||
|
@ -53,9 +50,6 @@ export const OptionComponent = <
|
|||
className,
|
||||
...props
|
||||
}: OptionProps<Option, IsMulti, Group>) => {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<reactSelectComponents.Option
|
||||
{...props}
|
||||
|
@ -67,13 +61,7 @@ export const OptionComponent = <
|
|||
)}>
|
||||
<>
|
||||
<span className="mr-auto">{props.label}</span>
|
||||
{(props.data as unknown as ExtendedOption).needsUpgrade && (
|
||||
<Tooltip content={t("upgrade_to_enable_feature")}>
|
||||
<button type="button" onClick={() => router.replace("/teams")}>
|
||||
<Badge variant="gray">{t("upgrade")}</Badge>
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(props.data as unknown as ExtendedOption).needsUpgrade && <UpgradeTeamsBadge />}
|
||||
{props.isSelected && <Icon.FiCheck className="ml-2 h-4 w-4" />}
|
||||
</>
|
||||
</reactSelectComponents.Option>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export { Avatar, AvatarGroup } from "./avatar";
|
||||
export type { AvatarProps, AvatarGroupProps } from "./avatar";
|
||||
export { Badge } from "./badge";
|
||||
export { Badge, UpgradeTeamsBadge } from "./badge";
|
||||
export type { BadgeProps } from "./badge";
|
||||
export { Breadcrumb, BreadcrumbContainer, BreadcrumbItem } from "./breadcrumb";
|
||||
export { Button, LinkIconButton } from "./button";
|
||||
|
|
|
@ -2,6 +2,7 @@ export {
|
|||
Avatar,
|
||||
AvatarGroup,
|
||||
Badge,
|
||||
UpgradeTeamsBadge,
|
||||
Breadcrumb,
|
||||
BreadcrumbContainer,
|
||||
BreadcrumbItem,
|
||||
|
|
Loading…
Reference in New Issue