chore: remove deprecated code, Meta & MetaProvider (#19407)

* chore: remove deprecated code Meta, MetaProvider

* fix type checks
This commit is contained in:
Benny Joo
2025-02-21 09:01:44 -05:00
committed by GitHub
parent 829bb63eb9
commit c2be796a5b
13 changed files with 14 additions and 169 deletions
+1 -4
View File
@@ -17,7 +17,6 @@ import { OrgBrandingProvider } from "@calcom/features/ee/organizations/context/p
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
import { FeatureProvider } from "@calcom/features/flags/context/provider";
import { useFlags } from "@calcom/features/flags/hooks";
import { MetaProvider } from "@calcom/ui";
import useIsBookingPage from "@lib/hooks/useIsBookingPage";
import type { WithLocaleProps } from "@lib/withLocale";
@@ -303,9 +302,7 @@ const AppProviders = (props: AppPropsWithChildren) => {
isBookingPage={props.Component.isBookingPage || isBookingPage}
router={props.router}>
<FeatureFlagsProvider>
<OrgBrandProvider>
<MetaProvider>{props.children}</MetaProvider>
</OrgBrandProvider>
<OrgBrandProvider>{props.children}</OrgBrandProvider>
</FeatureFlagsProvider>
</CalcomThemeProvider>
</TooltipProvider>
@@ -11,7 +11,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, Dialog, DialogContent, EmptyScreen, SkeletonContainer, SkeletonText } from "@calcom/ui";
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
const SkeletonLoader = () => {
return (
<SkeletonContainer>
<div className="divide-subtle border-subtle space-y-6 rounded-b-lg border border-t-0 px-6 py-4">
@@ -64,12 +64,7 @@ const ApiKeysView = () => {
}, []);
if (isPending || !data) {
return (
<SkeletonLoader
title={t("api_keys")}
description={t("create_first_api_key_description", { appName: APP_NAME })}
/>
);
return <SkeletonLoader />;
}
return (
@@ -28,7 +28,6 @@ import {
DialogHeader,
DropdownMenuSeparator,
Form,
Meta,
SettingsToggle,
showToast,
TextAreaField,
@@ -761,7 +760,6 @@ function SingleForm({ form, appUrl, Page, enrichedWithUserProfileForm }: SingleF
appUrl={appUrl}
newFormDialogState={newFormDialogState}
setNewFormDialogState={setNewFormDialogState}>
<Meta title={form.name} description={form.description || ""} />
<ShellMain
heading={
<div className="flex">
@@ -7,7 +7,7 @@ import { z } from "zod";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, useMeta, showToast } from "@calcom/ui";
import { Button, showToast } from "@calcom/ui";
import { AttributeForm } from "./AttributesForm";
@@ -51,7 +51,6 @@ function CreateAttributesPage() {
}
function CreateAttributeHeader(props: { isPending: boolean }) {
const { meta } = useMeta();
const { t } = useLocale();
const formContext = useFormContext<FormValues>();
@@ -69,7 +68,7 @@ function CreateAttributeHeader(props: { isPending: boolean }) {
<span className="sr-only">{t("back_to_attributes")}</span>
</Button>
<div className="font-cal text-cal flex space-x-1 text-xl font-semibold leading-none">
<h1 className="text-emphasis">{meta.title || t("attribute")}</h1>
<h1 className="text-emphasis">{t("attribute")}</h1>
{watchedTitle && (
<>
<span className="text-subtle">/</span> <span className="text-emphasis">{watchedTitle}</span>
@@ -7,7 +7,7 @@ import { z } from "zod";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, useMeta, showToast } from "@calcom/ui";
import { Button, showToast } from "@calcom/ui";
import { AttributeForm } from "./AttributesForm";
@@ -73,7 +73,6 @@ function CreateAttributesPage() {
}
function EditAttributeHeader(props: { isPending: boolean }) {
const { meta } = useMeta();
const { t } = useLocale();
const formContext = useFormContext<FormValues>();
@@ -91,7 +90,7 @@ function EditAttributeHeader(props: { isPending: boolean }) {
<span className="sr-only">{t("back_to_attributes")}</span>
</Button>
<div className="font-cal text-cal flex space-x-1 text-xl font-semibold leading-none">
<h1 className="text-emphasis">{meta.title || t("attribute")}</h1>
<h1 className="text-emphasis">{t("attribute")}</h1>
{watchedTitle && (
<>
<span className="text-subtle">/</span> <span className="text-emphasis">{watchedTitle}</span>
@@ -57,7 +57,7 @@ type FormValues = {
calVideoLogo: string | null;
};
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
const SkeletonLoader = () => {
return (
<SkeletonContainer>
<div className="border-subtle space-y-6 rounded-b-xl border border-t-0 px-4 py-8">
@@ -101,7 +101,7 @@ const OrgProfileView = () => {
);
if (isPending || !orgBranding || !currentOrganisation) {
return <SkeletonLoader title={t("profile")} description={t("profile_org_description")} />;
return <SkeletonLoader />;
}
const isOrgAdminOrOwner =
@@ -4,12 +4,11 @@ import OIDCConnection from "@calcom/features/ee/sso/components/OIDCConnection";
import SAMLConnection from "@calcom/features/ee/sso/components/SAMLConnection";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Meta, Alert, SkeletonContainer, SkeletonText } from "@calcom/ui";
import { Alert, SkeletonContainer, SkeletonText } from "@calcom/ui";
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
const SkeletonLoader = () => {
return (
<SkeletonContainer>
<Meta title={title} description={description} borderInShellHeader={true} />
<div className="divide-subtle border-subtle space-y-6 rounded-b-xl border border-t-0 px-6 py-4">
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
@@ -25,17 +24,12 @@ export default function SSOConfiguration({ teamId }: { teamId: number | null })
const { data: connection, isPending, error } = trpc.viewer.saml.get.useQuery({ teamId });
if (isPending) {
return <SkeletonLoader title={t("sso_configuration")} description={t("sso_configuration_description")} />;
return <SkeletonLoader />;
}
if (error) {
return (
<>
<Meta
title={t("sso_configuration")}
description={t("sso_configuration_description")}
borderInShellHeader={true}
/>
<Alert severity="warning" message={t(error.message)} className="mt-4" />
</>
);
@@ -14,8 +14,7 @@ const SAMLSSO = () => {
const { data, status } = useSession();
const org = data?.user.org;
if (status === "loading")
<SkeletonLoader title={t("sso_saml_heading")} description={t("sso_configuration_description_orgs")} />;
if (status === "loading") <SkeletonLoader />;
if (!org) {
return null;
+1 -12
View File
@@ -1,21 +1,10 @@
import { ShellSubHeading } from "../layout";
import Meta from "../meta/Meta";
import { SkeletonText } from "../skeleton";
export function SkeletonLoader({
className,
title,
description,
}: {
className?: string;
title?: string;
description?: string;
}) {
export function SkeletonLoader({ className }: { className?: string }) {
return (
<>
<ShellSubHeading title={<div className="bg-subtle h-6 w-32" />} {...{ className }} />
{title && description && <Meta title={title} description={description} />}
<ul className="bg-default border-subtle divide-subtle -mx-4 animate-pulse divide-y rounded-md border sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
-69
View File
@@ -1,69 +0,0 @@
"use client";
import Head from "next/head";
import { createContext, useContext, useState, useEffect } from "react";
import type { ReactNode } from "react";
import { APP_NAME } from "@calcom/lib/constants";
type MetaType = {
title: string;
description: string;
backButton?: boolean;
CTA?: ReactNode;
borderInShellHeader?: boolean;
};
const initialMeta: MetaType = {
title: "",
description: "",
backButton: false,
CTA: null,
borderInShellHeader: true,
};
const MetaContext = createContext({
meta: initialMeta,
// eslint-disable-next-line @typescript-eslint/no-empty-function
setMeta: (_newMeta: Partial<MetaType>) => {},
});
export function useMeta() {
return useContext(MetaContext);
}
export function MetaProvider({ children }: { children: ReactNode }) {
const [value, setValue] = useState(initialMeta);
const setMeta = (newMeta: Partial<MetaType>) => {
setValue((v) => ({ ...v, ...newMeta }));
};
return <MetaContext.Provider value={{ meta: value, setMeta }}>{children}</MetaContext.Provider>;
}
/**
* The purpose of this component is to simplify title and description handling.
* Similarly to `next/head`'s `Head` component this allow us to update the metadata for a page
* from any children, also exposes the metadata via the `useMeta` hook in case we need them
* elsewhere (ie. on a Heading, Title, Subtitle, etc.)
* @example <Meta title="Password" description="Manage settings for your account passwords" />
*/
export default function Meta({ title, description, backButton, CTA, borderInShellHeader }: MetaType) {
const { setMeta, meta } = useMeta();
/* @TODO: maybe find a way to have this data on first render to prevent flicker */
useEffect(() => {
if (meta.title !== title || meta.description !== description || meta.CTA !== CTA) {
setMeta({ title, description, backButton, CTA, borderInShellHeader });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [title, description, backButton, CTA]);
const title_ = `${title} | ${APP_NAME}`;
return (
<Head>
<title>{title_}</title>
<meta name="description" content={description} />
</Head>
);
}
-1
View File
@@ -1 +0,0 @@
export { default as Meta, MetaProvider, useMeta } from "./Meta";
-54
View File
@@ -1,54 +0,0 @@
import { render } from "@testing-library/react";
import { vi } from "vitest";
import Meta, { useMeta } from "./Meta";
vi.mock("./Meta", async () => {
const actualMeta = (await vi.importActual("./Meta")) as object;
const MockMeta = ({ title, description }: { title: string; description: string }) => (
<div>
<h1>{title}</h1>
<p>{description}</p>
</div>
);
type MetaProviderProps = {
children: React.ReactNode;
};
return {
...actualMeta,
default: MockMeta,
useMeta: vi.fn(),
MetaProvider: ({ children }: MetaProviderProps) => children,
};
});
describe("Meta Component", () => {
test("Should render with default metadata", () => {
(useMeta as jest.Mock).mockReturnValue({
meta: { title: "", description: "", backButton: false, CTA: null },
});
const { getByText } = render(<Meta title="Page Title" description="Page Description" />);
expect(getByText("Page Title")).toBeInTheDocument();
expect(getByText("Page Description")).toBeInTheDocument();
});
test("Should update metadata when props change", () => {
(useMeta as jest.Mock).mockReturnValue({
meta: { title: "", description: "", backButton: false, CTA: null },
});
const { rerender, getByText } = render(<Meta title="Page Title" description="Page Description" />);
expect(getByText("Page Title")).toBeInTheDocument();
expect(getByText("Page Description")).toBeInTheDocument();
rerender(<Meta title="New Title" description="New Description" />);
expect(getByText("New Title")).toBeInTheDocument();
expect(getByText("New Description")).toBeInTheDocument();
});
});
-1
View File
@@ -124,7 +124,6 @@ export { AppListCard } from "./components/app-list-card";
export { DisconnectIntegrationComponent } from "./components/disconnect-calendar-integration";
export { CalendarSwitchComponent } from "./components/calendar-switch";
export { showToast, ErrorToast, SuccessToast, WarningToast } from "./components/toast"; // We don't export the toast components as they are only used in local storybook file
export { Meta, MetaProvider, useMeta } from "./components/meta";
export { ShellSubHeading } from "./components/layout";
/** ⬇️ TODO - Move these to components */