Skip to content

Commit

Permalink
Add custom 404 page (#2876)
Browse files Browse the repository at this point in the history
* add not-found page

* fix border on header

* move common tests out of view-data

* rename not found page

* update fetch data error handling

* make back button customizable

* add back button to 404 page

* [pre-commit.ci] auto fixes from pre-commit hooks

* change back button text

* Increase padding to 24 px

* Boban/why (#2881)

Add not found on non-integrated viewer

* fix home page tests

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
BobanL and pre-commit-ci[bot] authored Nov 8, 2024
1 parent 6f80942 commit 6239898
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 150 deletions.
47 changes: 47 additions & 0 deletions containers/ecr-viewer/src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"use client";
import { Icon } from "@trussworks/react-uswds";
import Header from "./Header";
import { BackButton } from "./view-data/components/BackButton";

/**
* 404 page
* @returns 404 Page
*/
const NotFound = () => (
<div className="height-viewport width-viewport display-flex flex-column">
<Header />
<main className="display-flex flex-justify-center height-full">
<div className="display-inline-block margin-y-auto">
<h2 className="font-family-serif font-serif-xl margin-bottom-0">
<Icon.Error
size={5}
className="margin-right-105 text-middle"
aria-hidden
/>
Page not found
</h2>
<div className="text-semibold font-sans-md margin-top-1">
The requested page could not be found
</div>
<div className="bg-info-lighter border border-info-light radius-md font-sans-md line-height-sans-4 padding-3 margin-top-2">
Please try the following:
<ul className="margin-0 padding-left-3">
<li>
<b>Check the URL:</b> Make sure there are no typos in the address.
</li>
<li>
<b>Return to NBS:</b> Return to NBS and try to reopen the eCR.
</li>
<li>
<b>Contact support:</b> If the problem persists, please reach out
to your eCR coordinator.
</li>
</ul>
</div>
<BackButton className="margin-top-3 font-sans-md text-primary" />
</div>
</main>
</div>
);

export default NotFound;
5 changes: 2 additions & 3 deletions containers/ecr-viewer/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getTotalEcrCount } from "@/app/api/services/listEcrDataService";
import EcrPaginationWrapper from "@/app/components/EcrPaginationWrapper";
import EcrTable from "@/app/components/EcrTable";
import LibrarySearch from "./components/LibrarySearch";
import NotFound from "./not-found";

/**
* Functional component for rendering the home page that lists all eCRs.
Expand Down Expand Up @@ -53,9 +54,7 @@ const HomePage = async ({
</EcrPaginationWrapper>
</>
) : (
<div>
<h1>Sorry, this page is not available.</h1>
</div>
<NotFound />
)}
</main>
</div>
Expand Down
16 changes: 4 additions & 12 deletions containers/ecr-viewer/src/app/tests/HomePage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,23 @@ describe("Home Page", () => {
it("env false value, should not show the homepage", async () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "false";
render(await HomePage({ searchParams: {} }));
expect(
screen.getByText("Sorry, this page is not available."),
).toBeInTheDocument();
expect(screen.getByText("Page not found")).toBeInTheDocument();
});
it("env invalid value, should not show the homepage", async () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "foo";
render(await HomePage({ searchParams: {} }));
expect(
screen.getByText("Sorry, this page is not available."),
).toBeInTheDocument();
expect(screen.getByText("Page not found")).toBeInTheDocument();
});
it("env no value, should not show the homepage", async () => {
render(await HomePage({ searchParams: {} }));
expect(
screen.getByText("Sorry, this page is not available."),
).toBeInTheDocument();
expect(screen.getByText("Page not found")).toBeInTheDocument();
});
it("env true value, should show the homepage", async () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "true";
const mockData = [{ id: 1, name: "Test Ecr" }];
(listEcrData as jest.Mock).mockResolvedValue(mockData);
render(await HomePage({ searchParams: {} }));
expect(getTotalEcrCount).toHaveBeenCalledOnce();
expect(
screen.queryByText("Sorry, this page is not available"),
).not.toBeInTheDocument();
expect(screen.queryByText("Page not found")).not.toBeInTheDocument();
});
});
38 changes: 38 additions & 0 deletions containers/ecr-viewer/src/app/tests/components/BackButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { BackButton } from "@/app/view-data/components/BackButton";
import { render, screen } from "@testing-library/react";

describe("Back button", () => {
it("should not appear when non integrated = false", () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "false";

render(<BackButton />);

expect(screen.queryByText("Back to eCR Library")).not.toBeInTheDocument();
});

it("should appear when non integrated = true", () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "true";

render(<BackButton />);

expect(screen.getByText("Back to eCR Library")).toBeInTheDocument();
});

it("should apply class name to the a tag", () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "true";

render(<BackButton className="some-class" />);

expect(screen.getByText("Back to eCR Library").className).toContain(
"some-class",
);
});

it("should icon apply class name to the icon tag", () => {
process.env.NEXT_PUBLIC_NON_INTEGRATED_VIEWER = "true";

render(<BackButton iconClassName="some-icon-class" />);

expect(screen.getByRole("img").classList).toContain("some-icon-class");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,26 @@ exports[`Snapshot test for EcrLoadingSkeleton should match snapshot 1`] = `
<div
class="nav-wrapper"
>
<div
class="display-flex back-button-wrapper"
<a
class="display-inline-block margin-bottom-3"
href="/"
>
<a
class="back-button display-flex"
href="/"
<svg
aria-label="Back Arrow"
class="usa-icon usa-icon--size-3 text-middle margin-right-1 text-base"
focusable="false"
height="1em"
role="img"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<svg
aria-label="Back Arrow"
class="usa-icon usa-icon--size-3"
focusable="false"
height="1em"
role="img"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
/>
</svg>
Back to eCR Library
</a>
</div>
<path
d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
/>
</svg>
Back to eCR Library
</a>
<nav
class="sticky-nav top-550"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,26 @@ exports[`SectionConfig should match the snapshot 1`] = `
<nav
class="nav-wrapper top-550"
>
<div
class="display-flex back-button-wrapper"
<a
class="display-inline-block margin-bottom-3"
href="/"
>
<a
class="back-button display-flex"
href="/"
<svg
aria-label="Back Arrow"
class="usa-icon usa-icon--size-3 text-middle margin-right-1 text-base"
focusable="false"
height="1em"
role="img"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<svg
aria-label="Back Arrow"
class="usa-icon usa-icon--size-3"
focusable="false"
height="1em"
role="img"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
/>
</svg>
Back to eCR Library
</a>
</div>
<path
d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
/>
</svg>
Back to eCR Library
</a>
<ul
class="usa-sidenav"
data-testid="sidenav"
Expand Down
60 changes: 60 additions & 0 deletions containers/ecr-viewer/src/app/tests/components/common.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { getMedicationDisplayName } from "@/app/view-data/components/common";

describe("getMedicationDisplayName", () => {
it("handles undefined case", () => {
expect(getMedicationDisplayName(undefined)).toBe(undefined);
});

it("handles empty case", () => {
expect(getMedicationDisplayName({ coding: [] })).toBe(undefined);
});

it("handles single named case", () => {
expect(
getMedicationDisplayName({
coding: [{ code: "123", display: "medication", system: "ABC" }],
}),
).toBe("medication");
});

it("handles single un-named case", () => {
expect(
getMedicationDisplayName({
coding: [{ code: "123", system: "ABC" }],
}),
).toBe("Unknown medication name - ABC code 123");
});

it("handles multiple named case", () => {
expect(
getMedicationDisplayName({
coding: [
{ code: "123", display: "first", system: "ABC" },
{ code: "456", display: "second", system: "DEF" },
],
}),
).toBe("first");
});

it("handles multiple mixed named case", () => {
expect(
getMedicationDisplayName({
coding: [
{ code: "123", system: "ABC" },
{ code: "456", display: "second", system: "DEF" },
],
}),
).toBe("second");
});

it("handles multiple un-named case", () => {
expect(
getMedicationDisplayName({
coding: [
{ code: "123", system: "ABC" },
{ code: "456", system: "DEF" },
],
}),
).toBe("Unknown medication name - ABC code 123");
});
});
Loading

0 comments on commit 6239898

Please sign in to comment.