From e05da237d751fd847ca6658745a2a76ca908921e Mon Sep 17 00:00:00 2001 From: Shankar Ambady Date: Fri, 20 Sep 2024 09:32:44 -0400 Subject: [PATCH] Reinstate head metadata (#1572) * adding metadata to channel details page * refactor * refactor * switching to using site name * switching to using site name * adding site name * adding site name * removing comment * using getMetadataAsync for open resource drawer * switching to getMetaData * import missing var * fixing search page title and edit channel details title * removing unused attr * removing redundant metatag call * removing comment * fixing regression with settings tabs * adding more titles and fixing regression on search page * fixing missing import * missing import * adding site name * adding site name * removing conditional * moving addition of site name to getMetaData * adding docstrings * refactoring metatag method * switching to standardizeMetadata and refactoring all views to use async method * removign wrapper fragment * set single react types resolution (#1586) * switching to standardizeMetadata method * fixing typechecks --------- Co-authored-by: Chris Chudzicki --- .../ChannelPage/DefaultChannelTemplate.tsx | 1 - .../app-pages/DashboardPage/DashboardPage.tsx | 2 +- .../ListDetailsPage.tsx | 4 +-- .../OnboardingPage/OnboardingPage.tsx | 1 - frontends/main/src/app/about/page.tsx | 5 +-- .../src/app/c/[channelType]/[name]/page.tsx | 28 ++++++++++++++++ .../src/app/dashboard/[tab]/[id]/page.tsx | 8 +++++ .../main/src/app/dashboard/[tab]/page.tsx | 7 ++++ frontends/main/src/app/dashboard/page.tsx | 5 ++- frontends/main/src/app/departments/page.tsx | 4 +-- frontends/main/src/app/learningpaths/page.tsx | 6 ++++ frontends/main/src/app/onboarding/page.tsx | 4 +-- frontends/main/src/app/privacy/page.tsx | 6 ++-- frontends/main/src/app/search/page.tsx | 16 +++++++--- frontends/main/src/app/terms/page.tsx | 6 ++-- frontends/main/src/app/topics/page.tsx | 4 +-- frontends/main/src/app/units/page.tsx | 6 ++-- frontends/main/src/common/metadata.ts | 18 +++++++---- .../main/src/components/MetaTags/MetaTags.tsx | 32 ------------------- .../components/PrivateTitle/PrivateTitle.tsx | 15 +++++++++ .../src/pages/ChannelPage/EditChannelPage.tsx | 5 ++- 21 files changed, 112 insertions(+), 71 deletions(-) delete mode 100644 frontends/main/src/components/MetaTags/MetaTags.tsx create mode 100644 frontends/main/src/components/PrivateTitle/PrivateTitle.tsx diff --git a/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx b/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx index ea11734c1f..016706a0ce 100644 --- a/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx +++ b/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx @@ -60,7 +60,6 @@ const DefaultChannelTemplate: React.FC = ({ const displayConfiguration = channel.data?.configuration return ( <> - {/* TODO */} { const { isLoading: isLoadingProfile, data: profile } = useProfileMeQuery() const params = useParams<{ tab: string }>() - const appRouterPath = `${DASHBOARD_HOME}${params.tab}/` + const appRouterPath = `${DASHBOARD_HOME}/${params.tab}` const id = Number(useParams().id) || -1 const showUserListDetail = appRouterPath === MY_LISTS && id !== -1 diff --git a/frontends/main/src/app-pages/LearningPathDetailsPage/ListDetailsPage.tsx b/frontends/main/src/app-pages/LearningPathDetailsPage/ListDetailsPage.tsx index 43685b46f1..9635b3055c 100644 --- a/frontends/main/src/app-pages/LearningPathDetailsPage/ListDetailsPage.tsx +++ b/frontends/main/src/app-pages/LearningPathDetailsPage/ListDetailsPage.tsx @@ -1,6 +1,6 @@ import React from "react" import { Container, BannerPage, styled } from "ol-components" -// import MetaTags from "@/page-components/MetaTags/MetaTags" +import PrivateTitle from "@/components/PrivateTitle/PrivateTitle" import ItemsListingComponent from "@/page-components/ItemsListing/ItemsListingComponent" import type { ItemsListingComponentProps } from "@/page-components/ItemsListing/ItemsListingComponent" @@ -23,7 +23,7 @@ const ListDetailsPage: React.FC = ({ src="/images/backgrounds/course_search_banner.png" className="learningpaths-page" > - {/* TODO */} + res.data) + return getMetadataAsync({ + searchParams, + title: `${channelDetails.title}`, + description: channelDetails.public_description, + image: channelDetails.configuration.logo, + }) +} const Page: React.FC = () => { return diff --git a/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx b/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx index ece6a5603b..6cfd91673f 100644 --- a/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx +++ b/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx @@ -1,6 +1,14 @@ import React from "react" import DashboardPage from "@/app-pages/DashboardPage/DashboardPage" +import { Metadata } from "next" +import { standardizeMetadata } from "@/common/metadata" + +export const metadata: Metadata = standardizeMetadata({ + title: "Your MIT Learning Journey", + social: false, +}) + const Page: React.FC = () => { return } diff --git a/frontends/main/src/app/dashboard/[tab]/page.tsx b/frontends/main/src/app/dashboard/[tab]/page.tsx index ece6a5603b..d89e7d5b3e 100644 --- a/frontends/main/src/app/dashboard/[tab]/page.tsx +++ b/frontends/main/src/app/dashboard/[tab]/page.tsx @@ -1,6 +1,13 @@ import React from "react" import DashboardPage from "@/app-pages/DashboardPage/DashboardPage" +import { Metadata } from "next" +import { standardizeMetadata } from "@/common/metadata" + +export const metadata: Metadata = standardizeMetadata({ + title: "Your MIT Learning Journey", + social: false, +}) const Page: React.FC = () => { return } diff --git a/frontends/main/src/app/dashboard/page.tsx b/frontends/main/src/app/dashboard/page.tsx index 274fb49292..05c7f8aefc 100644 --- a/frontends/main/src/app/dashboard/page.tsx +++ b/frontends/main/src/app/dashboard/page.tsx @@ -1,9 +1,8 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" import DashboardPage from "@/app-pages/DashboardPage/DashboardPage" - -export const metadata: Metadata = getMetadata({ +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ title: "Your MIT Learning Journey", social: false, }) diff --git a/frontends/main/src/app/departments/page.tsx b/frontends/main/src/app/departments/page.tsx index 4dfd8e6ca7..41364044ee 100644 --- a/frontends/main/src/app/departments/page.tsx +++ b/frontends/main/src/app/departments/page.tsx @@ -1,8 +1,8 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" -export const metadata: Metadata = getMetadata({ +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ title: "Departments", }) diff --git a/frontends/main/src/app/learningpaths/page.tsx b/frontends/main/src/app/learningpaths/page.tsx index ce29d8baad..2ecf26fa1f 100644 --- a/frontends/main/src/app/learningpaths/page.tsx +++ b/frontends/main/src/app/learningpaths/page.tsx @@ -1,6 +1,12 @@ import React from "react" import LearningPathListingPage from "@/app-pages/LearningPathListingPage/LearningPathListingPage" +import { Metadata } from "next" +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ + title: "Learning Paths", +}) + const Page: React.FC = () => { return } diff --git a/frontends/main/src/app/onboarding/page.tsx b/frontends/main/src/app/onboarding/page.tsx index 729c526251..ddf07d6d21 100644 --- a/frontends/main/src/app/onboarding/page.tsx +++ b/frontends/main/src/app/onboarding/page.tsx @@ -1,9 +1,9 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" import OnboardingPage from "@/app-pages/OnboardingPage/OnboardingPage" +import { standardizeMetadata } from "@/common/metadata" -export const metadata: Metadata = getMetadata({ +export const metadata: Metadata = standardizeMetadata({ title: "Onboarding", social: false, }) diff --git a/frontends/main/src/app/privacy/page.tsx b/frontends/main/src/app/privacy/page.tsx index bdc1b095ee..bea7709610 100644 --- a/frontends/main/src/app/privacy/page.tsx +++ b/frontends/main/src/app/privacy/page.tsx @@ -1,9 +1,9 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" -import PrivacyPage from "@/app-pages/PrivacyPage/PrivacyPage" -export const metadata: Metadata = getMetadata({ +import PrivacyPage from "@/app-pages/PrivacyPage/PrivacyPage" +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ title: "Privacy Policy", }) diff --git a/frontends/main/src/app/search/page.tsx b/frontends/main/src/app/search/page.tsx index 5ee825afa2..50ca9c295a 100644 --- a/frontends/main/src/app/search/page.tsx +++ b/frontends/main/src/app/search/page.tsx @@ -1,11 +1,17 @@ import React, { Suspense } from "react" -import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" +import { getMetadataAsync } from "@/common/metadata" import SearchPage from "@/app-pages/SearchPage/SearchPage" -export const metadata: Metadata = getMetadata({ - title: "Search", -}) +export async function generateMetadata({ + searchParams, +}: { + searchParams: { [key: string]: string | string[] | undefined } +}) { + return await getMetadataAsync({ + title: "Search", + searchParams, + }) +} const Page: React.FC = () => { return ( diff --git a/frontends/main/src/app/terms/page.tsx b/frontends/main/src/app/terms/page.tsx index 1185db30ce..67c45a73be 100644 --- a/frontends/main/src/app/terms/page.tsx +++ b/frontends/main/src/app/terms/page.tsx @@ -1,9 +1,9 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" -import TermsPage from "@/app-pages/TermsPage/TermsPage" -export const metadata: Metadata = getMetadata({ +import TermsPage from "@/app-pages/TermsPage/TermsPage" +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ title: "Terms of Service", }) diff --git a/frontends/main/src/app/topics/page.tsx b/frontends/main/src/app/topics/page.tsx index 655793d3d1..abbbfc7a66 100644 --- a/frontends/main/src/app/topics/page.tsx +++ b/frontends/main/src/app/topics/page.tsx @@ -1,8 +1,8 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" -export const metadata: Metadata = getMetadata({ +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ title: "Topics", }) diff --git a/frontends/main/src/app/units/page.tsx b/frontends/main/src/app/units/page.tsx index 51c8a33553..1f1a535933 100644 --- a/frontends/main/src/app/units/page.tsx +++ b/frontends/main/src/app/units/page.tsx @@ -1,9 +1,9 @@ import React from "react" import { Metadata } from "next" -import { getMetadata } from "@/common/metadata" -import UnitsListingPage from "@/app-pages/UnitsListingPage/UnitsListingPage" -export const metadata: Metadata = getMetadata({ +import UnitsListingPage from "@/app-pages/UnitsListingPage/UnitsListingPage" +import { standardizeMetadata } from "@/common/metadata" +export const metadata: Metadata = standardizeMetadata({ title: "Units", }) diff --git a/frontends/main/src/common/metadata.ts b/frontends/main/src/common/metadata.ts index c80be4202e..1dfa0032ff 100644 --- a/frontends/main/src/common/metadata.ts +++ b/frontends/main/src/common/metadata.ts @@ -12,6 +12,10 @@ type MetadataAsyncProps = { social?: boolean } +/* + * Fetch metadata for the current page. + * the method handles resource param override if necessary. + */ export const getMetadataAsync = async ({ title = "MIT Learn", description = "Learn with MIT", @@ -20,8 +24,6 @@ export const getMetadataAsync = async ({ searchParams, social = true, }: MetadataAsyncProps) => { - title = `${title} | ${process.env.NEXT_PUBLIC_SITE_NAME}` - // The learning resource drawer is open const learningResourceId = searchParams?.[RESOURCE_DRAWER_QUERY_PARAM] if (learningResourceId) { @@ -30,7 +32,7 @@ export const getMetadataAsync = async ({ id: Number(learningResourceId), }) - title = `${data?.title} | ${process.env.NEXT_PUBLIC_SITE_NAME}` + title = data?.title description = data?.description?.replace(/<\/[^>]+(>|$)/g, "") ?? "" image = data?.image?.url || image imageAlt = image === data?.image?.url ? imageAlt : data?.image?.alt || "" @@ -42,7 +44,7 @@ export const getMetadataAsync = async ({ } } - return getMetadata({ + return standardizeMetadata({ title, description, image, @@ -53,19 +55,23 @@ export const getMetadataAsync = async ({ type MetadataProps = Omit -export const getMetadata = ({ +/* + * Method that returns standardized metadata including + * social tags for the current page + */ +export const standardizeMetadata = ({ title = "MIT Learn", description = "Learn with MIT", image = DEFAULT_OG_IMAGE, imageAlt, social = true, }: MetadataProps) => { + title = `${title} | ${process.env.NEXT_PUBLIC_SITE_NAME}` const socialMetadata = social ? { openGraph: { title, description, - // url: process.env.NEXT_PUBLIC_ORIGIN, siteName: process.env.NEXT_PUBLIC_SITE_NAME, images: [ { diff --git a/frontends/main/src/components/MetaTags/MetaTags.tsx b/frontends/main/src/components/MetaTags/MetaTags.tsx deleted file mode 100644 index 11923abad4..0000000000 --- a/frontends/main/src/components/MetaTags/MetaTags.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react" -// import { Helmet } from "react-helmet-async" -import Head from "next/head" - -type MetaTagsProps = { - title?: string | string[] - canonicalLink?: string - children?: React.ReactNode -} - -/** - * Renders a Next.js head component to customize meta tags - */ -const MetaTags: React.FC = ({ - title, - children, - canonicalLink, -}) => { - title = title ? (Array.isArray(title) ? title : [title]) : [] - - return ( - - {[...title, process.env.NEXT_PUBLIC_SITE_NAME].join(" | ")} - {children} - {canonicalLink ? ( - - ) : null} - - ) -} - -export default MetaTags diff --git a/frontends/main/src/components/PrivateTitle/PrivateTitle.tsx b/frontends/main/src/components/PrivateTitle/PrivateTitle.tsx new file mode 100644 index 0000000000..3d0bb6e37a --- /dev/null +++ b/frontends/main/src/components/PrivateTitle/PrivateTitle.tsx @@ -0,0 +1,15 @@ +import React from "react" + +/** + * Alert! Prefer the nextjs [metadata api](https://nextjs.org/docs/app/building-your-application/optimizing/metadata) + * This is intended for rendering titles that require authentication and hence + * can't be rendered on our nextjs server. + * + * Render a title tag. Will be hoisted to by React. + * See [title](https://react.dev/reference/react-dom/components/title) + */ +const PrivateTitle: React.FC<{ title: string }> = ({ title }) => { + return {[title, process.env.NEXT_PUBLIC_SITE_NAME].join(" | ")} +} + +export default PrivateTitle diff --git a/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx b/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx index a080047734..d14a17596c 100644 --- a/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx +++ b/frontends/mit-learn/src/pages/ChannelPage/EditChannelPage.tsx @@ -4,13 +4,12 @@ import { useRouter, useLocation, useParams } from "next/navigation" import Link from "next/link" import { Container, TabList, Tab, TabContext, TabPanel } from "ol-components" -// import { MetaTags } from "ol-utilities" - import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout" import { useChannelDetail } from "api/hooks/channels" import EditChannelAppearanceForm from "./EditChannelAppearanceForm" import { ChannelPageTemplate } from "./ChannelPageTemplate" import MetaTags from "@/page-components/MetaTags/MetaTags" + type RouteParams = { channelType: string name: string @@ -41,7 +40,7 @@ const EditChannelPage: React.FC = () => { name={channel.data?.name} channelType={channel.data?.channel_type} > - {/* TODO */} + {channel.data.is_moderator ? (