* update env vars * update middleware * remove pages router and move pages to /app * move to /team * update imports * fix * remove pages router and move org pages to /app * wip * fix orgSlug/user pages * fix orgSlug/user/type pages * remove generateMetadata from embed pages * fix * remove pages router for /user pages * generateMetadata is not needed in embed pages * remove future/org * no layout in [user] page * simplify * fix * fix OG image for [user] * fix OG images for org/user and team/slug * fix OG images for booking page * fix all metadata * use isBrandingHidden * remove BookerSeo and its usages * rename excludeAppNameFromTitle -> hideBranding * remove logic for meeting type in HeadSeo * remove BookerSeo instances from team-view and users-public-view * create generateMeetingMetadata util and use it to reduce duplicate code * remove BookerSeo imports * fix spacing * remove constructMeetingImage mock from head-seo.test * fetch avatarUrl using user id for user page metadata * fix test * remove unused test cases * index and follow must be true by default * invert noindex/nofollow flags * remove HeadSeo for already migrated pages and refactor prepareMetadata * fix organization-settings.e2e.ts * fix order * enable parallel test execution for dynamic-booking e2e test * fix * + could be %2B in app router * refactor handling logic for embeds in app router * fix isEmbed * fix embed-core * remove dead code * move embed pages back to /future * add back embed pages in pages router * revert some changes * fix import type checks * simplify * fix * feat: Implement generateBookingPageMetadata function for improved SEO and metadata handling across user and event pages (#18440) - Added a new utility function `generateBookingPageMetadata` to streamline the generation of metadata for booking and user profile pages. - Updated multiple page components to utilize the new function, enhancing SEO indexing and metadata consistency. - Removed redundant code related to previous metadata generation methods, improving code clarity and maintainability. * fix dirs * Pr-review-fixes-app-router-team-pages (#18450) * Remove unnecessary getPublicEvent call * Remove unused variable * Fix 404 for team page (#18451) * Remove console log --------- Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
152 lines
3.9 KiB
TypeScript
152 lines
3.9 KiB
TypeScript
import type { TFunction } from "next-i18next";
|
|
|
|
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
|
|
|
|
import { generateMeetingMetadata } from "./_utils";
|
|
|
|
type MetadataPayload = {
|
|
title: (t: TFunction) => string;
|
|
description: (t: TFunction) => string;
|
|
meeting: {
|
|
title: string;
|
|
profile: { name: string; image: string };
|
|
users?: { name: string; username: string }[];
|
|
};
|
|
robots: {
|
|
index: boolean;
|
|
follow: boolean;
|
|
};
|
|
};
|
|
|
|
type UserProfilePageProfile = {
|
|
name: string | null;
|
|
username: string | null;
|
|
image: string | null;
|
|
markdownStrippedBio: string | null | undefined;
|
|
};
|
|
|
|
type TeamProfilePageProfile = {
|
|
teamName: string | null;
|
|
image: string | null;
|
|
markdownStrippedBio: string | null | undefined;
|
|
};
|
|
|
|
type EventBookingPageProfile = { name: string; image: string };
|
|
type BaseMetadataArgs = {
|
|
hideBranding: boolean;
|
|
orgSlug: string | null;
|
|
isSEOIndexable: boolean;
|
|
isReschedule?: boolean;
|
|
};
|
|
|
|
type TeamProfilePageArgs = BaseMetadataArgs & {
|
|
profile: TeamProfilePageProfile;
|
|
event: null;
|
|
};
|
|
|
|
type UserProfilePageArgs = BaseMetadataArgs & {
|
|
profile: UserProfilePageProfile;
|
|
event: null;
|
|
};
|
|
|
|
type EventBookingPageArgs = BaseMetadataArgs & {
|
|
profile: EventBookingPageProfile;
|
|
event: {
|
|
title: string;
|
|
hidden: boolean;
|
|
users: { name: string | null; username: string | null }[];
|
|
};
|
|
};
|
|
|
|
export const generateEventBookingPageMetadata = async (props: EventBookingPageArgs) => {
|
|
const { profile, isReschedule, hideBranding, orgSlug, isSEOIndexable, event } = props;
|
|
const fullOrigin = getOrgFullOrigin(orgSlug);
|
|
|
|
const payload: MetadataPayload = {
|
|
title: (t) => `${isReschedule ? t("reschedule") : ""} ${event.title} | ${profile.name}`,
|
|
description: (t) => `${isReschedule ? t("reschedule") : ""} ${event.title}`,
|
|
meeting: {
|
|
title: event.title,
|
|
profile: { name: profile.name, image: profile.image },
|
|
users: event.users.map((user) => ({
|
|
name: `${user.name}`,
|
|
username: `${user.username}`,
|
|
})),
|
|
},
|
|
robots: {
|
|
index: !(event.hidden || !isSEOIndexable),
|
|
follow: !(event.hidden || !isSEOIndexable),
|
|
},
|
|
};
|
|
|
|
return {
|
|
...(await generateMeetingMetadata(
|
|
payload.meeting,
|
|
payload.title,
|
|
payload.description,
|
|
hideBranding,
|
|
fullOrigin
|
|
)),
|
|
robots: payload.robots,
|
|
};
|
|
};
|
|
|
|
export const generateUserProfilePageMetadata = async (props: UserProfilePageArgs) => {
|
|
const { profile, hideBranding, orgSlug, isSEOIndexable } = props;
|
|
const fullOrigin = getOrgFullOrigin(orgSlug);
|
|
|
|
const payload: MetadataPayload = {
|
|
title: () => profile.name ?? "",
|
|
description: () => profile.markdownStrippedBio ?? "",
|
|
meeting: {
|
|
title: profile.markdownStrippedBio ?? "",
|
|
profile: { name: profile.name ?? "", image: profile.image ?? "" },
|
|
users: [{ name: profile.name ?? "", username: profile.username ?? "" }],
|
|
},
|
|
robots: {
|
|
index: isSEOIndexable,
|
|
follow: isSEOIndexable,
|
|
},
|
|
};
|
|
|
|
return {
|
|
...(await generateMeetingMetadata(
|
|
payload.meeting,
|
|
payload.title,
|
|
payload.description,
|
|
hideBranding,
|
|
fullOrigin
|
|
)),
|
|
robots: payload.robots,
|
|
};
|
|
};
|
|
|
|
export const generateTeamProfilePageMetadata = async (props: TeamProfilePageArgs) => {
|
|
const { profile, hideBranding, orgSlug, isSEOIndexable } = props;
|
|
const fullOrigin = getOrgFullOrigin(orgSlug);
|
|
|
|
const payload: MetadataPayload = {
|
|
title: (t) => profile.teamName || t("nameless_team"),
|
|
description: () => profile.markdownStrippedBio ?? "",
|
|
meeting: {
|
|
title: profile.markdownStrippedBio ?? "",
|
|
profile: { name: `${profile.teamName}`, image: profile.image ?? "" },
|
|
},
|
|
robots: {
|
|
index: isSEOIndexable,
|
|
follow: isSEOIndexable,
|
|
},
|
|
};
|
|
|
|
return {
|
|
...(await generateMeetingMetadata(
|
|
payload.meeting,
|
|
payload.title,
|
|
payload.description,
|
|
hideBranding,
|
|
fullOrigin
|
|
)),
|
|
robots: payload.robots,
|
|
};
|
|
};
|