chore: remove deprecated code, Meta & MetaProvider (#19407)
* chore: remove deprecated code Meta, MetaProvider * fix type checks
This commit is contained in:
@@ -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">
|
||||
|
||||
+2
-3
@@ -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>
|
||||
|
||||
+2
-3
@@ -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,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 />
|
||||
|
||||
@@ -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 +0,0 @@
|
||||
export { default as Meta, MetaProvider, useMeta } from "./Meta";
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user