2022-08-30 19:46:52 +00:00
|
|
|
import Head from "next/head";
|
2023-04-19 18:24:34 +00:00
|
|
|
import { createContext, useContext, useState, useEffect } from "react";
|
|
|
|
import type { ReactNode } from "react";
|
2022-08-30 19:46:52 +00:00
|
|
|
|
2023-01-04 22:14:46 +00:00
|
|
|
import { APP_NAME } from "@calcom/lib/constants";
|
|
|
|
|
2022-08-30 19:46:52 +00:00
|
|
|
type MetaType = {
|
|
|
|
title: string;
|
|
|
|
description: string;
|
2022-09-12 19:07:52 +00:00
|
|
|
backButton?: boolean;
|
2023-04-19 18:24:34 +00:00
|
|
|
CTA?: ReactNode;
|
2022-08-30 19:46:52 +00:00
|
|
|
};
|
|
|
|
|
2022-10-20 10:03:39 +00:00
|
|
|
const initialMeta: MetaType = {
|
2022-08-30 19:46:52 +00:00
|
|
|
title: "",
|
|
|
|
description: "",
|
2022-09-12 19:07:52 +00:00
|
|
|
backButton: false,
|
2022-10-20 10:03:39 +00:00
|
|
|
CTA: null,
|
2022-08-30 19:46:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const MetaContext = createContext({
|
|
|
|
meta: initialMeta,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
|
|
setMeta: (newMeta: Partial<MetaType>) => {},
|
|
|
|
});
|
|
|
|
|
|
|
|
export function useMeta() {
|
|
|
|
return useContext(MetaContext);
|
|
|
|
}
|
|
|
|
|
2023-04-19 18:24:34 +00:00
|
|
|
export function MetaProvider({ children }: { children: ReactNode }) {
|
2022-08-30 19:46:52 +00:00
|
|
|
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" />
|
|
|
|
*/
|
2022-10-20 10:03:39 +00:00
|
|
|
export default function Meta({ title, description, backButton, CTA }: MetaType) {
|
2022-08-30 19:46:52 +00:00
|
|
|
const { setMeta, meta } = useMeta();
|
2022-09-15 16:59:48 +00:00
|
|
|
|
2022-08-30 19:46:52 +00:00
|
|
|
/* @TODO: maybe find a way to have this data on first render to prevent flicker */
|
2022-09-15 16:59:48 +00:00
|
|
|
useEffect(() => {
|
2022-12-19 17:53:46 +00:00
|
|
|
if (meta.title !== title || meta.description !== description || meta.CTA !== CTA) {
|
2022-10-20 10:03:39 +00:00
|
|
|
setMeta({ title, description, backButton, CTA });
|
2022-09-15 16:59:48 +00:00
|
|
|
}
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2022-10-20 10:03:39 +00:00
|
|
|
}, [title, description, backButton, CTA]);
|
2022-08-30 19:46:52 +00:00
|
|
|
|
2023-01-06 17:35:32 +00:00
|
|
|
const title_ = `${title} | ${APP_NAME}`;
|
2022-08-30 19:46:52 +00:00
|
|
|
return (
|
|
|
|
<Head>
|
2023-01-06 17:35:32 +00:00
|
|
|
<title>{title_}</title>
|
2022-09-14 09:42:48 +00:00
|
|
|
<meta name="description" content={description} />
|
2022-08-30 19:46:52 +00:00
|
|
|
</Head>
|
|
|
|
);
|
|
|
|
}
|