-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(initial submission): Waiver & SPA options, Landing pages for ext…
…ernal app submissions (#145) * Set up routing for spa submission secondary options * Wire up landing pages and routing * Populate landing page content and styles * fix button text * touchups * Set up link to anchor to proper FAQ section * Grammar fix * Add waiver options * Wire up routing for waiver options * Fix b-cap waiver options * Prettier code * Text updates re:testing
- Loading branch information
Kevin Haube
authored
Oct 4, 2023
1 parent
001bfff
commit 9d00dbc
Showing
15 changed files
with
600 additions
and
180 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 59 additions & 54 deletions
113
src/services/ui/src/components/Cards/OptionCard.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,63 @@ | ||
import {describe, test, expect, beforeEach} from "vitest"; | ||
import {render, screen} from "@testing-library/react"; | ||
import {OptionCard, OptionFieldset} from "@/components/Cards/OptionCard"; | ||
import {ROUTES} from "@/routes"; | ||
import {BrowserRouter} from "react-router-dom"; | ||
import { describe, test, expect, beforeEach } from "vitest"; | ||
import { render, screen } from "@testing-library/react"; | ||
import { OptionCard, OptionFieldset } from "@/components/Cards/OptionCard"; | ||
import { ROUTES } from "@/routes"; | ||
import { BrowserRouter } from "react-router-dom"; | ||
|
||
describe("OptionCard Component System", () => { | ||
describe("OptionFieldset", () => { | ||
beforeEach(() => { | ||
render( | ||
<OptionFieldset legend={"Test Legend"}> | ||
Testing rendering of children | ||
</OptionFieldset>); | ||
}); | ||
test("legend prop populates legend element in fieldset", () => { | ||
expect(screen.getByRole("group", { name: "Test Legend" })).toBeInTheDocument(); | ||
}); | ||
test("renders children", () => { | ||
expect(screen.getByText("Testing rendering of children")).toBeInTheDocument(); | ||
}); | ||
describe("OptionFieldset", () => { | ||
beforeEach(() => { | ||
render( | ||
<OptionFieldset legend={"Test Legend"}> | ||
Testing rendering of children | ||
</OptionFieldset> | ||
); | ||
}); | ||
describe("OptionCard", () => { | ||
const renderOptionCard = (altBg: boolean) => { | ||
render( | ||
<BrowserRouter> | ||
<OptionCard | ||
linkTo={ROUTES.HOME} | ||
title={"Test Card Title"} | ||
description={"Test Card Description"} | ||
altBg={altBg} | ||
/> | ||
</BrowserRouter> | ||
); | ||
}; | ||
test("default background is white", () => { | ||
renderOptionCard(false); | ||
const innerWrapper = screen.getByTestId("card-inner-wrapper"); | ||
expect(innerWrapper.className.includes("bg-white")).toBeTruthy(); | ||
expect(innerWrapper.className.includes("bg-slate-100")).toBeFalsy(); | ||
}); | ||
test("option for alternate background color", () => { | ||
renderOptionCard(true); | ||
const innerWrapper = screen.getByTestId("card-inner-wrapper"); | ||
expect(innerWrapper.className.includes("bg-slate-100")).toBeTruthy(); | ||
expect(innerWrapper.className.includes("bg-white")).toBeFalsy(); | ||
}); | ||
test("title is rendered as an h3 and styled", () => { | ||
renderOptionCard(false); | ||
const header = screen.getByRole("heading", {level: 3}); | ||
expect(header).toHaveTextContent("Test Card Title"); | ||
expect(header).toHaveClass("text-lg text-sky-600 font-bold my-2"); | ||
}); | ||
test("description is rendered", () => { | ||
renderOptionCard(false); | ||
expect(screen.getByText("Test Card Description")).toBeInTheDocument(); | ||
}); | ||
test("legend prop populates legend element in fieldset", () => { | ||
expect( | ||
screen.getByRole("group", { name: "Test Legend" }) | ||
).toBeInTheDocument(); | ||
}); | ||
}); | ||
test("renders children", () => { | ||
expect( | ||
screen.getByText("Testing rendering of children") | ||
).toBeInTheDocument(); | ||
}); | ||
}); | ||
describe("OptionCard", () => { | ||
const renderOptionCard = (altBg: boolean) => { | ||
render( | ||
<BrowserRouter> | ||
<OptionCard | ||
linkTo={ROUTES.HOME} | ||
title={"Test Card Title"} | ||
description={"Test Card Description"} | ||
altBg={altBg} | ||
/> | ||
</BrowserRouter> | ||
); | ||
}; | ||
test("default background is white", () => { | ||
renderOptionCard(false); | ||
const innerWrapper = screen.getByTestId("card-inner-wrapper"); | ||
expect(innerWrapper.className.includes("bg-white")).toBeTruthy(); | ||
expect(innerWrapper.className.includes("bg-slate-100")).toBeFalsy(); | ||
}); | ||
test("option for alternate background color", () => { | ||
renderOptionCard(true); | ||
const innerWrapper = screen.getByTestId("card-inner-wrapper"); | ||
expect(innerWrapper.className.includes("bg-slate-100")).toBeTruthy(); | ||
expect(innerWrapper.className.includes("bg-white")).toBeFalsy(); | ||
}); | ||
test("title is rendered as an h3 and styled", () => { | ||
renderOptionCard(false); | ||
const header = screen.getByRole("heading", { level: 3 }); | ||
expect(header).toHaveTextContent("Test Card Title"); | ||
expect(header).toHaveClass("text-lg text-sky-600 font-bold my-2"); | ||
}); | ||
test("description is rendered", () => { | ||
renderOptionCard(false); | ||
expect(screen.getByText("Test Card Description")).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,56 @@ | ||
import React, {PropsWithChildren, ReactNode} from "react"; | ||
import {Link} from "react-router-dom"; | ||
import {ROUTES} from "@/routes"; | ||
import {ChevronRight} from "lucide-react"; | ||
import {CardWithTopBorder} from "@/components"; | ||
import React, { PropsWithChildren, ReactNode } from "react"; | ||
import { Link } from "react-router-dom"; | ||
import { ROUTES } from "@/routes"; | ||
import { ChevronRight } from "lucide-react"; | ||
import { CardWithTopBorder } from "@/components"; | ||
|
||
export type OptionCardFieldsetProps = PropsWithChildren<{ | ||
legend: string; | ||
legend: string; | ||
}>; | ||
export type MACFieldsetOption = { | ||
title: string, | ||
description: ReactNode, | ||
linkTo: ROUTES | string; | ||
altBg?: boolean; | ||
title: string; | ||
description: ReactNode; | ||
linkTo: ROUTES | string; | ||
altBg?: boolean; | ||
}; | ||
/** A fieldset for nesting {@link OptionCard} with MACCard styling */ | ||
export const OptionFieldset = ({ | ||
children, | ||
legend, | ||
children, | ||
legend, | ||
}: OptionCardFieldsetProps) => { | ||
return ( | ||
<section className="max-w-3xl mx-auto mb-6"> | ||
<fieldset> | ||
<legend className="text-2xl font-medium py-8">{legend}</legend> | ||
<CardWithTopBorder> | ||
{children} | ||
</CardWithTopBorder> | ||
</fieldset> | ||
</section> | ||
); | ||
return ( | ||
<section className="max-w-3xl mx-auto mb-6"> | ||
<fieldset> | ||
<legend className="text-2xl font-medium py-8">{legend}</legend> | ||
<CardWithTopBorder>{children}</CardWithTopBorder> | ||
</fieldset> | ||
</section> | ||
); | ||
}; | ||
/** An element for use in options lists that lead to a destination, such as | ||
* the new submission options found in {@link NewSubmissionInitialOptions} */ | ||
export const OptionCard = ({ | ||
title, | ||
description, | ||
linkTo, | ||
altBg = false | ||
title, | ||
description, | ||
linkTo, | ||
altBg = false, | ||
}: MACFieldsetOption) => { | ||
return ( | ||
<label> | ||
<Link to={linkTo}> | ||
<div data-testid={"card-inner-wrapper"} className={`flex items-center justify-between gap-6 px-6 py-4 ${altBg ? "bg-slate-100" : "bg-white"} hover:bg-sky-100`}> | ||
<div> | ||
<h3 className="text-lg text-sky-600 font-bold my-2"> | ||
{title} | ||
</h3> | ||
<p className="my-2 text-slate-600"> | ||
{description} | ||
</p> | ||
</div> | ||
<ChevronRight className="text-sky-600 w-8 h-8" /> | ||
</div> | ||
</Link> | ||
</label> | ||
); | ||
}; | ||
return ( | ||
<label> | ||
<Link to={linkTo} relative={"path"}> | ||
<div | ||
data-testid={"card-inner-wrapper"} | ||
className={`flex items-center justify-between gap-6 px-6 py-4 ${ | ||
altBg ? "bg-slate-100" : "bg-white" | ||
} hover:bg-sky-100`} | ||
> | ||
<div> | ||
<h3 className="text-lg text-sky-600 font-bold my-2">{title}</h3> | ||
<p className="my-2 text-slate-600">{description}</p> | ||
</div> | ||
<ChevronRight className="text-sky-600 w-8 h-8" /> | ||
</div> | ||
</Link> | ||
</label> | ||
); | ||
}; |
5 changes: 5 additions & 0 deletions
5
src/services/ui/src/components/Container/SimplePageContainer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { PropsWithChildren } from "react"; | ||
|
||
export const SimplePageContainer = ({ children }: PropsWithChildren) => ( | ||
<div className="max-w-screen-xl mx-auto px-4 lg:px-8">{children}</div> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { SimplePageContainer } from "./SimplePageContainer"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,107 @@ | ||
import React, {PropsWithChildren} from "react"; | ||
import {MACFieldsetOption, OptionCard, OptionFieldset} from "@/components/Cards/OptionCard"; | ||
import {AUTHORITY_OPTIONS, SPA_OPTIONS} from "@/pages/create/options"; | ||
import { | ||
MACFieldsetOption, | ||
OptionCard, | ||
OptionFieldset, | ||
} from "@/components/Cards/OptionCard"; | ||
import { | ||
AUTHORITY_OPTIONS, | ||
B4_WAIVER_OPTIONS, | ||
B_WAIVER_OPTIONS, | ||
BCAP_WAIVER_OPTIONS, | ||
CHIP_SPA_OPTIONS, | ||
MEDICAID_SPA_OPTIONS, | ||
SPA_OPTIONS, | ||
WAIVER_OPTIONS, | ||
} from "@/pages/create/options"; | ||
import { SimplePageContainer } from "@/components"; | ||
|
||
/** I didn't see a page container already present in the repo, so to better standardize | ||
* we can extract this and use it on more pages where currently each page has its own. (KH) */ | ||
export const SimplePageContainer = ({ children }: PropsWithChildren) => ( | ||
<div className="max-w-screen-xl mx-auto px-4 lg:px-8"> | ||
{children} | ||
</div> | ||
); | ||
/** Can be removed once page title bar with back nav is integrated */ | ||
export const SimplePageTitle = ({ title }: { title: string }) => ( | ||
<div className="flex items-center justify-between my-4"> | ||
<h1 className="text-xl">{title}</h1> | ||
</div> | ||
<div className="flex items-center justify-between my-4"> | ||
<h1 className="text-xl">{title}</h1> | ||
</div> | ||
); | ||
|
||
export type OptionData = Omit<MACFieldsetOption, "altBg"> | ||
export type OptionData = Omit<MACFieldsetOption, "altBg">; | ||
type OptionsPageProps = { | ||
options: OptionData[] | ||
title: string | ||
fieldsetLegend: string | ||
} | ||
options: OptionData[]; | ||
title: string; | ||
fieldsetLegend: string; | ||
}; | ||
/** A page for rendering an array of {@link OptionData} */ | ||
const OptionsPage = ({ options, title, fieldsetLegend }: OptionsPageProps) => { | ||
return ( | ||
<SimplePageContainer> | ||
<SimplePageTitle title={title}/> | ||
<OptionFieldset legend={fieldsetLegend}> | ||
{options.map((opt, idx) => | ||
<OptionCard | ||
key={idx} | ||
{...opt} | ||
altBg={idx % 2 === 1} // Even number option cards show altBg | ||
/> | ||
)} | ||
</OptionFieldset> | ||
</SimplePageContainer> | ||
); | ||
return ( | ||
<SimplePageContainer> | ||
<SimplePageTitle title={title} /> | ||
<OptionFieldset legend={fieldsetLegend}> | ||
{options.map((opt, idx) => ( | ||
<OptionCard | ||
key={idx} | ||
{...opt} | ||
altBg={idx % 2 === 1} // Even number option cards show altBg | ||
/> | ||
))} | ||
</OptionFieldset> | ||
</SimplePageContainer> | ||
); | ||
}; | ||
/** Initial set of options for a New Submission */ | ||
export const NewSubmissionInitialOptions = () => ( | ||
<OptionsPage | ||
title="Submission Type" | ||
fieldsetLegend="Select a Submission Type." | ||
options={AUTHORITY_OPTIONS} | ||
/> | ||
<OptionsPage | ||
title="Submission Type" | ||
fieldsetLegend="Select a Submission Type." | ||
options={AUTHORITY_OPTIONS} | ||
/> | ||
); | ||
/** Choice between the main SPA types when creating a New Submission */ | ||
export const SPASubmissionOptions = () => ( | ||
<OptionsPage | ||
title="SPA Type" | ||
fieldsetLegend="Select a SPA type to start your submission" | ||
options={SPA_OPTIONS} /> | ||
<OptionsPage | ||
title="SPA Type" | ||
fieldsetLegend="Select a SPA type to start your submission" | ||
options={SPA_OPTIONS} | ||
/> | ||
); | ||
/** Sub-choices for Medicaid SPAs */ | ||
export const MedicaidSPASubmissionOptions = () => ( | ||
<OptionsPage | ||
title="Medicaid SPA Type" | ||
fieldsetLegend="Select a Medicaid SPA type to create your submission" | ||
options={MEDICAID_SPA_OPTIONS} | ||
/> | ||
); | ||
/** Sub-choices for CHIP SPAs */ | ||
export const ChipSPASubmissionOptions = () => ( | ||
<OptionsPage | ||
title="CHIP SPA Type" | ||
fieldsetLegend="Select a CHIP SPA type to create your submission" | ||
options={CHIP_SPA_OPTIONS} | ||
/> | ||
); | ||
export const WaiverSubmissionOptions = () => ( | ||
<OptionsPage | ||
title="Waiver Action Type" | ||
fieldsetLegend="Select a Waiver type to start your submission." | ||
options={WAIVER_OPTIONS} | ||
/> | ||
); | ||
export const BWaiverSubmissionOptions = () => ( | ||
<OptionsPage | ||
title="1915(b) Waiver Action Type" | ||
fieldsetLegend="Select a 1915(b) Waiver type for your submission." | ||
options={B_WAIVER_OPTIONS} | ||
/> | ||
); | ||
export const B4WaiverSubmissionOptions = () => ( | ||
<OptionsPage | ||
title="1915(b)(4) FFS Selective Contracting Waiver Authority" | ||
fieldsetLegend="Select a Waiver type to start your submission." | ||
options={B4_WAIVER_OPTIONS} | ||
/> | ||
); | ||
export const BCapWaiverSubmissionOptions = () => ( | ||
<OptionsPage | ||
title="1915(b) Comprehensive (Capitated) Waiver Authority" | ||
fieldsetLegend="Select a Waiver type to start your submission." | ||
options={BCAP_WAIVER_OPTIONS} | ||
/> | ||
); |
Oops, something went wrong.