From bf935977e6687eee3a0cdb98fd28c02705b7d7f8 Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Fri, 24 Jan 2025 14:15:36 -0700 Subject: [PATCH 01/17] Remove verbiage file for HelpPage.tsx --- .../accordions/FaqAccordion.test.tsx | 44 ----------- .../components/accordions/FaqAccordion.tsx | 33 -------- .../src/components/cards/EmailCard.test.tsx | 35 --------- .../src/components/cards/HelpCard.test.tsx | 18 +++++ .../cards/{EmailCard.tsx => HelpCard.tsx} | 27 ++----- services/ui-src/src/components/index.ts | 3 +- .../pages/HelpPage/HelpPage.test.tsx | 3 +- .../components/pages/HelpPage/HelpPage.tsx | 78 +++++++++++++++---- services/ui-src/src/verbiage/pages/help.ts | 37 --------- 9 files changed, 91 insertions(+), 187 deletions(-) delete mode 100644 services/ui-src/src/components/accordions/FaqAccordion.test.tsx delete mode 100644 services/ui-src/src/components/accordions/FaqAccordion.tsx delete mode 100644 services/ui-src/src/components/cards/EmailCard.test.tsx create mode 100644 services/ui-src/src/components/cards/HelpCard.test.tsx rename services/ui-src/src/components/cards/{EmailCard.tsx => HelpCard.tsx} (59%) delete mode 100644 services/ui-src/src/verbiage/pages/help.ts diff --git a/services/ui-src/src/components/accordions/FaqAccordion.test.tsx b/services/ui-src/src/components/accordions/FaqAccordion.test.tsx deleted file mode 100644 index c6e74c2b..00000000 --- a/services/ui-src/src/components/accordions/FaqAccordion.test.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import { testA11y } from "utils/testing/commonTests"; -import userEvent from "@testing-library/user-event"; -import { RouterWrappedComponent } from "utils/testing/setupJest"; -import { FaqAccordion } from "components"; - -const accordionItems = [ - { - question: "Question?", - answer: "Answer!", - }, -]; - -const faqAccordionComponent = ( - - - -); - -describe("Test FaqAccordion", () => { - beforeEach(() => { - render(faqAccordionComponent); - }); - - test("FaqAccordion is visible", () => { - expect(screen.getByText(accordionItems[0].question)).toBeVisible(); - }); - - test("FaqAccordion default closed state only shows the question", () => { - expect(screen.getByText(accordionItems[0].question)).toBeVisible(); - expect(screen.getByText(accordionItems[0].answer)).not.toBeVisible(); - }); - - test("FaqAccordion should show answer on click", async () => { - const faqQuestion = screen.getByText(accordionItems[0].question); - expect(faqQuestion).toBeVisible(); - expect(screen.getByText(accordionItems[0].answer)).not.toBeVisible(); - await userEvent.click(faqQuestion); - expect(faqQuestion).toBeVisible(); - expect(screen.getByText(accordionItems[0].answer)).toBeVisible(); - }); - - testA11y(faqAccordionComponent); -}); diff --git a/services/ui-src/src/components/accordions/FaqAccordion.tsx b/services/ui-src/src/components/accordions/FaqAccordion.tsx deleted file mode 100644 index 1c152824..00000000 --- a/services/ui-src/src/components/accordions/FaqAccordion.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Accordion, Box, Text } from "@chakra-ui/react"; -import { AccordionItem } from "components"; -import { AnyObject } from "types"; - -export const FaqAccordion = ({ accordionItems, ...props }: Props) => { - return ( - - {accordionItems.map((item: AnyObject, index: number) => ( - - - {item.answer} - - - ))} - - ); -}; - -interface Props { - accordionItems: AnyObject; -} - -const sx = { - item: { - marginBottom: "1.5rem", - borderStyle: "none", - }, - answerBox: { - ".mobile &": { - paddingLeft: "1rem", - }, - }, -}; diff --git a/services/ui-src/src/components/cards/EmailCard.test.tsx b/services/ui-src/src/components/cards/EmailCard.test.tsx deleted file mode 100644 index f2e9e0e2..00000000 --- a/services/ui-src/src/components/cards/EmailCard.test.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import { testA11y } from "utils/testing/commonTests"; -import { EmailCard } from "components"; -import { createEmailLink } from "utils/other/email"; -import verbiage from "verbiage/pages/help"; - -const emailCardComponent = ( - -); - -describe("Test EmailCard", () => { - beforeEach(() => { - render(emailCardComponent); - }); - - test("Email for EmailCard is visible", () => { - expect(screen.getByText("mdct_help@cms.hhs.gov")).toBeVisible(); - }); - - test("Email links are created correctly", () => { - const mockEmailData = { - address: "test@test.com", - subject: "the subject", - body: "the body", - }; - const expectedEmailLink = "mailto:test@test.com?the%20subject"; - expect(createEmailLink(mockEmailData)).toEqual(expectedEmailLink); - }); - - test("Email links are visible", () => { - expect(screen.getByRole("link")).toBeVisible(); - }); - - testA11y(emailCardComponent); -}); diff --git a/services/ui-src/src/components/cards/HelpCard.test.tsx b/services/ui-src/src/components/cards/HelpCard.test.tsx new file mode 100644 index 00000000..576c8d0c --- /dev/null +++ b/services/ui-src/src/components/cards/HelpCard.test.tsx @@ -0,0 +1,18 @@ +import { render, screen } from "@testing-library/react"; +import { testA11y } from "utils/testing/commonTests"; +import { EmailCard } from "components"; +import { Link } from "@chakra-ui/react"; + +describe("Test EmailCard", () => { + test("Email for EmailCard is visible", () => { + render( + + mdct_help@cms.hhs.gov + + ); + const link = screen.getByRole("link", { name: "mdct_help@cms.hhs.gov" }); + expect(link).toBeVisible(); + }); + + testA11y(); +}); diff --git a/services/ui-src/src/components/cards/EmailCard.tsx b/services/ui-src/src/components/cards/HelpCard.tsx similarity index 59% rename from services/ui-src/src/components/cards/EmailCard.tsx rename to services/ui-src/src/components/cards/HelpCard.tsx index 512f6c07..6711ba8b 100644 --- a/services/ui-src/src/components/cards/EmailCard.tsx +++ b/services/ui-src/src/components/cards/HelpCard.tsx @@ -1,10 +1,8 @@ -import { Flex, Image, Link, Text } from "@chakra-ui/react"; +import { Flex, Image } from "@chakra-ui/react"; import { Card } from "components"; -import { useBreakpoint } from "utils"; -import { AnyObject } from "types"; -import { createEmailLink } from "utils/other/email"; import spreadsheetIcon from "assets/icons/spreadsheet/icon_spreadsheet_gray.svg"; import settingsIcon from "assets/icons/icon_wrench_gear.svg"; +import { ComponentProps } from "react"; const iconMap = { spreadsheet: { @@ -17,35 +15,22 @@ const iconMap = { }, }; -export const EmailCard = ({ verbiage, icon, cardprops, ...props }: Props) => { - const { isDesktop } = useBreakpoint(); - +export const HelpCard = ({ icon, children }: Props) => { return ( - + {iconMap[icon].alt} - - {verbiage.body} - - Email {!isDesktop &&
} - - {verbiage.email.address} - -
-
+ {children}
); }; -interface Props { - verbiage: AnyObject; +interface Props extends Pick, "children"> { icon: keyof typeof iconMap; - [key: string]: any; } const sx = { diff --git a/services/ui-src/src/components/index.ts b/services/ui-src/src/components/index.ts index 01709b55..79252dd7 100644 --- a/services/ui-src/src/components/index.ts +++ b/services/ui-src/src/components/index.ts @@ -1,6 +1,5 @@ // accordions export { AccordionItem } from "./accordions/AccordionItem"; -export { FaqAccordion } from "./accordions/FaqAccordion"; export { TemplateCardAccordion } from "./accordions/TemplateCardAccordion"; export { InstructionsAccordion } from "./accordions/InstructionsAccordion"; // alerts @@ -25,7 +24,7 @@ export { AppRoutes } from "./app/AppRoutes"; export { Timeout } from "./layout/Timeout"; // cards export { Card } from "./cards/Card"; -export { EmailCard } from "./cards/EmailCard"; +export { HelpCard as EmailCard } from "./cards/HelpCard"; export { TemplateCard } from "./cards/TemplateCard"; // export export { ExportedReportBanner } from "./export/ExportedReportBanner"; diff --git a/services/ui-src/src/components/pages/HelpPage/HelpPage.test.tsx b/services/ui-src/src/components/pages/HelpPage/HelpPage.test.tsx index 62b86f21..01104063 100644 --- a/services/ui-src/src/components/pages/HelpPage/HelpPage.test.tsx +++ b/services/ui-src/src/components/pages/HelpPage/HelpPage.test.tsx @@ -1,7 +1,6 @@ import { render, screen } from "@testing-library/react"; import { HelpPage } from "components/pages/HelpPage/HelpPage"; import { RouterWrappedComponent } from "utils/testing/setupJest"; -import verbiage from "verbiage/pages/help"; import { testA11y } from "utils/testing/commonTests"; import userEvent from "@testing-library/user-event"; @@ -17,7 +16,7 @@ describe("Test HelpPage", () => { }); test("Check that HelpPage renders", () => { - expect(screen.getByText(verbiage.intro.header)).toHaveTextContent( + expect(screen.getByRole("heading")).toHaveTextContent( "How can we help you?" ); }); diff --git a/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx b/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx index 67475a9c..393af69d 100644 --- a/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx +++ b/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx @@ -1,26 +1,78 @@ -import { Box, Flex, Heading, Text } from "@chakra-ui/react"; -import { EmailCard, FaqAccordion, PageTemplate } from "components"; -import verbiage from "verbiage/pages/help"; +import { Accordion, Box, Flex, Heading, Link, Text } from "@chakra-ui/react"; +import { AccordionItem, EmailCard, PageTemplate } from "components"; +import { useBreakpoint } from "utils"; + +const helpDeskEmailAddress = "mdct_help@cms.hhs.gov"; +const mfpDemoEmailAddress = "MFPDemo@cms.hhs.gov"; export const HelpPage = () => { - const { intro, cards, accordionItems } = verbiage; + const { isDesktop } = useBreakpoint(); return ( - {intro.header} + How can we help you? - {intro.body} + + Question or feedback? Please email us and we will respond as soon as + possible. You can also review our frequently asked questions below. + - - + + For technical support and login issues: + + Email {!isDesktop &&
} + + {helpDeskEmailAddress} + +
+
+ + For questions about the online form: + + Email {!isDesktop &&
} + + {mfpDemoEmailAddress} + +
+
- {accordionItems.length > 0 && ( - - - - )} + + + + + TBD + + + + + TBD + + + +
); }; + +const sx = { + bodyText: { + marginBottom: "1rem", + }, + emailText: { + fontWeight: "bold", + }, + accordionItem: { + marginBottom: "1.5rem", + borderStyle: "none", + }, + accordionPanel: { + ".mobile &": { + paddingLeft: "1rem", + }, + }, +}; diff --git a/services/ui-src/src/verbiage/pages/help.ts b/services/ui-src/src/verbiage/pages/help.ts deleted file mode 100644 index dc71e0e9..00000000 --- a/services/ui-src/src/verbiage/pages/help.ts +++ /dev/null @@ -1,37 +0,0 @@ -export default { - intro: { - header: "How can we help you?", - body: "Question or feedback? Please email us and we will respond as soon as possible. You can also review our frequently asked questions below.", - }, - cards: { - helpdesk: { - body: "For technical support and login issues: ", - email: { - address: "mdct_help@cms.hhs.gov", - }, - }, - template: { - body: "For questions about the online form:", - email: { - address: "MFPDemo@cms.hhs.gov", - }, - }, - }, - accordionItems: [ - /* - * accordion items are in the following format: - * { - * question: "", - * answer: "", - * } - */ - { - question: "How do I log into my IDM account?", - answer: "TBD", - }, - { - question: "Question #2", - answer: "TBD", - }, - ], -}; From bcb691feecc4d9c2ed8c3e1f5e080777d5bc611a Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Fri, 24 Jan 2025 14:35:54 -0700 Subject: [PATCH 02/17] Remove export and admin verbiage files --- .../export/ExportedReportBanner.tsx | 7 ++----- .../src/components/pages/Admin/AdminPage.tsx | 5 ++--- .../pages/Export/ExportedReportPage.tsx | 8 +++---- .../ui-src/src/verbiage/export/qms-export.ts | 21 ------------------- services/ui-src/src/verbiage/pages/admin.ts | 6 ------ 5 files changed, 7 insertions(+), 40 deletions(-) delete mode 100644 services/ui-src/src/verbiage/export/qms-export.ts delete mode 100644 services/ui-src/src/verbiage/pages/admin.ts diff --git a/services/ui-src/src/components/export/ExportedReportBanner.tsx b/services/ui-src/src/components/export/ExportedReportBanner.tsx index 3dc8a02e..ae820755 100644 --- a/services/ui-src/src/components/export/ExportedReportBanner.tsx +++ b/services/ui-src/src/components/export/ExportedReportBanner.tsx @@ -1,20 +1,17 @@ import { Box, Text, Button, Image } from "@chakra-ui/react"; import pdfIcon from "assets/icons/pdf/icon_pdf_white.svg"; -import qmsVerbiage from "verbiage/export/qms-export"; export const ExportedReportBanner = () => { - const { reportBanner } = qmsVerbiage; - const onClickHandler = () => { window?.print(); }; return ( - {reportBanner.intro} + Click below to export or print Quality Measure Set shown here ); diff --git a/services/ui-src/src/components/pages/Admin/AdminPage.tsx b/services/ui-src/src/components/pages/Admin/AdminPage.tsx index c0b819d2..bf9ef22b 100644 --- a/services/ui-src/src/components/pages/Admin/AdminPage.tsx +++ b/services/ui-src/src/components/pages/Admin/AdminPage.tsx @@ -16,7 +16,6 @@ import { PageTemplate, } from "components"; import { convertDateUtcToEt, useStore } from "utils"; -import verbiage from "verbiage/pages/admin"; export const AdminPage = () => { const { deleteAdminBanner, writeAdminBanner } = @@ -35,9 +34,9 @@ export const AdminPage = () => { - {verbiage.intro.header} + Banner Admin - {verbiage.intro.body} + Manage the announcement banner below. Current Banner diff --git a/services/ui-src/src/components/pages/Export/ExportedReportPage.tsx b/services/ui-src/src/components/pages/Export/ExportedReportPage.tsx index 0aacb34b..78dd5b13 100644 --- a/services/ui-src/src/components/pages/Export/ExportedReportPage.tsx +++ b/services/ui-src/src/components/pages/Export/ExportedReportPage.tsx @@ -1,7 +1,6 @@ import { Helmet } from "react-helmet"; import { Box, Center, Heading, Spinner, Flex } from "@chakra-ui/react"; import { useStore } from "utils"; -import qmsVerbiage from "verbiage/export/qms-export"; import { FormPageTemplate, MeasurePageTemplate, @@ -13,7 +12,6 @@ import { ExportedReportBanner, ExportedReportWrapper } from "components"; export const ExportedReportPage = () => { const { report } = useStore(); - const { metadata } = qmsVerbiage; const reportPages = report?.pages.filter( (page) => page.type !== PageType.Modal && page.type !== PageType.Measure @@ -28,9 +26,9 @@ export const ExportedReportPage = () => { {/* pdf metadata */} {reportTitle(report)} - - - + + + {/* report heading */} diff --git a/services/ui-src/src/verbiage/export/qms-export.ts b/services/ui-src/src/verbiage/export/qms-export.ts deleted file mode 100644 index 0d5fbf5a..00000000 --- a/services/ui-src/src/verbiage/export/qms-export.ts +++ /dev/null @@ -1,21 +0,0 @@ -export default { - reportBanner: { - intro: "Click below to export or print Quality Measure Set shown here", - pdfButton: "Download PDF", - }, - metadata: { - author: "CMS", - subject: "Quality Measure Set", - language: "English", - }, - reportPage: { - heading: "Quality Measure Set for", - metadataTableHeaders: { - submissionName: "Submission Name", - dueDate: "Due date", - lastEdited: "Last edited", - status: "Status", - editedBy: "Edited by", - }, - }, -}; diff --git a/services/ui-src/src/verbiage/pages/admin.ts b/services/ui-src/src/verbiage/pages/admin.ts deleted file mode 100644 index 7261469d..00000000 --- a/services/ui-src/src/verbiage/pages/admin.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default { - intro: { - header: "Banner Admin", - body: "Manage the announcement banner below.", - }, -}; From 7da3fd2fd054612ee31ec81043d8b940b81efc48 Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Fri, 24 Jan 2025 15:12:11 -0700 Subject: [PATCH 03/17] Replace CustomHtmlElement in ErrorAlert with React children --- .../src/components/alerts/Alert.test.tsx | 5 ++- .../ui-src/src/components/alerts/Alert.tsx | 18 ++++---- .../src/components/alerts/ErrorAlert.test.tsx | 2 +- .../src/components/alerts/ErrorAlert.tsx | 5 ++- .../ui-src/src/components/banners/Banner.tsx | 4 +- .../export/ExportedReportBanner.test.tsx | 3 +- .../src/components/logins/LoginCognito.tsx | 2 +- services/ui-src/src/types/other.ts | 6 ++- services/ui-src/src/verbiage/errors.ts | 40 ------------------ services/ui-src/src/verbiage/errors.tsx | 42 +++++++++++++++++++ 10 files changed, 68 insertions(+), 59 deletions(-) delete mode 100644 services/ui-src/src/verbiage/errors.ts create mode 100644 services/ui-src/src/verbiage/errors.tsx diff --git a/services/ui-src/src/components/alerts/Alert.test.tsx b/services/ui-src/src/components/alerts/Alert.test.tsx index 4085c11a..d34e0f35 100644 --- a/services/ui-src/src/components/alerts/Alert.test.tsx +++ b/services/ui-src/src/components/alerts/Alert.test.tsx @@ -8,11 +8,12 @@ const alertIcon = "test-file-stub"; const alertComponent = ( + > + This is for testing. + ); describe("", () => { diff --git a/services/ui-src/src/components/alerts/Alert.tsx b/services/ui-src/src/components/alerts/Alert.tsx index 17c4ce93..796fe0c5 100644 --- a/services/ui-src/src/components/alerts/Alert.tsx +++ b/services/ui-src/src/components/alerts/Alert.tsx @@ -8,14 +8,14 @@ import { Link, Text, } from "@chakra-ui/react"; -import { AlertTypes, CustomHtmlElement } from "types"; +import { AlertTypes } from "types"; import alertIcon from "assets/icons/alert/icon_alert.svg"; -import { parseCustomHtml } from "utils"; +import { ComponentProps } from "react"; export const Alert = ({ status = AlertTypes.INFO, title, - description, + children, link, showIcon = true, icon, @@ -35,9 +35,9 @@ export const Alert = ({ )} {title && {title}} - {description && ( + {children && ( - {parseCustomHtml(description)} + {children} {link && ( @@ -53,14 +53,16 @@ export const Alert = ({ ); }; -interface Props { +interface Props + extends Pick< + ComponentProps, + "children" | "className" | "sx" + > { status?: AlertTypes; title?: string; - description?: string | CustomHtmlElement[]; link?: string; showIcon?: boolean; icon?: string; - [key: string]: any; } const sx = { diff --git a/services/ui-src/src/components/alerts/ErrorAlert.test.tsx b/services/ui-src/src/components/alerts/ErrorAlert.test.tsx index 62aeeddc..59f404bb 100644 --- a/services/ui-src/src/components/alerts/ErrorAlert.test.tsx +++ b/services/ui-src/src/components/alerts/ErrorAlert.test.tsx @@ -6,7 +6,7 @@ import { testA11y } from "utils/testing/commonTests"; const error: ErrorVerbiage = { title: "We've run into a problem", - description: genericErrorContent, + children: genericErrorContent, }; const errorAlertComponent = ; diff --git a/services/ui-src/src/components/alerts/ErrorAlert.tsx b/services/ui-src/src/components/alerts/ErrorAlert.tsx index adb67aa7..99249142 100644 --- a/services/ui-src/src/components/alerts/ErrorAlert.tsx +++ b/services/ui-src/src/components/alerts/ErrorAlert.tsx @@ -23,12 +23,13 @@ export const ErrorAlert = ({ + > + {error.children} + )} diff --git a/services/ui-src/src/components/banners/Banner.tsx b/services/ui-src/src/components/banners/Banner.tsx index e900424e..6d32d358 100644 --- a/services/ui-src/src/components/banners/Banner.tsx +++ b/services/ui-src/src/components/banners/Banner.tsx @@ -6,7 +6,9 @@ export const Banner = ({ bannerData, ...props }: Props) => { const { title, description, link } = bannerData; return ( bannerData && ( - + + {description} + ) ); } else return <>; diff --git a/services/ui-src/src/components/export/ExportedReportBanner.test.tsx b/services/ui-src/src/components/export/ExportedReportBanner.test.tsx index 279576e9..49faac77 100644 --- a/services/ui-src/src/components/export/ExportedReportBanner.test.tsx +++ b/services/ui-src/src/components/export/ExportedReportBanner.test.tsx @@ -1,7 +1,6 @@ import { render, screen } from "@testing-library/react"; import { ExportedReportBanner } from "./ExportedReportBanner"; import userEvent from "@testing-library/user-event"; -import qmsVerbiage from "verbiage/export/qms-export"; describe("ExportedReportBanner", () => { beforeEach(() => { @@ -10,7 +9,7 @@ describe("ExportedReportBanner", () => { }); it("ExportedReportBanner is visible", () => { expect( - screen.getByText(qmsVerbiage.reportBanner.intro) + screen.getByText("Click below to export", { exact: false }) ).toBeInTheDocument(); }); it("Test click of print button", async () => { diff --git a/services/ui-src/src/components/logins/LoginCognito.tsx b/services/ui-src/src/components/logins/LoginCognito.tsx index 2f888dec..5b40c19a 100644 --- a/services/ui-src/src/components/logins/LoginCognito.tsx +++ b/services/ui-src/src/components/logins/LoginCognito.tsx @@ -36,7 +36,7 @@ export const LoginCognito = () => { } catch (error: any) { let errorMessage: ErrorVerbiage = { title: "Unable to login", - description: error.message, + children: error.message, }; setError(errorMessage); } diff --git a/services/ui-src/src/types/other.ts b/services/ui-src/src/types/other.ts index 8ac83dd2..c7490bc3 100644 --- a/services/ui-src/src/types/other.ts +++ b/services/ui-src/src/types/other.ts @@ -1,5 +1,7 @@ // ALERTS +import { Box } from "@chakra-ui/react"; +import { ComponentProps } from "react"; import { StateNames } from "../constants"; export enum AlertTypes { @@ -43,9 +45,9 @@ export interface CustomHtmlElement { children?: CustomHtmlElement[]; } -export interface ErrorVerbiage { +export interface ErrorVerbiage + extends Pick, "children"> { title: string; - description: string | CustomHtmlElement[]; } export type StateAbbr = keyof typeof StateNames; diff --git a/services/ui-src/src/verbiage/errors.ts b/services/ui-src/src/verbiage/errors.ts deleted file mode 100644 index c16de18b..00000000 --- a/services/ui-src/src/verbiage/errors.ts +++ /dev/null @@ -1,40 +0,0 @@ -export const genericErrorContent = [ - { - type: "span", - content: - "Something went wrong on our end. Refresh your screen and try again.
If this persists, contact the MDCT Help Desk with questions or to request technical assistance by emailing ", - }, - { - type: "externalLink", - content: "mdct_help@cms.hhs.gov", - props: { - href: "mailto:mdct_help@cms.hhs.gov", - target: "_blank", - color: "black", - fontWeight: "bold", - }, - }, - { - type: "span", - content: ".", - }, -]; - -export const bannerErrors = { - GET_BANNER_FAILED: { - title: "Banner could not be fetched", - description: genericErrorContent, - }, - REPLACE_BANNER_FAILED: { - title: "Current banner could not be replaced.", - description: genericErrorContent, - }, - DELETE_BANNER_FAILED: { - title: "Current banner could not be deleted", - description: genericErrorContent, - }, - CREATE_BANNER_FAILED: { - title: "Could not create a banner.", - description: genericErrorContent, - }, -}; diff --git a/services/ui-src/src/verbiage/errors.tsx b/services/ui-src/src/verbiage/errors.tsx new file mode 100644 index 00000000..35f4767b --- /dev/null +++ b/services/ui-src/src/verbiage/errors.tsx @@ -0,0 +1,42 @@ +import { Link } from "@chakra-ui/react"; +import { ErrorVerbiage } from "types"; + +const helpDeskEmailAddress = "mdct_help@cms.hhs.gov"; + +export const genericErrorContent = ( + <> +

Something went wrong on our end. Refresh your screen and try again.

+

+ If this persists, contact the MDCT Help Desk with questions or to request + technical assistance by emailing + + {helpDeskEmailAddress} + + . +

+ +); + +export const bannerErrors: Record = { + GET_BANNER_FAILED: { + title: "Banner could not be fetched", + children: genericErrorContent, + }, + REPLACE_BANNER_FAILED: { + title: "Current banner could not be replaced.", + children: genericErrorContent, + }, + DELETE_BANNER_FAILED: { + title: "Current banner could not be deleted", + children: genericErrorContent, + }, + CREATE_BANNER_FAILED: { + title: "Could not create a banner.", + children: genericErrorContent, + }, +}; From 52f9d00e43b006e25d57e821927ac4c857fc822b Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Mon, 27 Jan 2025 15:40:06 -0700 Subject: [PATCH 04/17] Restructure home page to inline all the verbiage --- .../accordions/TemplateCardAccordion.test.tsx | 81 ---------- .../accordions/TemplateCardAccordion.tsx | 25 --- .../cards/CiIntroductionCard.test.tsx | 19 +++ .../components/cards/CiIntroductionCard.tsx | 31 ++++ .../cards/DownloadTemplate.test.tsx | 39 ----- .../src/components/cards/HelpCard.test.tsx | 8 +- .../cards/QMSIntroductionCard.test.tsx | 19 +++ .../components/cards/QmsIntroductionCard.tsx | 32 ++++ .../components/cards/ReportIntroCard.test.tsx | 50 ++++++ .../src/components/cards/ReportIntroCard.tsx | 59 +++++++ .../cards/ReportIntroCardActions.test.tsx | 98 ++++++++++++ .../cards/ReportIntroCardActions.tsx | 78 +++++++++ .../cards/TaIntroductionCard.test.tsx | 19 +++ .../components/cards/TaIntroductionCard.tsx | 31 ++++ .../components/cards/TemplateCard.test.tsx | 62 -------- .../src/components/cards/TemplateCard.tsx | 149 ------------------ .../forms/AdminDashSelector.test.tsx | 23 ++- .../components/forms/AdminDashSelector.tsx | 12 +- services/ui-src/src/components/index.ts | 9 +- .../ui-src/src/components/layout/HomePage.tsx | 33 ++-- .../components/pages/HelpPage/HelpPage.tsx | 10 +- .../ui-src/src/components/report/Elements.tsx | 20 ++- services/ui-src/src/types/other.ts | 7 +- services/ui-src/src/types/report.ts | 3 + services/ui-src/src/verbiage/pages/home.ts | 103 ------------ 25 files changed, 502 insertions(+), 518 deletions(-) delete mode 100644 services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx delete mode 100644 services/ui-src/src/components/accordions/TemplateCardAccordion.tsx create mode 100644 services/ui-src/src/components/cards/CiIntroductionCard.test.tsx create mode 100644 services/ui-src/src/components/cards/CiIntroductionCard.tsx delete mode 100644 services/ui-src/src/components/cards/DownloadTemplate.test.tsx create mode 100644 services/ui-src/src/components/cards/QMSIntroductionCard.test.tsx create mode 100644 services/ui-src/src/components/cards/QmsIntroductionCard.tsx create mode 100644 services/ui-src/src/components/cards/ReportIntroCard.test.tsx create mode 100644 services/ui-src/src/components/cards/ReportIntroCard.tsx create mode 100644 services/ui-src/src/components/cards/ReportIntroCardActions.test.tsx create mode 100644 services/ui-src/src/components/cards/ReportIntroCardActions.tsx create mode 100644 services/ui-src/src/components/cards/TaIntroductionCard.test.tsx create mode 100644 services/ui-src/src/components/cards/TaIntroductionCard.tsx delete mode 100644 services/ui-src/src/components/cards/TemplateCard.test.tsx delete mode 100644 services/ui-src/src/components/cards/TemplateCard.tsx delete mode 100644 services/ui-src/src/verbiage/pages/home.ts diff --git a/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx b/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx deleted file mode 100644 index 284670c5..00000000 --- a/services/ui-src/src/components/accordions/TemplateCardAccordion.test.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { RouterWrappedComponent } from "utils/testing/setupJest"; -import { TemplateCardAccordion } from "components"; -import verbiage from "verbiage/pages/home"; -import { AnyObject } from "types"; -import { testA11y } from "utils/testing/commonTests"; - -const accordionComponent = (mockProps?: AnyObject) => { - const props = { - verbiage: verbiage.cards.QMS.accordion, - ...mockProps, - }; - return ( - - - - ); -}; - -const accordionContent = verbiage.cards.QMS.accordion.text[0].content; -const accordionButtonLabel = verbiage.cards.QMS.accordion.buttonLabel; - -describe("", () => { - test("Accordion is visible", () => { - render(accordionComponent()); - expect(screen.getByText(accordionButtonLabel)).toBeVisible(); - }); - - test("Accordion default closed state only shows the question", () => { - render(accordionComponent()); - expect(screen.getByText(accordionButtonLabel)).toBeVisible(); - expect(screen.getByText(accordionContent)).not.toBeVisible(); - }); - - test("Accordion should show answer on click", async () => { - render(accordionComponent()); - const accordionQuestion = screen.getByText(accordionButtonLabel); - expect(accordionQuestion).toBeVisible(); - expect(screen.getByText(accordionContent)).not.toBeVisible(); - await userEvent.click(accordionQuestion); - expect(accordionQuestion).toBeVisible(); - expect(screen.getByText(accordionContent)).toBeVisible(); - }); - - test("Accordion should render a list when given one", async () => { - const mockProps = { - verbiage: { - buttonLabel: "expand", - list: ["item one", "item two", "item three"], - }, - }; - - render(accordionComponent(mockProps)); - const button = screen.getByText("expand"); - await userEvent.click(button); - - expect(screen.getByText("item one")).toBeVisible(); - expect(screen.getByText("item two")).toBeVisible(); - expect(screen.getByText("item three")).toBeVisible(); - }); - - test("Accordion should render a table when given one", async () => { - const mockProps = { - verbiage: { - buttonLabel: "expand", - table: { - headRow: ["mock column header"], - }, - }, - }; - - render(accordionComponent(mockProps)); - const button = screen.getByText("expand"); - await userEvent.click(button); - - expect(screen.getByText("mock column header")).toBeVisible(); - }); - - testA11y(accordionComponent()); -}); diff --git a/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx b/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx deleted file mode 100644 index 70f4ff8a..00000000 --- a/services/ui-src/src/components/accordions/TemplateCardAccordion.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Accordion, ListItem, UnorderedList } from "@chakra-ui/react"; -import { AccordionItem, Table } from "components"; -import { AnyObject } from "types"; -import { parseCustomHtml } from "utils"; - -export const TemplateCardAccordion = ({ verbiage, ...props }: Props) => ( - - - {parseCustomHtml(verbiage.text)} - {verbiage.table && } - {verbiage.list && ( - - {verbiage.list.map((listItem: string, index: number) => ( - {listItem} - ))} - - )} - - -); - -interface Props { - verbiage: AnyObject; - [key: string]: any; -} diff --git a/services/ui-src/src/components/cards/CiIntroductionCard.test.tsx b/services/ui-src/src/components/cards/CiIntroductionCard.test.tsx new file mode 100644 index 00000000..8176e264 --- /dev/null +++ b/services/ui-src/src/components/cards/CiIntroductionCard.test.tsx @@ -0,0 +1,19 @@ +import { CiIntroductionCard } from "./CiIntroductionCard"; +import { render, screen } from "@testing-library/react"; +import { testA11y } from "utils/testing/commonTests"; +import { RouterWrappedComponent } from "utils/testing/mockRouter"; + +const component = ( + + + +); + +describe("CiIntroductionCard", () => { + it("should render", () => { + render(component); + expect(screen.getByText("The HCBS is", { exact: false })).toBeVisible(); + }); + + testA11y(component); +}); diff --git a/services/ui-src/src/components/cards/CiIntroductionCard.tsx b/services/ui-src/src/components/cards/CiIntroductionCard.tsx new file mode 100644 index 00000000..f8e57636 --- /dev/null +++ b/services/ui-src/src/components/cards/CiIntroductionCard.tsx @@ -0,0 +1,31 @@ +import { Accordion, Link } from "@chakra-ui/react"; +import { AccordionItem, ReportIntroCard } from "components"; +import { ReportType } from "types"; +import { ReportIntroCardActions } from "./ReportIntroCardActions"; + +/** + * This card appears on the state user home page. + * It contains text specific to the CI report. + */ +export const CiIntroductionCard = () => { + return ( + + The HCBS is ... + + 6071(a)(1) of the Deficit Reduction Act (DRA) + + as "increasing the use of home and community-based, rather than + institutional, long-term care services." + + + +

The HCBS Critical Incident will be created and submitted ...

+

The HCBS Critical Incident deadlines are TBD ...

+
+
+
+ ); +}; diff --git a/services/ui-src/src/components/cards/DownloadTemplate.test.tsx b/services/ui-src/src/components/cards/DownloadTemplate.test.tsx deleted file mode 100644 index 1300b50e..00000000 --- a/services/ui-src/src/components/cards/DownloadTemplate.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { downloadTemplate } from "./TemplateCard"; - -jest.mock("utils", () => ({ - getSignedTemplateUrl: jest.fn(), -})); - -const mockCreateElement = jest.spyOn(document, "createElement"); -const mockClick = jest.fn(); -const mockSetAttribute = jest.fn(); -const mockRemove = jest.fn(); - -describe("downloadTemplate", () => { - beforeEach(() => { - mockCreateElement.mockReturnValue({ - setAttribute: mockSetAttribute, - click: mockClick, - remove: mockRemove, - } as unknown as HTMLAnchorElement); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test("should download the template when called", async () => { - const templateName = "test-template"; - const signedUrl = "https://example.com/signed-url"; - const { getSignedTemplateUrl } = require("utils"); - (getSignedTemplateUrl as jest.Mock).mockResolvedValue(signedUrl); - - await downloadTemplate(templateName); - - expect(getSignedTemplateUrl).toHaveBeenCalledWith(templateName); - expect(mockSetAttribute).toHaveBeenCalledWith("target", "_blank"); - expect(mockSetAttribute).toHaveBeenCalledWith("href", signedUrl); - expect(mockClick).toHaveBeenCalled(); - expect(mockRemove).toHaveBeenCalled(); - }); -}); diff --git a/services/ui-src/src/components/cards/HelpCard.test.tsx b/services/ui-src/src/components/cards/HelpCard.test.tsx index 576c8d0c..fc0b4471 100644 --- a/services/ui-src/src/components/cards/HelpCard.test.tsx +++ b/services/ui-src/src/components/cards/HelpCard.test.tsx @@ -1,18 +1,18 @@ import { render, screen } from "@testing-library/react"; import { testA11y } from "utils/testing/commonTests"; -import { EmailCard } from "components"; +import { HelpCard } from "components"; import { Link } from "@chakra-ui/react"; describe("Test EmailCard", () => { test("Email for EmailCard is visible", () => { render( - + mdct_help@cms.hhs.gov - + ); const link = screen.getByRole("link", { name: "mdct_help@cms.hhs.gov" }); expect(link).toBeVisible(); }); - testA11y(); + testA11y(); }); diff --git a/services/ui-src/src/components/cards/QMSIntroductionCard.test.tsx b/services/ui-src/src/components/cards/QMSIntroductionCard.test.tsx new file mode 100644 index 00000000..fafda4d9 --- /dev/null +++ b/services/ui-src/src/components/cards/QMSIntroductionCard.test.tsx @@ -0,0 +1,19 @@ +import { QmsIntroductionCard } from "./QmsIntroductionCard"; +import { render, screen } from "@testing-library/react"; +import { testA11y } from "utils/testing/commonTests"; +import { RouterWrappedComponent } from "utils/testing/mockRouter"; + +const component = ( + + + +); + +describe("QmsIntroductionCard", () => { + it("should render", () => { + render(component); + expect(screen.getByText("The HCBS is", { exact: false })).toBeVisible(); + }); + + testA11y(component); +}); diff --git a/services/ui-src/src/components/cards/QmsIntroductionCard.tsx b/services/ui-src/src/components/cards/QmsIntroductionCard.tsx new file mode 100644 index 00000000..5d884a38 --- /dev/null +++ b/services/ui-src/src/components/cards/QmsIntroductionCard.tsx @@ -0,0 +1,32 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Accordion, Link } from "@chakra-ui/react"; +import { AccordionItem, ReportIntroCard } from "components"; +import { ReportType } from "types"; +import { ReportIntroCardActions } from "./ReportIntroCardActions"; + +/** + * This card appears on the state user home page. + * It contains text specific to the QMS report. + */ +export const QmsIntroductionCard = () => { + return ( + + The HCBS is ... + + 6071(a)(1) of the Deficit Reduction Act (DRA) + + as "increasing the use of home and community-based, rather than + institutional, long-term care services." + + + +

The HCBS Quality Measure Set will be created and submitted ...

+

The HCBS Quality Measure Set deadlines are TBD ...

+
+
+
+ ); +}; diff --git a/services/ui-src/src/components/cards/ReportIntroCard.test.tsx b/services/ui-src/src/components/cards/ReportIntroCard.test.tsx new file mode 100644 index 00000000..f5d79fa4 --- /dev/null +++ b/services/ui-src/src/components/cards/ReportIntroCard.test.tsx @@ -0,0 +1,50 @@ +import { render, screen } from "@testing-library/react"; +import { ReportIntroCard } from "components"; +import { mockUseStore, RouterWrappedComponent } from "utils/testing/setupJest"; +import { useStore } from "utils"; +import { testA11y } from "utils/testing/commonTests"; + +jest.mock("utils/other/useBreakpoint", () => ({ + useBreakpoint: jest.fn(() => ({ + isDesktop: true, + })), +})); + +jest.mock("utils/state/useStore"); +const mockedUseStore = useStore as jest.MockedFunction; +mockedUseStore.mockReturnValue(mockUseStore); + +const mockUseNavigate = jest.fn(); + +jest.mock("react-router-dom", () => ({ + useNavigate: () => mockUseNavigate, +})); + +const qmsReportTypeCardComponent = ( + + + This is the body of the report intro card. Normally it would contain a + description of the report, as well as an instance of + <IntroCardActions> + + +); + +describe("", () => { + describe("Renders", () => { + beforeEach(() => { + render(qmsReportTypeCardComponent); + }); + + test("QMS ReportTypeCard is visible", () => { + expect(screen.getByText("HCBS Quality Measure Set")).toBeVisible(); + }); + + test("QMS ReportTypeCard image is visible on desktop", () => { + const imageAltText = "Spreadsheet icon"; + expect(screen.getByAltText(imageAltText)).toBeVisible(); + }); + }); + + testA11y(qmsReportTypeCardComponent); +}); diff --git a/services/ui-src/src/components/cards/ReportIntroCard.tsx b/services/ui-src/src/components/cards/ReportIntroCard.tsx new file mode 100644 index 00000000..8cfd3ba9 --- /dev/null +++ b/services/ui-src/src/components/cards/ReportIntroCard.tsx @@ -0,0 +1,59 @@ +import { Flex, Heading, Image } from "@chakra-ui/react"; +import { Card } from "components"; +import { useBreakpoint } from "utils"; +import spreadsheetIcon from "assets/icons/spreadsheet/icon_spreadsheet_gray.svg"; +import { ReactNode } from "react"; + +/** + * This card used on the state user home page. + * Each report type has its own card, + * describing the report and answering common questions (such as due date). + * Each card will also contain a button to download the User Guide, + * and a link to that report type's dashboard. + */ +export const ReportIntroCard = ({ title, children }: Props) => { + const { isDesktop } = useBreakpoint(); + + return ( + + + {isDesktop && ( + + )} + + {title} + {children} + + + + ); +}; + +interface Props { + title: string; + children: ReactNode; +} + +const sx = { + root: { + flexDirection: "row", + }, + spreadsheetIcon: { + marginRight: "2rem", + boxSize: "5.5rem", + }, + cardContentFlex: { + width: "100%", + flexDirection: "column", + }, + cardTitleText: { + marginBottom: "0.5rem", + fontSize: "lg", + fontWeight: "bold", + lineHeight: "1.5", + }, +}; diff --git a/services/ui-src/src/components/cards/ReportIntroCardActions.test.tsx b/services/ui-src/src/components/cards/ReportIntroCardActions.test.tsx new file mode 100644 index 00000000..a0c4cb4e --- /dev/null +++ b/services/ui-src/src/components/cards/ReportIntroCardActions.test.tsx @@ -0,0 +1,98 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { + downloadUserGuide, + ReportIntroCardActions, +} from "./ReportIntroCardActions"; +import { mockUseStore, RouterWrappedComponent } from "utils/testing/setupJest"; +import { useStore, getSignedTemplateUrl } from "utils"; +import { testA11y } from "utils/testing/commonTests"; +import { ReportType } from "types"; + +jest.mock("../../utils/api/requestMethods/getTemplateUrl", () => ({ + getSignedTemplateUrl: jest + .fn() + .mockResolvedValue("https://mdcthcbs.cms.gov/qms/userGuide.pdf"), +})); + +const mockCreateElement = jest.spyOn(document, "createElement"); +const mockClick = jest.fn(); +const mockSetAttribute = jest.fn(); +const mockRemove = jest.fn(); + +jest.mock("utils/other/useBreakpoint", () => ({ + useBreakpoint: jest.fn(() => ({ + isDesktop: true, + })), +})); + +jest.mock("utils/state/useStore"); +const mockedUseStore = useStore as jest.MockedFunction; +mockedUseStore.mockReturnValue(mockUseStore); + +const mockUseNavigate = jest.fn(); + +jest.mock("react-router-dom", () => ({ + useNavigate: () => mockUseNavigate, +})); + +const reportActionsComponent = ( + + + +); + +describe("", () => { + describe("Renders", () => { + beforeEach(() => { + render(reportActionsComponent); + }); + + test("QMS ReportTypeCard link is visible on desktop", () => { + const downloadButton = screen.getByRole("button", { + name: "User Guide and Help File", + }); + expect(downloadButton).toBeVisible(); + }); + + test("QMS ReportTypeCard navigates to next route on link click", async () => { + const dashboardLink = screen.getByRole("button", { + name: "Enter HCBS QMS online", + }); + await userEvent.click(dashboardLink); + const expectedRoute = "/report/QMS/MN"; + expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute); + }); + }); + + describe("downloadTemplate", () => { + beforeEach(() => { + mockCreateElement.mockReturnValueOnce({ + setAttribute: mockSetAttribute, + click: mockClick, + remove: mockRemove, + } as unknown as HTMLAnchorElement); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("should download the template when called", async () => { + const reportType = ReportType.QMS; + + await downloadUserGuide(reportType); + + expect(getSignedTemplateUrl).toHaveBeenCalledWith(reportType); + expect(mockSetAttribute).toHaveBeenCalledWith("target", "_blank"); + expect(mockSetAttribute).toHaveBeenCalledWith( + "href", + "https://mdcthcbs.cms.gov/qms/userGuide.pdf" + ); + expect(mockClick).toHaveBeenCalled(); + expect(mockRemove).toHaveBeenCalled(); + }); + }); + + testA11y(reportActionsComponent); +}); diff --git a/services/ui-src/src/components/cards/ReportIntroCardActions.tsx b/services/ui-src/src/components/cards/ReportIntroCardActions.tsx new file mode 100644 index 00000000..0ab2e9ca --- /dev/null +++ b/services/ui-src/src/components/cards/ReportIntroCardActions.tsx @@ -0,0 +1,78 @@ +import { Button, Flex, Image } from "@chakra-ui/react"; +import downloadIcon from "assets/icons/download/icon_download_primary.svg"; +import nextIcon from "assets/icons/arrows/icon_arrow_next_white.svg"; +import { useNavigate } from "react-router-dom"; +import { ReportType } from "types"; +import { getSignedTemplateUrl, useStore } from "utils"; + +/** + * This component is contained within each card on the stat user home page. + * It has a button to download the user guide for that report type, + * and a link to that report type's dashboard. + */ +export const ReportIntroCardActions = ({ reportType }: Props) => { + const navigate = useNavigate(); + const state = useStore().user?.state; + const dashboardRoute = `/report/${reportType}/${state}`; + + return ( + + + {/* TODO: this Button is for navigation, so it maybe should be a Link instead. */} + + + ); +}; + +export const downloadUserGuide = async (reportType: ReportType) => { + const signedUrl = await getSignedTemplateUrl(reportType); + const link = document.createElement("a"); + link.setAttribute("target", "_blank"); + link.setAttribute("href", signedUrl); + link.click(); + link.remove(); +}; + +interface Props { + reportType: ReportType; +} + +const sx = { + actionsFlex: { + flexFlow: "wrap", + gridGap: "1rem", + justifyContent: "space-between", + margin: "1rem 0 0 1rem", + ".mobile &": { + flexDirection: "column", + }, + }, + userGuideDownloadButton: { + justifyContent: "start", + marginRight: "1rem", + padding: "0", + span: { + marginLeft: "0rem", + marginRight: "0.5rem", + }, + ".mobile &": { + marginRight: "0", + }, + }, +}; diff --git a/services/ui-src/src/components/cards/TaIntroductionCard.test.tsx b/services/ui-src/src/components/cards/TaIntroductionCard.test.tsx new file mode 100644 index 00000000..52d0f04b --- /dev/null +++ b/services/ui-src/src/components/cards/TaIntroductionCard.test.tsx @@ -0,0 +1,19 @@ +import { TaIntroductionCard } from "./TaIntroductionCard"; +import { render, screen } from "@testing-library/react"; +import { testA11y } from "utils/testing/commonTests"; +import { RouterWrappedComponent } from "utils/testing/mockRouter"; + +const component = ( + + + +); + +describe("TaIntroductionCard", () => { + it("should render", () => { + render(component); + expect(screen.getByText("The HCBS is", { exact: false })).toBeVisible(); + }); + + testA11y(component); +}); diff --git a/services/ui-src/src/components/cards/TaIntroductionCard.tsx b/services/ui-src/src/components/cards/TaIntroductionCard.tsx new file mode 100644 index 00000000..a56b5bf6 --- /dev/null +++ b/services/ui-src/src/components/cards/TaIntroductionCard.tsx @@ -0,0 +1,31 @@ +import { Accordion, Link } from "@chakra-ui/react"; +import { AccordionItem, ReportIntroCard } from "components"; +import { ReportType } from "types"; +import { ReportIntroCardActions } from "./ReportIntroCardActions"; + +/** + * This card appears on the state user home page. + * It contains text specific to the TA report. + */ +export const TaIntroductionCard = () => { + return ( + + The HCBS is ... + + 6071(a)(1) of the Deficit Reduction Act (DRA) + + as "increasing the use of home and community-based, rather than + institutional, long-term care services." + + + +

The HCBS Timely Access will be created and submitted ...

+

The HCBS Timely Access deadlines are TBD ...

+
+
+
+ ); +}; diff --git a/services/ui-src/src/components/cards/TemplateCard.test.tsx b/services/ui-src/src/components/cards/TemplateCard.test.tsx deleted file mode 100644 index b599f0e1..00000000 --- a/services/ui-src/src/components/cards/TemplateCard.test.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { TemplateCard } from "components"; -import { mockUseStore, RouterWrappedComponent } from "utils/testing/setupJest"; -import { useStore } from "utils"; -import verbiage from "verbiage/pages/home"; -import { testA11y } from "utils/testing/commonTests"; - -jest.mock("utils/other/useBreakpoint", () => ({ - useBreakpoint: jest.fn(() => ({ - isDesktop: true, - })), -})); - -jest.mock("utils/state/useStore"); -const mockedUseStore = useStore as jest.MockedFunction; -mockedUseStore.mockReturnValue(mockUseStore); - -const mockUseNavigate = jest.fn(); - -jest.mock("react-router-dom", () => ({ - useNavigate: () => mockUseNavigate, -})); - -const qmsTemplateVerbiage = verbiage.cards.QMS; - -const qmsTemplateCardComponent = ( - - - -); - -describe("", () => { - describe("Renders", () => { - beforeEach(() => { - render(qmsTemplateCardComponent); - }); - - test("QMS TemplateCard is visible", () => { - expect(screen.getByText(qmsTemplateVerbiage.title)).toBeVisible(); - }); - - test("QMS TemplateCard image is visible on desktop", () => { - const imageAltText = "Spreadsheet icon"; - expect(screen.getByAltText(imageAltText)).toBeVisible(); - }); - - test("QMS TemplateCard link is visible on desktop", () => { - const templateCardLink = qmsTemplateVerbiage.link.text; - expect(screen.getByText(templateCardLink)).toBeVisible(); - }); - - test("QMS TemplateCard navigates to next route on link click", async () => { - const templateCardLink = screen.getByText(qmsTemplateVerbiage.link.text)!; - await userEvent.click(templateCardLink); - const expectedRoute = "/report/QMS/MN"; - expect(mockUseNavigate).toHaveBeenCalledWith(expectedRoute); - }); - }); - - testA11y(qmsTemplateCardComponent); -}); diff --git a/services/ui-src/src/components/cards/TemplateCard.tsx b/services/ui-src/src/components/cards/TemplateCard.tsx deleted file mode 100644 index 8b345edc..00000000 --- a/services/ui-src/src/components/cards/TemplateCard.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { Button, Flex, Heading, Image, Text, Link } from "@chakra-ui/react"; -import { Card, TemplateCardAccordion } from "components"; -import { useNavigate } from "react-router-dom"; -import { useBreakpoint, getSignedTemplateUrl, useStore } from "utils"; -import { AnyObject } from "types"; -import downloadIcon from "assets/icons/download/icon_download_primary.svg"; -import nextIcon from "assets/icons/arrows/icon_arrow_next_white.svg"; -import spreadsheetIcon from "assets/icons/spreadsheet/icon_spreadsheet_gray.svg"; - -export const downloadTemplate = async (templateName: string) => { - const signedUrl = await getSignedTemplateUrl(templateName); - const link = document.createElement("a"); - link.setAttribute("target", "_blank"); - link.setAttribute("href", signedUrl); - link.click(); - link.remove(); -}; - -export const TemplateCard = ({ - templateName, - verbiage, - cardprops, - isHidden, - ...props -}: Props) => { - const { isDesktop } = useBreakpoint(); - const navigate = useNavigate(); - const store = useStore(); - const user = store.user; - const state = user?.state; - const dashboardPath = verbiage.link.route.replace("{state}", state); - - return ( - - - {isDesktop && ( - - )} - - {verbiage.title} - - {verbiage.body.available} - {/* - {verbiage.linkText} - */} - {verbiage.midText} - - {verbiage.linkText2} - - {/* {verbiage.postLinkText} */} - - - {verbiage.downloadText && ( - - )} - {!isHidden && ( - - )} - - - Notes on when it's due - - - - ); -}; - -interface Props { - verbiage: AnyObject; - isHidden?: boolean; - [key: string]: any; -} - -const sx = { - root: { - flexDirection: "row", - }, - spreadsheetIcon: { - marginRight: "2rem", - boxSize: "5.5rem", - }, - cardContentFlex: { - width: "100%", - flexDirection: "column", - }, - cardTitleText: { - marginBottom: "0.5rem", - fontSize: "lg", - fontWeight: "bold", - lineHeight: "1.5", - }, - actionsFlex: { - flexFlow: "wrap", - gridGap: "1rem", - justifyContent: "space-between", - margin: "1rem 0 0 1rem", - ".mobile &": { - flexDirection: "column", - }, - }, - templateDownloadButton: { - justifyContent: "start", - marginRight: "1rem", - padding: "0", - span: { - marginLeft: "0rem", - marginRight: "0.5rem", - }, - ".mobile &": { - marginRight: "0", - }, - }, - formLink: { - justifyContent: "start", - span: { - marginLeft: "0.5rem", - marginRight: "-0.25rem", - }, - }, - textMargin: { - paddingTop: "1rem", - }, -}; diff --git a/services/ui-src/src/components/forms/AdminDashSelector.test.tsx b/services/ui-src/src/components/forms/AdminDashSelector.test.tsx index 9eb44688..e150e9b2 100644 --- a/services/ui-src/src/components/forms/AdminDashSelector.test.tsx +++ b/services/ui-src/src/components/forms/AdminDashSelector.test.tsx @@ -44,22 +44,19 @@ describe("AdminDashSelector Component", () => { (useNavigate as jest.Mock).mockReturnValue(mockNavigate); }); - const mockVerbiage = { - header: "Select a State and Report", - buttonLabel: "Submit", - }; - test("renders correctly with header and button label", () => { - render(); + render(); - expect(screen.getByText(mockVerbiage.header)).toBeInTheDocument(); expect( - screen.getByRole("button", { name: mockVerbiage.buttonLabel }) + screen.getByText("View State/Territory Reports") + ).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: "Go to Report Dashboard" }) ).toBeInTheDocument(); }); test("allows user to select a state and report", async () => { - render(); + render(); // Select a state const dropdown = screen.getByLabelText( @@ -77,7 +74,7 @@ describe("AdminDashSelector Component", () => { }); test("navigates to the correct report URL on form submission", async () => { - render(); + render(); // Select a state and report const dropdown = screen.getByLabelText("Select state or territory:"); @@ -87,7 +84,7 @@ describe("AdminDashSelector Component", () => { // Submit the form const submitButton = screen.getByRole("button", { - name: mockVerbiage.buttonLabel, + name: "Go to Report Dashboard", }); await userEvent.click(submitButton); @@ -95,10 +92,10 @@ describe("AdminDashSelector Component", () => { expect(mockNavigate).toHaveBeenCalledWith("report/QMS/CA"); }); test("submit button is disabled when no state or report is selected", async () => { - render(); + render(); const submitButton = screen.getByRole("button", { - name: mockVerbiage.buttonLabel, + name: "Go to Report Dashboard", }); expect(submitButton).toBeDisabled(); diff --git a/services/ui-src/src/components/forms/AdminDashSelector.tsx b/services/ui-src/src/components/forms/AdminDashSelector.tsx index af7f5087..523c39c6 100644 --- a/services/ui-src/src/components/forms/AdminDashSelector.tsx +++ b/services/ui-src/src/components/forms/AdminDashSelector.tsx @@ -2,14 +2,10 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import { Box, Button, Flex, Heading } from "@chakra-ui/react"; import { Dropdown, ChoiceList } from "@cmsgov/design-system"; -import { AnyObject, DropdownOptions } from "types"; +import { DropdownOptions } from "types"; import { StateNames } from "../../constants"; -interface FormProps { - verbiage: AnyObject; -} - -export const AdminDashSelector = ({ verbiage }: FormProps) => { +export const AdminDashSelector = () => { const [selectedState, setSelectedState] = useState(""); const [selectedReport, setSelectedReport] = useState(""); const navigate = useNavigate(); @@ -58,7 +54,7 @@ export const AdminDashSelector = ({ verbiage }: FormProps) => { return ( - {verbiage.header} + View State/Territory Reports
@@ -84,7 +80,7 @@ export const AdminDashSelector = ({ verbiage }: FormProps) => { onClick={() => handleSubmit()} disabled={!selectedState || !selectedReport} > - {verbiage.buttonLabel} + Go to Report Dashboard diff --git a/services/ui-src/src/components/index.ts b/services/ui-src/src/components/index.ts index 79252dd7..ff78a98a 100644 --- a/services/ui-src/src/components/index.ts +++ b/services/ui-src/src/components/index.ts @@ -1,6 +1,5 @@ // accordions export { AccordionItem } from "./accordions/AccordionItem"; -export { TemplateCardAccordion } from "./accordions/TemplateCardAccordion"; export { InstructionsAccordion } from "./accordions/InstructionsAccordion"; // alerts export { Alert } from "./alerts/Alert"; @@ -24,8 +23,12 @@ export { AppRoutes } from "./app/AppRoutes"; export { Timeout } from "./layout/Timeout"; // cards export { Card } from "./cards/Card"; -export { HelpCard as EmailCard } from "./cards/HelpCard"; -export { TemplateCard } from "./cards/TemplateCard"; +export { HelpCard } from "./cards/HelpCard"; +export { ReportIntroCard } from "./cards/ReportIntroCard"; +export { QmsIntroductionCard } from "./cards/QmsIntroductionCard"; +export { TaIntroductionCard } from "./cards/TaIntroductionCard"; +export { CiIntroductionCard } from "./cards/CiIntroductionCard"; +export { ReportIntroCardActions } from "./cards/ReportIntroCardActions"; // export export { ExportedReportBanner } from "./export/ExportedReportBanner"; export { ExportedReportWrapper } from "./export/ExportedReportWrapper"; diff --git a/services/ui-src/src/components/layout/HomePage.tsx b/services/ui-src/src/components/layout/HomePage.tsx index cfe2f429..e2a5e38d 100644 --- a/services/ui-src/src/components/layout/HomePage.tsx +++ b/services/ui-src/src/components/layout/HomePage.tsx @@ -2,17 +2,17 @@ import { Box, Collapse, Heading, Link, Text } from "@chakra-ui/react"; import { AdminDashSelector, Banner, + CiIntroductionCard, PageTemplate, - TemplateCard, + QmsIntroductionCard, + TaIntroductionCard, } from "components"; import { useEffect } from "react"; import { checkDateRangeStatus, useStore } from "utils"; -import verbiage from "verbiage/pages/home"; import { useFlags } from "launchdarkly-react-client-sdk"; export const HomePage = () => { const { bannerData, bannerActive, setBannerActive } = useStore(); - const { intro, cards } = verbiage; const { userIsEndUser } = useStore().user ?? {}; const isTAReportActive = useFlags()?.isTaReportActive; @@ -44,28 +44,27 @@ export const HomePage = () => { <> - {intro.header} + Home and Community Based Services (HCBS) Portal - {intro.body.preLinkText} - - {intro.body.linkText} + Get started by completing the Home and Community-Based Services + (HCBS) for your state or territory. Learn more about this + + new data collection tool - {intro.body.postLinkText} + from CMS. - - - {isTAReportActive && ( - - )} - {isCIReportActive && ( - - )} + + {isTAReportActive && } + {isCIReportActive && } ) : ( // show read-only view to non-state users - + )} diff --git a/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx b/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx index 393af69d..99575589 100644 --- a/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx +++ b/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx @@ -1,5 +1,5 @@ import { Accordion, Box, Flex, Heading, Link, Text } from "@chakra-ui/react"; -import { AccordionItem, EmailCard, PageTemplate } from "components"; +import { AccordionItem, HelpCard, PageTemplate } from "components"; import { useBreakpoint } from "utils"; const helpDeskEmailAddress = "mdct_help@cms.hhs.gov"; @@ -19,7 +19,7 @@ export const HelpPage = () => {
- + For technical support and login issues: Email {!isDesktop &&
} @@ -27,8 +27,8 @@ export const HelpPage = () => { {helpDeskEmailAddress}
-
- +
+ For questions about the online form: Email {!isDesktop &&
} @@ -36,7 +36,7 @@ export const HelpPage = () => { {mfpDemoEmailAddress}
-
+ diff --git a/services/ui-src/src/components/report/Elements.tsx b/services/ui-src/src/components/report/Elements.tsx index 8e30aa37..389d4a90 100644 --- a/services/ui-src/src/components/report/Elements.tsx +++ b/services/ui-src/src/components/report/Elements.tsx @@ -1,5 +1,12 @@ import { useNavigate, useParams } from "react-router-dom"; -import { Button, Heading, Stack, Image, Text } from "@chakra-ui/react"; +import { + Button, + Heading, + Stack, + Image, + Text, + Accordion, +} from "@chakra-ui/react"; import { HeaderTemplate, SubHeaderTemplate, @@ -8,8 +15,9 @@ import { ButtonLinkTemplate, PageElement, } from "types"; -import { TemplateCardAccordion } from "components"; +import { AccordionItem } from "components"; import arrowLeftIcon from "assets/icons/arrows/icon_arrow_left_blue.png"; +import { parseCustomHtml } from "utils"; export interface PageElementProps { element: PageElement; @@ -52,9 +60,11 @@ export const paragraphElement = (props: PageElementProps) => { export const accordionElement = (props: PageElementProps) => { const accordion = props.element as AccordionTemplate; return ( - + + + {parseCustomHtml(accordion.value)} + + ); }; diff --git a/services/ui-src/src/types/other.ts b/services/ui-src/src/types/other.ts index c7490bc3..e171558f 100644 --- a/services/ui-src/src/types/other.ts +++ b/services/ui-src/src/types/other.ts @@ -1,7 +1,6 @@ // ALERTS -import { Box } from "@chakra-ui/react"; -import { ComponentProps } from "react"; +import { ReactNode } from "react"; import { StateNames } from "../constants"; export enum AlertTypes { @@ -45,9 +44,9 @@ export interface CustomHtmlElement { children?: CustomHtmlElement[]; } -export interface ErrorVerbiage - extends Pick, "children"> { +export interface ErrorVerbiage { title: string; + children: ReactNode; } export type StateAbbr = keyof typeof StateNames; diff --git a/services/ui-src/src/types/report.ts b/services/ui-src/src/types/report.ts index f23e2588..9760f1e2 100644 --- a/services/ui-src/src/types/report.ts +++ b/services/ui-src/src/types/report.ts @@ -2,7 +2,10 @@ import { StateAbbr } from "./other"; export enum ReportType { QMS = "QMS", + TA = "TA", + CI = "CI", } + export const isReportType = ( reportType: string | undefined ): reportType is ReportType => { diff --git a/services/ui-src/src/verbiage/pages/home.ts b/services/ui-src/src/verbiage/pages/home.ts deleted file mode 100644 index 60689def..00000000 --- a/services/ui-src/src/verbiage/pages/home.ts +++ /dev/null @@ -1,103 +0,0 @@ -export default { - intro: { - header: "Home and Community Based Services (HCBS) Portal", - body: { - preLinkText: - "Get started by completing the Home and Community-Based Services (HCBS) for your state or territory. Learn more about this ", - linkText: "new data collection tool", - linkLocation: - "https://www.medicaid.gov/medicaid/home-community-based-services/index.html", - postLinkText: " from CMS.", - }, - }, - cards: { - QMS: { - title: "HCBS Quality Measure Set", - body: { - available: "The HCBS is ... ", - }, - linkText: "6071(a)(1) of the Deficit Reduction Act (DRA)", - linkLocation: - "https://www.govinfo.gov/content/pkg/PLAW-109publ171/pdf/PLAW-109publ171.pdf", - postLinkText: - ' as "increasing the use of home and community-based, rather than institutional, long-term care services."', - downloadText: "User Guide and Help File", - link: { - text: "Enter HCBS QMS online", - route: "/report/QMS/{state}", - }, - accordion: { - buttonLabel: "When is the HCBS Quality Measure Set due?", - text: [ - { - content: - "The HCBS Quality Measure Set will be created and submitted ...", - }, - { - content: "The HCBS Quality Measure Set deadlines are TBD ...", - }, - ], - }, - }, - TA: { - title: "HCBS Timely Access Report", - body: { - available: "The HCBS is ... ", - }, - linkText: "6071(a)(1) of the Deficit Reduction Act (DRA)", - linkLocation: - "https://www.govinfo.gov/content/pkg/PLAW-109publ171/pdf/PLAW-109publ171.pdf", - postLinkText: - ' as "increasing the use of home and community-based, rather than institutional, long-term care services."', - downloadText: "User Guide and Help File", - link: { - text: "Enter HCBS TA online", - route: "/report/TA/", - }, - accordion: { - buttonLabel: "When is the HCBS Timely Access Report due?", - text: [ - { - content: - "The HCBS Timely Access Report will be created and submitted ...", - }, - { - content: "The HCBS Timely Access Report deadlines are TBD ...", - }, - ], - }, - }, - CI: { - title: "HCBS Critical Incident Report", - body: { - available: "The HCBS is ... ", - }, - linkText: "6071(a)(1) of the Deficit Reduction Act (DRA)", - linkLocation: - "https://www.govinfo.gov/content/pkg/PLAW-109publ171/pdf/PLAW-109publ171.pdf", - postLinkText: - ' as "increasing the use of home and community-based, rather than institutional, long-term care services."', - downloadText: "User Guide and Help File", - link: { - text: "Enter HCBS CI online", - route: "/report/CI/", - }, - accordion: { - buttonLabel: "When is the HCBS Critical Incident Report due?", - text: [ - { - content: - "The HCBS Critical Incident will be created and submitted ...", - }, - { - content: "The HCBS Critical Incident Report deadlines are TBD ...", - }, - ], - }, - }, - }, - readOnly: { - header: "View State/Territory Reports", - buttonLabel: "Go to Report Dashboard", - }, -}; From 7ed5de7327184105637935a194fe15df949afb6e Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Mon, 27 Jan 2025 16:24:18 -0700 Subject: [PATCH 05/17] Inline verbiage for pages: Error, Help, Profile, NotFound --- services/ui-src/src/components/app/Error.tsx | 18 +++++-------- .../components/pages/HelpPage/HelpPage.tsx | 6 ++--- .../pages/NotFound/NotFoundPage.tsx | 27 +++++++++---------- .../components/pages/Profile/ProfilePage.tsx | 15 +++++------ services/ui-src/src/constants.ts | 2 ++ services/ui-src/src/verbiage/errors.tsx | 7 +++-- services/ui-src/src/verbiage/not-found.ts | 11 -------- services/ui-src/src/verbiage/pages/error.ts | 9 ------- services/ui-src/src/verbiage/pages/profile.ts | 9 ------- 9 files changed, 35 insertions(+), 69 deletions(-) delete mode 100644 services/ui-src/src/verbiage/not-found.ts delete mode 100644 services/ui-src/src/verbiage/pages/error.ts delete mode 100644 services/ui-src/src/verbiage/pages/profile.ts diff --git a/services/ui-src/src/components/app/Error.tsx b/services/ui-src/src/components/app/Error.tsx index 0349e893..0a67281c 100644 --- a/services/ui-src/src/components/app/Error.tsx +++ b/services/ui-src/src/components/app/Error.tsx @@ -1,30 +1,26 @@ import { Flex, Heading, Image, Link, Text } from "@chakra-ui/react"; import { PageTemplate } from "components"; -import { createEmailLink } from "utils/other/email"; import warningIcon from "assets/icons/alert/icon_warning.svg"; -import verbiage from "verbiage/pages/error"; +import { HELP_DESK_EMAIL_ADDRESS } from "../../constants"; export const Error = () => { - const { header, subHeading, emailText } = verbiage; - const { preLinkText, helpDeskEmail, postLinkText } = emailText; - return ( - {header} + Error - {subHeading} + Sorry! An error has occurred. - {preLinkText} - - {helpDeskEmail} + Please refresh and try again, or email + + {HELP_DESK_EMAIL_ADDRESS} - {postLinkText} + for help. ); diff --git a/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx b/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx index 99575589..278957d3 100644 --- a/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx +++ b/services/ui-src/src/components/pages/HelpPage/HelpPage.tsx @@ -1,8 +1,8 @@ import { Accordion, Box, Flex, Heading, Link, Text } from "@chakra-ui/react"; import { AccordionItem, HelpCard, PageTemplate } from "components"; +import { HELP_DESK_EMAIL_ADDRESS } from "../../../constants"; import { useBreakpoint } from "utils"; -const helpDeskEmailAddress = "mdct_help@cms.hhs.gov"; const mfpDemoEmailAddress = "MFPDemo@cms.hhs.gov"; export const HelpPage = () => { @@ -23,8 +23,8 @@ export const HelpPage = () => { For technical support and login issues: Email {!isDesktop &&
} - - {helpDeskEmailAddress} + + {HELP_DESK_EMAIL_ADDRESS}
diff --git a/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx b/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx index 974b46b3..d056f122 100644 --- a/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx +++ b/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx @@ -1,34 +1,33 @@ -// components import { Flex, Heading, Image, Link, Text, Box } from "@chakra-ui/react"; import { PageTemplate } from "components"; -// utils -import { createEmailLink } from "utils/other/email"; -// assets import warningIcon from "assets/icons/alert/icon_warning.svg"; -import verbiage from "./../../../verbiage/not-found"; +import { HELP_DESK_EMAIL_ADDRESS } from "../../../constants"; export const NotFoundPage = () => { - const { header, subHeading, emailText, body } = verbiage; - const { preLinkText, cmsEmail, postLinkText } = emailText; - return ( - {header} + Page not found - {subHeading} + Sorry, the page you're looking for couldn't be found. It's possible that + this page has moved, or the address may have been typed incorrectly. - {preLinkText} - {cmsEmail} - {postLinkText} + Please email + + {HELP_DESK_EMAIL_ADDRESS} + + for help or feedback. + + + Note: If you were using a bookmark, please reset it once you find the + correct page. - {body} ); diff --git a/services/ui-src/src/components/pages/Profile/ProfilePage.tsx b/services/ui-src/src/components/pages/Profile/ProfilePage.tsx index 5b7d06e0..c6deae96 100644 --- a/services/ui-src/src/components/pages/Profile/ProfilePage.tsx +++ b/services/ui-src/src/components/pages/Profile/ProfilePage.tsx @@ -1,8 +1,8 @@ import { useNavigate } from "react-router-dom"; import { Button, Heading, Link, Text } from "@chakra-ui/react"; import { PageTemplate, Table } from "components"; -import { createEmailLink, useStore } from "utils"; -import verbiage from "verbiage/pages/profile"; +import { useStore } from "utils"; +import { HELP_DESK_EMAIL_ADDRESS } from "../../../constants"; export const ProfilePage = () => { const navigate = useNavigate(); @@ -10,8 +10,6 @@ export const ProfilePage = () => { const { email, given_name, family_name, userRole, state, userIsAdmin } = useStore().user ?? {}; - const { intro } = verbiage; - const tableContent = { caption: "Profile Account Information", bodyRows: [ @@ -26,12 +24,13 @@ export const ProfilePage = () => { return ( - {intro.header} + My Account - {intro.body}{" "} - - {intro.email.address} + If any information is incorrect, please contact the Managed Care + Reporting (MCR) Help Desk at + + {HELP_DESK_EMAIL_ADDRESS} . diff --git a/services/ui-src/src/constants.ts b/services/ui-src/src/constants.ts index 8aba192d..0e24ef6c 100644 --- a/services/ui-src/src/constants.ts +++ b/services/ui-src/src/constants.ts @@ -6,6 +6,8 @@ export const PRODUCTION_HOST_DOMAIN = "mdcthcbs.cms.gov"; export const notAnsweredText = "Not answered"; +export const HELP_DESK_EMAIL_ADDRESS = "mdct_help@cms.hhs.gov" as const; + // STATES export const StateNames = { AL: "Alabama", diff --git a/services/ui-src/src/verbiage/errors.tsx b/services/ui-src/src/verbiage/errors.tsx index 35f4767b..d2e3c300 100644 --- a/services/ui-src/src/verbiage/errors.tsx +++ b/services/ui-src/src/verbiage/errors.tsx @@ -1,8 +1,7 @@ import { Link } from "@chakra-ui/react"; +import { HELP_DESK_EMAIL_ADDRESS } from "../constants"; import { ErrorVerbiage } from "types"; -const helpDeskEmailAddress = "mdct_help@cms.hhs.gov"; - export const genericErrorContent = ( <>

Something went wrong on our end. Refresh your screen and try again.

@@ -10,12 +9,12 @@ export const genericErrorContent = ( If this persists, contact the MDCT Help Desk with questions or to request technical assistance by emailing - {helpDeskEmailAddress} + {HELP_DESK_EMAIL_ADDRESS} .

diff --git a/services/ui-src/src/verbiage/not-found.ts b/services/ui-src/src/verbiage/not-found.ts deleted file mode 100644 index a9e00004..00000000 --- a/services/ui-src/src/verbiage/not-found.ts +++ /dev/null @@ -1,11 +0,0 @@ -export default { - header: "Page not found", - subHeading: - "Sorry, the page you're looking for couldn't be found. It's possible that this page has moved, or the address may have been typed incorrectly.", - emailText: { - preLinkText: "Please email ", - cmsEmail: "mdct_help@cms.hhs.gov", - postLinkText: " for help or feedback.", - }, - body: "Note: If you were using a bookmark, please reset it once you find the correct page.", -}; diff --git a/services/ui-src/src/verbiage/pages/error.ts b/services/ui-src/src/verbiage/pages/error.ts deleted file mode 100644 index 406b53b5..00000000 --- a/services/ui-src/src/verbiage/pages/error.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default { - header: "Error", - subHeading: "Sorry! An error has occurred.", - emailText: { - preLinkText: "Please refresh and try again, or email ", - helpDeskEmail: "mdct_help@cms.hhs.gov", - postLinkText: " for help.", - }, -}; diff --git a/services/ui-src/src/verbiage/pages/profile.ts b/services/ui-src/src/verbiage/pages/profile.ts deleted file mode 100644 index 539c2468..00000000 --- a/services/ui-src/src/verbiage/pages/profile.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default { - intro: { - header: "My Account", - body: "If any information is incorrect, please contact the Managed Care Reporting (MCR) Help Desk at", - email: { - address: "mdct_help@cms.hhs.gov", - }, - }, -}; From a5f1d834fcc505231811850702a004e1c823cc7a Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Mon, 27 Jan 2025 16:51:19 -0700 Subject: [PATCH 06/17] Inline verbiage for Dashboard page --- .../components/accordions/AccordionItem.tsx | 5 +- .../accordions/InstructionsAccordion.test.tsx | 33 --------- .../accordions/InstructionsAccordion.tsx | 72 ------------------- .../pages/Dashboard/DashboardPage.tsx | 66 ++++++++++++----- .../ui-src/src/verbiage/pages/accordion.ts | 24 ------- .../ui-src/src/verbiage/pages/dashboard.ts | 13 ---- 6 files changed, 51 insertions(+), 162 deletions(-) delete mode 100644 services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx delete mode 100644 services/ui-src/src/components/accordions/InstructionsAccordion.tsx delete mode 100644 services/ui-src/src/verbiage/pages/accordion.ts delete mode 100644 services/ui-src/src/verbiage/pages/dashboard.ts diff --git a/services/ui-src/src/components/accordions/AccordionItem.tsx b/services/ui-src/src/components/accordions/AccordionItem.tsx index 65f82ba6..c863284c 100644 --- a/services/ui-src/src/components/accordions/AccordionItem.tsx +++ b/services/ui-src/src/components/accordions/AccordionItem.tsx @@ -1,4 +1,4 @@ -import { ReactChild } from "react"; +import { ComponentProps, ReactChild } from "react"; import { AccordionButton, AccordionItem as AccordionItemRoot, @@ -33,9 +33,8 @@ export const AccordionItem = ({ label, children, ...props }: Props) => { ); }; -interface Props { +interface Props extends ComponentProps { children?: ReactChild | ReactChild[]; - [key: string]: any; label?: string; } diff --git a/services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx b/services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx deleted file mode 100644 index e162b243..00000000 --- a/services/ui-src/src/components/accordions/InstructionsAccordion.test.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { InstructionsAccordion } from "components"; -import { mockAccordion } from "utils/testing/setupJest"; -import { testA11y } from "utils/testing/commonTests"; - -const accordionComponent = ; - -describe("", () => { - beforeEach(() => { - render(accordionComponent); - }); - - test("Accordion is visible", () => { - expect(screen.getByText(mockAccordion.buttonLabel)).toBeVisible(); - }); - - test("Accordion default closed state only shows the question", () => { - expect(screen.getByText(mockAccordion.buttonLabel)).toBeVisible(); - expect(screen.getByText(mockAccordion.text)).not.toBeVisible(); - }); - - test("Accordion should show answer on click", async () => { - const accordionQuestion = screen.getByText(mockAccordion.buttonLabel); - expect(accordionQuestion).toBeVisible(); - expect(screen.getByText(mockAccordion.text)).not.toBeVisible(); - await userEvent.click(accordionQuestion); - expect(accordionQuestion).toBeVisible(); - expect(screen.getByText(mockAccordion.text)).toBeVisible(); - }); - - testA11y(accordionComponent); -}); diff --git a/services/ui-src/src/components/accordions/InstructionsAccordion.tsx b/services/ui-src/src/components/accordions/InstructionsAccordion.tsx deleted file mode 100644 index 32c1ebb8..00000000 --- a/services/ui-src/src/components/accordions/InstructionsAccordion.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { Accordion, Box, ListItem, UnorderedList } from "@chakra-ui/react"; -import { AccordionItem } from "components"; -import { AnyObject } from "types"; -import { parseCustomHtml, sanitizeAndParseHtml } from "utils"; - -export const InstructionsAccordion = ({ verbiage, ...props }: Props) => { - const { buttonLabel, intro, list, text } = verbiage; - return ( - - - {parseCustomHtml(intro)} - {list && parseList(list)} - {text && {parseCustomHtml(text)}} - - - ); -}; - -export const parseList = (list: any) => { - return ( - - {list?.map((listItem: string | AnyObject, index: number) => - typeof listItem === "string" ? ( - {sanitizeAndParseHtml(listItem)} - ) : ( - parseList(listItem) - ) - )} - - ); -}; - -interface Props { - verbiage: AnyObject; - [key: string]: any; -} - -const sx = { - root: { - marginTop: "2rem", - color: "palette.base", - }, - item: { - marginBottom: "1.5rem", - borderStyle: "none", - }, - textBox: { - ".mobile &": { - paddingLeft: "1rem", - }, - a: { - color: "palette.primary", - textDecoration: "underline", - }, - header: { - marginBottom: "1.5rem", - }, - p: { - marginBottom: "1.5rem", - }, - }, - text: { - marginBottom: "1rem", - }, - list: { - paddingLeft: "1rem", - margin: "1.5rem", - li: { - marginBottom: "1.25rem", - }, - }, -}; diff --git a/services/ui-src/src/components/pages/Dashboard/DashboardPage.tsx b/services/ui-src/src/components/pages/Dashboard/DashboardPage.tsx index 8437b085..13232fc5 100644 --- a/services/ui-src/src/components/pages/Dashboard/DashboardPage.tsx +++ b/services/ui-src/src/components/pages/Dashboard/DashboardPage.tsx @@ -4,9 +4,9 @@ import { StateNames } from "../../../constants"; import { isReportType, isStateAbbr, Report } from "types"; import { PageTemplate, - InstructionsAccordion, DashboardTable, AddEditReportModal, + AccordionItem, } from "components"; import { Box, @@ -17,22 +17,20 @@ import { Text, Flex, useDisclosure, + Accordion, } from "@chakra-ui/react"; -import { parseCustomHtml, useStore } from "utils"; -import dashboardVerbiage from "verbiage/pages/dashboard"; -import accordion from "verbiage/pages/accordion"; +import { useStore } from "utils"; import arrowLeftIcon from "assets/icons/arrows/icon_arrow_left_blue.png"; import { getReportsForState } from "utils/api/requestMethods/report"; export const DashboardPage = () => { - const { userIsAdmin, userIsEndUser } = useStore().user ?? {}; + const { userIsEndUser } = useStore().user ?? {}; const { reportType, state } = useParams(); const [isLoading, setIsLoading] = useState(true); const [reports, setReports] = useState([]); const [selectedReport, setSelectedReport] = useState( undefined ); - const { intro, body } = dashboardVerbiage; const fullStateName = StateNames[state as keyof typeof StateNames]; useEffect(() => { @@ -74,17 +72,23 @@ export const DashboardPage = () => { - {fullStateName} {intro.header} + {fullStateName} Quality Measure Set Report - - {parseCustomHtml(intro.body)} + > + + +

+ [Optional - Include instructions that would support the state in + the completion of the report] +

+
+
+
{!isLoading && ( @@ -94,11 +98,16 @@ export const DashboardPage = () => { readOnlyUser={!userIsEndUser} /> )} - {!reports?.length && {body.empty}} + {!reports?.length && ( + + Keep track of your Quality Measure Set Reports, once you start a + report you can access it here. + + )} {userIsEndUser && ( )} @@ -151,4 +160,27 @@ const sx = { }, }, }, + accordion: { + marginTop: "2rem", + color: "palette.base", + }, + accordionItem: { + marginBottom: "1.5rem", + borderStyle: "none", + }, + accordionPanel: { + ".mobile &": { + paddingLeft: "1rem", + }, + a: { + color: "palette.primary", + textDecoration: "underline", + }, + header: { + marginBottom: "1.5rem", + }, + p: { + marginBottom: "1.5rem", + }, + }, }; diff --git a/services/ui-src/src/verbiage/pages/accordion.ts b/services/ui-src/src/verbiage/pages/accordion.ts deleted file mode 100644 index 540d0de8..00000000 --- a/services/ui-src/src/verbiage/pages/accordion.ts +++ /dev/null @@ -1,24 +0,0 @@ -export default { - adminDashboard: { - buttonLabel: "Instructions", - intro: [ - { - type: "text", - as: "p", - content: - "[Optional - Include instructions that would support the state in the completion of the report]", - }, - ], - }, - stateUserDashboard: { - buttonLabel: "Instructions", - intro: [ - { - type: "text", - as: "p", - content: - "[Optional - Include instructions that would support the state in the completion of the report]", - }, - ], - }, -}; diff --git a/services/ui-src/src/verbiage/pages/dashboard.ts b/services/ui-src/src/verbiage/pages/dashboard.ts deleted file mode 100644 index 640f37c7..00000000 --- a/services/ui-src/src/verbiage/pages/dashboard.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default { - intro: { - header: "Quality Measure Set Report", - body: [], - }, - body: { - empty: - "Keep track of your Quality Measure Set Reports, once you start a report you can access it here.", - link: { - callToActionText: "Start Quality Measure Set Report", - }, - }, -}; From 4953b8e76b5e7e636429b86acdc0dbc16ee9110f Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Mon, 27 Jan 2025 17:08:36 -0700 Subject: [PATCH 07/17] Prefer explicit prop definitions to extended ComponentProps --- .../src/components/accordions/AccordionItem.tsx | 6 ++++-- services/ui-src/src/components/alerts/Alert.tsx | 12 ++++++------ services/ui-src/src/components/cards/HelpCard.tsx | 5 +++-- services/ui-src/src/components/index.ts | 1 - 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/services/ui-src/src/components/accordions/AccordionItem.tsx b/services/ui-src/src/components/accordions/AccordionItem.tsx index c863284c..5996e569 100644 --- a/services/ui-src/src/components/accordions/AccordionItem.tsx +++ b/services/ui-src/src/components/accordions/AccordionItem.tsx @@ -1,8 +1,9 @@ -import { ComponentProps, ReactChild } from "react"; +import { ReactChild } from "react"; import { AccordionButton, AccordionItem as AccordionItemRoot, AccordionPanel, + CSSObject, Image, Text, } from "@chakra-ui/react"; @@ -33,9 +34,10 @@ export const AccordionItem = ({ label, children, ...props }: Props) => { ); }; -interface Props extends ComponentProps { +interface Props { children?: ReactChild | ReactChild[]; label?: string; + sx?: CSSObject; } const sx = { diff --git a/services/ui-src/src/components/alerts/Alert.tsx b/services/ui-src/src/components/alerts/Alert.tsx index 796fe0c5..4f995435 100644 --- a/services/ui-src/src/components/alerts/Alert.tsx +++ b/services/ui-src/src/components/alerts/Alert.tsx @@ -3,6 +3,7 @@ import { AlertDescription, AlertTitle, Box, + CSSObject, Flex, Image, Link, @@ -10,7 +11,7 @@ import { } from "@chakra-ui/react"; import { AlertTypes } from "types"; import alertIcon from "assets/icons/alert/icon_alert.svg"; -import { ComponentProps } from "react"; +import { ReactNode } from "react"; export const Alert = ({ status = AlertTypes.INFO, @@ -53,16 +54,15 @@ export const Alert = ({ ); }; -interface Props - extends Pick< - ComponentProps, - "children" | "className" | "sx" - > { +interface Props { status?: AlertTypes; title?: string; link?: string; showIcon?: boolean; icon?: string; + children?: ReactNode; + className?: string; + sx?: CSSObject; } const sx = { diff --git a/services/ui-src/src/components/cards/HelpCard.tsx b/services/ui-src/src/components/cards/HelpCard.tsx index 6711ba8b..ae3c2d3d 100644 --- a/services/ui-src/src/components/cards/HelpCard.tsx +++ b/services/ui-src/src/components/cards/HelpCard.tsx @@ -2,7 +2,7 @@ import { Flex, Image } from "@chakra-ui/react"; import { Card } from "components"; import spreadsheetIcon from "assets/icons/spreadsheet/icon_spreadsheet_gray.svg"; import settingsIcon from "assets/icons/icon_wrench_gear.svg"; -import { ComponentProps } from "react"; +import { ReactNode } from "react"; const iconMap = { spreadsheet: { @@ -29,8 +29,9 @@ export const HelpCard = ({ icon, children }: Props) => { ); }; -interface Props extends Pick, "children"> { +interface Props { icon: keyof typeof iconMap; + children: ReactNode; } const sx = { diff --git a/services/ui-src/src/components/index.ts b/services/ui-src/src/components/index.ts index ff78a98a..378b1bd7 100644 --- a/services/ui-src/src/components/index.ts +++ b/services/ui-src/src/components/index.ts @@ -1,6 +1,5 @@ // accordions export { AccordionItem } from "./accordions/AccordionItem"; -export { InstructionsAccordion } from "./accordions/InstructionsAccordion"; // alerts export { Alert } from "./alerts/Alert"; export { ErrorAlert } from "./alerts/ErrorAlert"; From 0d04dc9a28097f36f0e70e6a8b547ca5b9a94211 Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Tue, 28 Jan 2025 10:08:01 -0700 Subject: [PATCH 08/17] Make AccordionItem sx prop more explicit --- services/ui-src/src/components/accordions/AccordionItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/ui-src/src/components/accordions/AccordionItem.tsx b/services/ui-src/src/components/accordions/AccordionItem.tsx index 5996e569..1425d751 100644 --- a/services/ui-src/src/components/accordions/AccordionItem.tsx +++ b/services/ui-src/src/components/accordions/AccordionItem.tsx @@ -10,9 +10,9 @@ import { import plusIcon from "assets/icons/accordion/icon_plus.svg"; import minusIcon from "assets/icons/accordion/icon_minus.svg"; -export const AccordionItem = ({ label, children, ...props }: Props) => { +export const AccordionItem = ({ label, children, sx: sxOverride }: Props) => { return ( - + {({ isExpanded }) => ( <> Date: Tue, 28 Jan 2025 12:17:55 -0700 Subject: [PATCH 09/17] Make props more explicit for Alert and ErrorAlert --- .../ui-src/src/components/alerts/Alert.tsx | 20 +++++++++---------- .../src/components/alerts/ErrorAlert.tsx | 11 +++++----- .../ui-src/src/components/banners/Banner.tsx | 4 ++-- .../src/components/logins/LoginCognito.tsx | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/services/ui-src/src/components/alerts/Alert.tsx b/services/ui-src/src/components/alerts/Alert.tsx index 4f995435..6b7ecf8e 100644 --- a/services/ui-src/src/components/alerts/Alert.tsx +++ b/services/ui-src/src/components/alerts/Alert.tsx @@ -15,20 +15,20 @@ import { ReactNode } from "react"; export const Alert = ({ status = AlertTypes.INFO, + sx: sxOverride, + className, + showIcon = true, + icon, title, children, link, - showIcon = true, - icon, - ...props }: Props) => { return ( {showIcon && ( @@ -56,13 +56,13 @@ export const Alert = ({ interface Props { status?: AlertTypes; - title?: string; - link?: string; + sx?: CSSObject; showIcon?: boolean; icon?: string; - children?: ReactNode; + title?: string; className?: string; - sx?: CSSObject; + children?: ReactNode; + link?: string; } const sx = { diff --git a/services/ui-src/src/components/alerts/ErrorAlert.tsx b/services/ui-src/src/components/alerts/ErrorAlert.tsx index 99249142..0371a282 100644 --- a/services/ui-src/src/components/alerts/ErrorAlert.tsx +++ b/services/ui-src/src/components/alerts/ErrorAlert.tsx @@ -1,4 +1,4 @@ -import { Box, Collapse } from "@chakra-ui/react"; +import { Box, Collapse, CSSObject } from "@chakra-ui/react"; import { Alert } from "components"; import { useRef } from "react"; import { AlertTypes, ErrorVerbiage } from "types"; @@ -7,7 +7,7 @@ export const ErrorAlert = ({ error, variant = "inline", sxOverride, - ...props + alertSxOverride, }: Props) => { // Focus the alert when an error is given const ref = useRef(null); @@ -25,8 +25,7 @@ export const ErrorAlert = ({ title={error.title} showIcon={false} className={variant} - sx={sx.root} - {...props} + sx={alertSxOverride ?? sx.root} > {error.children} @@ -39,8 +38,8 @@ export const ErrorAlert = ({ interface Props { error?: ErrorVerbiage; variant?: "inline" | "toast"; - sxOverride?: any; - [key: string]: any; + sxOverride?: CSSObject; + alertSxOverride?: CSSObject; } const sx = { diff --git a/services/ui-src/src/components/banners/Banner.tsx b/services/ui-src/src/components/banners/Banner.tsx index 6d32d358..82a72fbf 100644 --- a/services/ui-src/src/components/banners/Banner.tsx +++ b/services/ui-src/src/components/banners/Banner.tsx @@ -1,12 +1,12 @@ import { Alert } from "components"; import { BannerData } from "types"; -export const Banner = ({ bannerData, ...props }: Props) => { +export const Banner = ({ bannerData }: Props) => { if (bannerData) { const { title, description, link } = bannerData; return ( bannerData && ( - + {description} ) diff --git a/services/ui-src/src/components/logins/LoginCognito.tsx b/services/ui-src/src/components/logins/LoginCognito.tsx index 5b40c19a..767c69f1 100644 --- a/services/ui-src/src/components/logins/LoginCognito.tsx +++ b/services/ui-src/src/components/logins/LoginCognito.tsx @@ -47,7 +47,7 @@ export const LoginCognito = () => { Log In with Cognito - +
handleLogin(event)}> From f10ede7b6d304769bde37b2de0ff6cf02bc55997 Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Wed, 29 Jan 2025 15:00:40 -0700 Subject: [PATCH 14/17] Fix whitespace on ProfilePage --- services/ui-src/src/components/pages/Profile/ProfilePage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/ui-src/src/components/pages/Profile/ProfilePage.tsx b/services/ui-src/src/components/pages/Profile/ProfilePage.tsx index c6deae96..746831bd 100644 --- a/services/ui-src/src/components/pages/Profile/ProfilePage.tsx +++ b/services/ui-src/src/components/pages/Profile/ProfilePage.tsx @@ -28,7 +28,7 @@ export const ProfilePage = () => { If any information is incorrect, please contact the Managed Care - Reporting (MCR) Help Desk at + Reporting (MCR) Help Desk at{" "} {HELP_DESK_EMAIL_ADDRESS} From 81c3dc6fe5279afa7ef93f5a4dfd35ea906ac087 Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Wed, 29 Jan 2025 15:16:18 -0700 Subject: [PATCH 15/17] Fix whitespace around email link on NotFoundPage --- .../ui-src/src/components/pages/NotFound/NotFoundPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx b/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx index d056f122..cce5fe33 100644 --- a/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx +++ b/services/ui-src/src/components/pages/NotFound/NotFoundPage.tsx @@ -18,10 +18,10 @@ export const NotFoundPage = () => { - Please email + Please email{" "} {HELP_DESK_EMAIL_ADDRESS} - + {" "} for help or feedback. From 8423f1635680d948fea69381cb2886030d048f75 Mon Sep 17 00:00:00 2001 From: benmartin-coforma Date: Wed, 29 Jan 2025 15:19:33 -0700 Subject: [PATCH 16/17] Fix whitespace around email link for banner errors --- services/ui-src/src/verbiage/errors.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/ui-src/src/verbiage/errors.tsx b/services/ui-src/src/verbiage/errors.tsx index d2e3c300..b5a334a5 100644 --- a/services/ui-src/src/verbiage/errors.tsx +++ b/services/ui-src/src/verbiage/errors.tsx @@ -7,7 +7,7 @@ export const genericErrorContent = (

Something went wrong on our end. Refresh your screen and try again.

If this persists, contact the MDCT Help Desk with questions or to request - technical assistance by emailing + technical assistance by emailing{" "} Date: Wed, 29 Jan 2025 15:23:10 -0700 Subject: [PATCH 17/17] Fix whitespace around email link for Error.tsx --- services/ui-src/src/components/app/Error.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/ui-src/src/components/app/Error.tsx b/services/ui-src/src/components/app/Error.tsx index 0a67281c..36659495 100644 --- a/services/ui-src/src/components/app/Error.tsx +++ b/services/ui-src/src/components/app/Error.tsx @@ -16,10 +16,10 @@ export const Error = () => { Sorry! An error has occurred. - Please refresh and try again, or email + Please refresh and try again, or email{" "} {HELP_DESK_EMAIL_ADDRESS} - + {" "} for help.