From 2f948fcccea9555b97c2e79cfddaccded9a36c73 Mon Sep 17 00:00:00 2001 From: Andy Cochran Date: Wed, 6 Dec 2023 10:51:46 -0500 Subject: [PATCH] [Issue 789] Newsletter Pages (#804) * add newsletter pages, content, and Sendy form HTML --- frontend/public/locales/en/common.json | 30 +++++ frontend/src/constants/breadcrumbs.ts | 20 ++++ .../src/pages/newsletter-confirmation.tsx | 80 +++++++++++++ frontend/src/pages/newsletter-unsubscribe.tsx | 83 ++++++++++++++ frontend/src/pages/newsletter.tsx | 107 ++++++++++++++++++ .../pages/newsletter-confirmation.test.tsx | 12 ++ .../pages/newsletter-unsubscribe.test.tsx | 12 ++ frontend/tests/pages/newsletter.test.tsx | 20 ++++ 8 files changed, 364 insertions(+) create mode 100644 frontend/src/pages/newsletter-confirmation.tsx create mode 100644 frontend/src/pages/newsletter-unsubscribe.tsx create mode 100644 frontend/src/pages/newsletter.tsx create mode 100644 frontend/tests/pages/newsletter-confirmation.test.tsx create mode 100644 frontend/tests/pages/newsletter-unsubscribe.test.tsx create mode 100644 frontend/tests/pages/newsletter.test.tsx diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index 5edc6abd8..45037dc77 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -68,6 +68,36 @@ "agile_title": "Agile", "agile_content": "We’re building a simpler Grants.gov with you, not for you. Our process gives us the flexibility to swiftly respond to feedback and adapt to changing priorities and requirements." }, + "Newsletter": { + "alert_title": "Simpler Grants.gov is a work in progress.", + "alert": "To search for funding opportunities and apply, go to www.grants.gov.", + "title": "Newsletter signup", + "intro": "Subscribe to get Simpler.Grants.gov project updates in your inbox!", + "paragraph_1": "If you sign up for the Simpler.Grants.gov newsletter, we’ll keep you informed of our progress and you’ll know about every opportunity to get involved.", + "list": "", + "disclaimer": "The Simpler.Grants.gov newsletter is powered by the Sendy data service. Personal information is not stored within Simpler.Grants.gov. " + }, + "Newsletter_confirmation": { + "alert_title": "Simpler Grants.gov is a work in progress.", + "alert": "To search for funding opportunities and apply, go to www.grants.gov.", + "title": "You’re subscribed", + "intro": "You are signed up to receive project updates from Simpler.Grants.gov.", + "paragraph_1": "Thank you for subscribing. We’ll keep you informed of our progress and you’ll know about every opportunity to get involved.", + "heading": "Learn more", + "paragraph_2": "You can read all about our transparent process and what we’re doing now, or explore our existing user research and the findings that are guiding our work.", + "disclaimer": "The Simpler.Grants.gov newsletter is powered by the Sendy data service. Personal information is not stored within Simpler.Grants.gov. " + }, + "Newsletter_unsubscribe": { + "alert_title": "Simpler Grants.gov is a work in progress.", + "alert": "To search for funding opportunities and apply, go to www.grants.gov.", + "title": "You have unsubscribed", + "intro": "You will no longer receive project updates from Simpler.Grants.gov. ", + "paragraph_1": "Did you unsubscribe by accident? Sign up again.", + "button_resub": "Re-subscribe", + "heading": "Learn more", + "paragraph_2": "You can read all about our transparent process and what we’re doing now, or explore our existing user research and the findings that are guiding our work.", + "disclaimer": "The Simpler.Grants.gov newsletter is powered by the Sendy data service. Personal information is not stored within Simpler.Grants.gov. " + }, "ErrorPages": { "page_not_found": { "title": "Oops! Page Not Found", diff --git a/frontend/src/constants/breadcrumbs.ts b/frontend/src/constants/breadcrumbs.ts index da1190096..c25e4c629 100644 --- a/frontend/src/constants/breadcrumbs.ts +++ b/frontend/src/constants/breadcrumbs.ts @@ -3,6 +3,26 @@ import { Breadcrumb, BreadcrumbList } from "src/components/Breadcrumbs"; const HOME: Breadcrumb = { title: "Home", path: "/" }; const RESEARCH: Breadcrumb = { title: "Research", path: "research/" }; const PROCESS: Breadcrumb = { title: "Process", path: "process/" }; +const NEWSLETTER: Breadcrumb = { title: "Newsletter", path: "newsletter/" }; +const NEWSLETTER_CONFIRMATION: Breadcrumb = { + title: "Confirmation", + path: "newsletter-confirmation/", +}; +const NEWSLETTER_UNSUBSCRIBE: Breadcrumb = { + title: "Unsubscribe", + path: "newsletter-unsubscribe/", +}; export const RESEARCH_CRUMBS: BreadcrumbList = [HOME, RESEARCH]; export const PROCESS_CRUMBS: BreadcrumbList = [HOME, PROCESS]; +export const NEWSLETTER_CRUMBS: BreadcrumbList = [HOME, NEWSLETTER]; +export const NEWSLETTER_CONFIRMATION_CRUMBS: BreadcrumbList = [ + HOME, + NEWSLETTER, + NEWSLETTER_CONFIRMATION, +]; +export const NEWSLETTER_UNSUBSCRIBE_CRUMBS: BreadcrumbList = [ + HOME, + NEWSLETTER, + NEWSLETTER_UNSUBSCRIBE, +]; diff --git a/frontend/src/pages/newsletter-confirmation.tsx b/frontend/src/pages/newsletter-confirmation.tsx new file mode 100644 index 000000000..a7d08381c --- /dev/null +++ b/frontend/src/pages/newsletter-confirmation.tsx @@ -0,0 +1,80 @@ +import type { GetStaticProps, NextPage } from "next"; +import { NEWSLETTER_CONFIRMATION_CRUMBS } from "src/constants/breadcrumbs"; +import { ExternalRoutes } from "src/constants/routes"; + +import { Trans, useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import Link from "next/link"; +import { Grid, GridContainer } from "@trussworks/react-uswds"; + +import Breadcrumbs from "src/components/Breadcrumbs"; +import PageSEO from "src/components/PageSEO"; +import FullWidthAlert from "../components/FullWidthAlert"; + +const NewsletterConfirmation: NextPage = () => { + const { t } = useTranslation("common", { + keyPrefix: "Newsletter_confirmation", + }); + + return ( + <> + + + + ), + }} + /> + + + + +

+ {t("title")} +

+

+ {t("intro")} +

+ + +

{t("paragraph_1")}

+
+ +

+ {t("heading")} +

+

+ , + "research-link": , + }} + /> +

+
+
+
+ +

{t("disclaimer")}

+
+ + ); +}; + +// Change this to GetServerSideProps if you're using server-side rendering +export const getStaticProps: GetStaticProps = async ({ locale }) => { + const translations = await serverSideTranslations(locale ?? "en"); + return { props: { ...translations } }; +}; + +export default NewsletterConfirmation; diff --git a/frontend/src/pages/newsletter-unsubscribe.tsx b/frontend/src/pages/newsletter-unsubscribe.tsx new file mode 100644 index 000000000..f7504abc7 --- /dev/null +++ b/frontend/src/pages/newsletter-unsubscribe.tsx @@ -0,0 +1,83 @@ +import type { GetStaticProps, NextPage } from "next"; +import { NEWSLETTER_UNSUBSCRIBE_CRUMBS } from "src/constants/breadcrumbs"; +import { ExternalRoutes } from "src/constants/routes"; + +import { Trans, useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import Link from "next/link"; +import { Grid, GridContainer } from "@trussworks/react-uswds"; + +import Breadcrumbs from "src/components/Breadcrumbs"; +import PageSEO from "src/components/PageSEO"; +import FullWidthAlert from "../components/FullWidthAlert"; + +const NewsletterUnsubscribe: NextPage = () => { + const { t } = useTranslation("common", { + keyPrefix: "Newsletter_unsubscribe", + }); + + return ( + <> + + + + ), + }} + /> + + + + +

+ {t("title")} +

+

+ {t("intro")} +

+ + +

{t("paragraph_1")}

+ + {t("button_resub")} + +
+ +

+ {t("heading")} +

+

+ , + "research-link": , + }} + /> +

+
+
+
+ +

{t("disclaimer")}

+
+ + ); +}; + +// Change this to GetServerSideProps if you're using server-side rendering +export const getStaticProps: GetStaticProps = async ({ locale }) => { + const translations = await serverSideTranslations(locale ?? "en"); + return { props: { ...translations } }; +}; + +export default NewsletterUnsubscribe; diff --git a/frontend/src/pages/newsletter.tsx b/frontend/src/pages/newsletter.tsx new file mode 100644 index 000000000..65db9af63 --- /dev/null +++ b/frontend/src/pages/newsletter.tsx @@ -0,0 +1,107 @@ +import type { GetStaticProps, NextPage } from "next"; +import { NEWSLETTER_CRUMBS } from "src/constants/breadcrumbs"; +import { ExternalRoutes } from "src/constants/routes"; + +import { Trans, useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { + Button, + Grid, + GridContainer, + Label, + TextInput, +} from "@trussworks/react-uswds"; + +import Breadcrumbs from "src/components/Breadcrumbs"; +import PageSEO from "src/components/PageSEO"; +import FullWidthAlert from "../components/FullWidthAlert"; + +const Newsletter: NextPage = () => { + const { t } = useTranslation("common", { keyPrefix: "Newsletter" }); + + return ( + <> + + + + ), + }} + /> + + + + +

+ {t("title")} +

+

+ {t("intro")} +

+ + +

{t("paragraph_1")}

+ + ), + li:
  • , + }} + /> + + +
    + + + + +
    + + +
    + + + + + + +
    + + + +

    {t("disclaimer")}

    +
    + + ); +}; + +// Change this to GetServerSideProps if you're using server-side rendering +export const getStaticProps: GetStaticProps = async ({ locale }) => { + const translations = await serverSideTranslations(locale ?? "en"); + return { props: { ...translations } }; +}; + +export default Newsletter; diff --git a/frontend/tests/pages/newsletter-confirmation.test.tsx b/frontend/tests/pages/newsletter-confirmation.test.tsx new file mode 100644 index 000000000..12e446b88 --- /dev/null +++ b/frontend/tests/pages/newsletter-confirmation.test.tsx @@ -0,0 +1,12 @@ +import { render, waitFor } from "@testing-library/react"; +import { axe } from "jest-axe"; +import NewsletterConfirmation from "src/pages/newsletter-confirmation"; + +describe("Newsletter", () => { + it("passes accessibility scan", async () => { + const { container } = render(); + const results = await waitFor(() => axe(container)); + + expect(results).toHaveNoViolations(); + }); +}); diff --git a/frontend/tests/pages/newsletter-unsubscribe.test.tsx b/frontend/tests/pages/newsletter-unsubscribe.test.tsx new file mode 100644 index 000000000..5592e54e4 --- /dev/null +++ b/frontend/tests/pages/newsletter-unsubscribe.test.tsx @@ -0,0 +1,12 @@ +import { render, waitFor } from "@testing-library/react"; +import { axe } from "jest-axe"; +import NewsletterUnsubscribe from "src/pages/newsletter-unsubscribe"; + +describe("Newsletter", () => { + it("passes accessibility scan", async () => { + const { container } = render(); + const results = await waitFor(() => axe(container)); + + expect(results).toHaveNoViolations(); + }); +}); diff --git a/frontend/tests/pages/newsletter.test.tsx b/frontend/tests/pages/newsletter.test.tsx new file mode 100644 index 000000000..0d4308c38 --- /dev/null +++ b/frontend/tests/pages/newsletter.test.tsx @@ -0,0 +1,20 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import { axe } from "jest-axe"; +import Newsletter from "src/pages/newsletter"; + +describe("Newsletter", () => { + it("renders signup form with a submit button", () => { + render(); + + const sendyform = screen.getByTestId("sendy-form"); + + expect(sendyform).toBeInTheDocument(); + }); + + it("passes accessibility scan", async () => { + const { container } = render(); + const results = await waitFor(() => axe(container)); + + expect(results).toHaveNoViolations(); + }); +});