diff --git a/frontend/src/app/[locale]/newsletter/confirmation/page.tsx b/frontend/src/app/[locale]/newsletter/confirmation/page.tsx index 060dcb6395..e621b610a7 100644 --- a/frontend/src/app/[locale]/newsletter/confirmation/page.tsx +++ b/frontend/src/app/[locale]/newsletter/confirmation/page.tsx @@ -8,19 +8,18 @@ import PageSEO from "src/components/PageSEO"; import BetaAlert from "src/components/BetaAlert"; import { useTranslations } from "next-intl"; import { Metadata } from "next"; +import { getTranslations } from "next-intl/server"; -export function generateMetadata() { - // TODO: Enable once [locale] folder created, see: https://next-intl-docs.vercel.app/docs/getting-started/app-router/with-i18n-routing - // const t = await getTranslations({ locale: "en" }); +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); const meta: Metadata = { - // title: t("Newsletter.page_title"), - title: "Newsletter Confirmation | Simpler.Grants.gov", - description: - "A one‑stop shop for all federal discretionary funding to make it easy for you to discover, understand, and apply for opportunities.", + title: t("Newsletter.page_title"), + description: t("Index.meta_description"), }; return meta; } + export default function NewsletterConfirmation() { const t = useTranslations("Newsletter_confirmation"); diff --git a/frontend/src/app/[locale]/newsletter/page.tsx b/frontend/src/app/[locale]/newsletter/page.tsx index 3830f64d92..080aaed5a2 100644 --- a/frontend/src/app/[locale]/newsletter/page.tsx +++ b/frontend/src/app/[locale]/newsletter/page.tsx @@ -7,20 +7,18 @@ import PageSEO from "src/components/PageSEO"; import BetaAlert from "src/components/BetaAlert"; import NewsletterForm from "src/app/[locale]/newsletter/NewsletterForm"; import { Metadata } from "next"; +import { getTranslations } from "next-intl/server"; import { useTranslations, useMessages, NextIntlClientProvider, } from "next-intl"; -export function generateMetadata() { - // TODO: Enable once [locale] folder created, see: https://next-intl-docs.vercel.app/docs/getting-started/app-router/with-i18n-routing - // const t = await getTranslations({ locale: "en" }); +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); const meta: Metadata = { - // title: t("Newsletter.page_title"), - title: "Newsletter | Simpler.Grants.gov", - description: - "A one‑stop shop for all federal discretionary funding to make it easy for you to discover, understand, and apply for opportunities.", + title: t("Newsletter.page_title"), + description: t("Index.meta_description"), }; return meta; diff --git a/frontend/src/app/[locale]/newsletter/unsubscribe/page.tsx b/frontend/src/app/[locale]/newsletter/unsubscribe/page.tsx index 122f8f4790..9a095211ae 100644 --- a/frontend/src/app/[locale]/newsletter/unsubscribe/page.tsx +++ b/frontend/src/app/[locale]/newsletter/unsubscribe/page.tsx @@ -8,15 +8,13 @@ import PageSEO from "src/components/PageSEO"; import BetaAlert from "src/components/BetaAlert"; import { useTranslations } from "next-intl"; import { Metadata } from "next"; +import { getTranslations } from "next-intl/server"; -export function generateMetadata() { - // TODO: Enable once [locale] folder created, see: https://next-intl-docs.vercel.app/docs/getting-started/app-router/with-i18n-routing - // const t = await getTranslations({ locale: "en" }); +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); const meta: Metadata = { - // title: t("Newsletter.page_title"), - title: "Newsletter | Simpler.Grants.gov", - description: - "A one‑stop shop for all federal discretionary funding to make it easy for you to discover, understand, and apply for opportunities.", + title: t("Newsletter.page_title"), + description: t("Index.meta_description"), }; return meta; diff --git a/frontend/src/app/[locale]/page.tsx b/frontend/src/app/[locale]/page.tsx index 29633cfc7d..795c8d84d1 100644 --- a/frontend/src/app/[locale]/page.tsx +++ b/frontend/src/app/[locale]/page.tsx @@ -5,19 +5,17 @@ import IndexGoalContent from "src/components/content/IndexGoalContent"; import ProcessAndResearchContent from "src/components/content/ProcessAndResearchContent"; import { Metadata } from "next"; import { useTranslations } from "next-intl"; +import { getTranslations } from "next-intl/server"; -export function generateMetadata() { - // TODO: Enable once [locale] folder created, see: https://next-intl-docs.vercel.app/docs/getting-started/app-router/with-i18n-routing - // const t = await getTranslations({ locale: "en" }); +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); const meta: Metadata = { - // title: t("Research.page_title"), - title: "Simpler.Grants.gov", - description: - "A one‑stop shop for all federal discretionary funding to make it easy for you to discover, understand, and apply for opportunities.", + title: t("Index.page_title"), + description: t("Index.meta_description"), }; - return meta; } + export default function Home() { const t = useTranslations("Index"); diff --git a/frontend/src/app/[locale]/process/page.tsx b/frontend/src/app/[locale]/process/page.tsx index c0a8a0f427..788627afa2 100644 --- a/frontend/src/app/[locale]/process/page.tsx +++ b/frontend/src/app/[locale]/process/page.tsx @@ -9,17 +9,14 @@ import ProcessIntro from "src/app/[locale]/process/ProcessIntro"; import ProcessInvolved from "src/app/[locale]/process/ProcessInvolved"; import ProcessMilestones from "src/app/[locale]/process/ProcessMilestones"; import { useTranslations } from "next-intl"; +import { getTranslations } from "next-intl/server"; -export function generateMetadata() { - // TODO: Enable once [locale] folder created, see: https://next-intl-docs.vercel.app/docs/getting-started/app-router/with-i18n-routing - // const t = await getTranslations({ locale: "en" }); +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); const meta: Metadata = { - // title: t("Process.page_title"), - title: "Process | Simpler.Grants.gov", - description: - "A one‑stop shop for all federal discretionary funding to make it easy for you to discover, understand, and apply for opportunities.", + title: t("Process.page_title"), + description: t("Process.meta_description"), }; - return meta; } diff --git a/frontend/src/app/[locale]/research/page.tsx b/frontend/src/app/[locale]/research/page.tsx index bae9903b69..b6fc950768 100644 --- a/frontend/src/app/[locale]/research/page.tsx +++ b/frontend/src/app/[locale]/research/page.tsx @@ -10,19 +10,17 @@ import ResearchMethodology from "src/app/[locale]/research/ResearchMethodology"; import ResearchThemes from "src/app/[locale]/research/ResearchThemes"; import { Metadata } from "next"; import { useTranslations } from "next-intl"; +import { getTranslations } from "next-intl/server"; -export function generateMetadata() { - // TODO: Enable once [locale] folder created, see: https://next-intl-docs.vercel.app/docs/getting-started/app-router/with-i18n-routing - // const t = await getTranslations({ locale: "en" }); +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); const meta: Metadata = { - // title: t("Research.page_title"), - title: "Research | Simpler.Grants.gov", - description: - "A one‑stop shop for all federal discretionary funding to make it easy for you to discover, understand, and apply for opportunities.", + title: t("Research.page_title"), + description: t("Research.meta_description"), }; - return meta; } + export default function Research() { const t = useTranslations("Research"); diff --git a/frontend/src/app/[locale]/search/page.tsx b/frontend/src/app/[locale]/search/page.tsx index cdbf999d78..36cb75ef4e 100644 --- a/frontend/src/app/[locale]/search/page.tsx +++ b/frontend/src/app/[locale]/search/page.tsx @@ -25,10 +25,11 @@ export async function generateMetadata() { const t = await getTranslations({ locale: "en" }); const meta: Metadata = { title: t("Search.title"), + description: t("Index.meta_description"), }; - return meta; } + async function Search({ searchParams }: ServerPageProps) { const convertedSearchParams = convertSearchParamsToProperTypes(searchParams); const initialSearchResults = await searchFetcher.fetchOpportunities( diff --git a/frontend/src/app/[locale]/layout.tsx b/frontend/src/app/layout.tsx similarity index 95% rename from frontend/src/app/[locale]/layout.tsx rename to frontend/src/app/layout.tsx index f3b3fbabb8..e45e82c425 100644 --- a/frontend/src/app/[locale]/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,6 +1,6 @@ import "src/styles/styles.scss"; import { GoogleAnalytics } from "@next/third-parties/google"; -import { PUBLIC_ENV } from "../../constants/environments"; +import { PUBLIC_ENV } from "src/constants/environments"; import Layout from "src/components/Layout"; import { unstable_setRequestLocale } from "next-intl/server"; diff --git a/frontend/src/app/[locale]/not-found.tsx b/frontend/src/app/not-found.tsx similarity index 63% rename from frontend/src/app/[locale]/not-found.tsx rename to frontend/src/app/not-found.tsx index 8b72c2223b..08416f07fb 100644 --- a/frontend/src/app/[locale]/not-found.tsx +++ b/frontend/src/app/not-found.tsx @@ -2,8 +2,20 @@ import BetaAlert from "src/components/BetaAlert"; import { GridContainer } from "@trussworks/react-uswds"; import Link from "next/link"; import { useTranslations } from "next-intl"; +import { getTranslations, unstable_setRequestLocale } from "next-intl/server"; +import { Metadata } from "next"; + +export async function generateMetadata() { + const t = await getTranslations({ locale: "en" }); + const meta: Metadata = { + title: t("ErrorPages.page_not_found.title"), + description: t("Index.meta_description"), + }; + return meta; +} export default function NotFound() { + unstable_setRequestLocale("en"); const t = useTranslations("ErrorPages.page_not_found"); return ( diff --git a/frontend/src/app/[locale]/template.tsx b/frontend/src/app/template.tsx similarity index 87% rename from frontend/src/app/[locale]/template.tsx rename to frontend/src/app/template.tsx index 05cc3d7e00..b7250859f0 100644 --- a/frontend/src/app/[locale]/template.tsx +++ b/frontend/src/app/template.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { sendGAEvent } from "@next/third-parties/google"; -import { PUBLIC_ENV } from "../../constants/environments"; +import { PUBLIC_ENV } from "src/constants/environments"; export default function Template({ children }: { children: React.ReactNode }) { const isProd = process.env.NODE_ENV === "production"; diff --git a/frontend/src/i18n/messages/en/index.ts b/frontend/src/i18n/messages/en/index.ts index 1749e19605..11a5f900a8 100644 --- a/frontend/src/i18n/messages/en/index.ts +++ b/frontend/src/i18n/messages/en/index.ts @@ -323,6 +323,7 @@ export const messages = { "The Simpler.Grants.gov newsletter is powered by the Sendy data service. Personal information is not stored within Simpler.Grants.gov. ", }, ErrorPages: { + page_title: "Page Not Found | Simpler.Grants.gov", page_not_found: { title: "Oops! Page Not Found", message_content_1: diff --git a/frontend/stories/pages/404.stories.tsx b/frontend/stories/pages/404.stories.tsx index da5b1b3b97..ee03b30f56 100644 --- a/frontend/stories/pages/404.stories.tsx +++ b/frontend/stories/pages/404.stories.tsx @@ -1,5 +1,5 @@ import { Meta } from "@storybook/react"; -import PageNotFound from "src/app/[locale]/not-found"; +import PageNotFound from "src/app/not-found"; const meta: Meta = { title: "Pages/404", diff --git a/frontend/tests/e2e/404.spec.ts b/frontend/tests/e2e/404.spec.ts new file mode 100644 index 0000000000..5335c4b8ee --- /dev/null +++ b/frontend/tests/e2e/404.spec.ts @@ -0,0 +1,20 @@ +/* eslint-disable testing-library/prefer-screen-queries */ +import { test, expect } from "@playwright/test"; + +test.beforeEach(async ({ page }) => { + await page.goto("/imnothere"); +}); + +test.afterEach(async ({ context }) => { + await context.close(); +}); + +test("has title", async ({ page }) => { + await expect(page).toHaveTitle("Oops! Page Not Found"); +}); + +test("can view the home button", async ({ page }) => { + await expect(page.getByRole("link", { name: "Return Home" })).toHaveText( + "Return Home", + ); +}); diff --git a/frontend/tests/pages/404.test.tsx b/frontend/tests/pages/404.test.tsx index 86e18675fe..0de01e9b4a 100644 --- a/frontend/tests/pages/404.test.tsx +++ b/frontend/tests/pages/404.test.tsx @@ -1,8 +1,8 @@ -import { screen, waitFor, render } from "tests/react-utils"; -// import { render } from "@testing-library/react"; +import { screen, waitFor } from "tests/react-utils"; +import { render } from "@testing-library/react"; import { axe } from "jest-axe"; -import PageNotFound from "src/app/[locale]/not-found"; +import PageNotFound from "src/app/not-found"; describe("PageNotFound", () => { it("renders alert with grants.gov link", () => {