Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boban/refactor qp #3125

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 8 additions & 26 deletions containers/ecr-viewer/e2e/ecr-library.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ test.describe("eCR Library Filtering", () => {
const totalNumOfConditions = "4";
test("Set reportable condition filter to anthrax", async ({ page }) => {
await page.goto("/ecr-viewer");
await page.waitForURL("/ecr-viewer?columnId=date_created&direction=DESC");
await page.waitForURL("/ecr-viewer?itemsPerPage=25");
await expect(page.getByTestId("filter-tag")).toContainText(
totalNumOfConditions,
);
Expand All @@ -38,7 +38,7 @@ test.describe("eCR Library Filtering", () => {

test("Search should filter results ", async ({ page }) => {
await page.goto("/ecr-viewer");
await page.waitForURL("/ecr-viewer?columnId=date_created&direction=DESC");
await page.waitForURL("/ecr-viewer?itemsPerPage=25");
await expect(page.getByTestId("filter-tag")).toContainText(
totalNumOfConditions,
);
Expand All @@ -59,7 +59,7 @@ test.describe("eCR Library Filtering", () => {
page,
}) => {
await page.goto("/ecr-viewer");
await page.waitForURL("/ecr-viewer?columnId=date_created&direction=DESC");
await page.waitForURL("/ecr-viewer?itemsPerPage=25");
await expect(page.getByTestId("filter-tag")).toContainText(
totalNumOfConditions,
);
Expand All @@ -81,40 +81,22 @@ test.describe("eCR Library Filtering", () => {
);
});

// BUG: When selecting eCRs per page so quickly after load the table doesn't get updated
test.skip("Set 100 results per page", async ({ page }) => {
await page.goto("/ecr-viewer?columnId=date_created&direction=DESC");
await page.waitForURL("/ecr-viewer?columnId=date_created&direction=DESC");
await expect(page.getByTestId("filter-tag")).toContainText(
totalNumOfConditions,
);

await page.getByText("Showing 1-25").waitFor();

await page.getByTestId("Select").selectOption("100");

await expect(page.getByLabel("Page 3")).not.toBeVisible();
expect((await page.locator("tbody > tr").allTextContents()).length).toEqual(
100,
);
});

// BUG: Items per page does not get set when in query parameters
test.skip("When visiting a direct url all query parameters should be applied", async ({
test("When visiting a direct url all query parameters should be applied", async ({
page,
}) => {
await page.goto(
"/ecr-viewer?columnId=date_created&direction=DESC&itemsPerPage=100&page=1&condition=Anthrax+%28disorder%29&search=Cutla",
"/ecr-viewer?itemsPerPage=100&page=1&condition=Anthrax+%28disorder%29&search=Cutla",
);
await expect(page.getByTestId("textInput")).toHaveValue("Cutla");
await expect(page.getByTestId("Select")).toHaveValue("100");
await page.getByText("Showing 1-6 of 6 eCRs").click();
await page.getByText("Showing 1-1 of 1 eCRs").click();
await page.getByLabel("Filter by reportable condition").click();
await expect(
page.getByRole("group").getByText("Anthrax (disorder)"),
).toBeChecked();
await expect(page.getByTestId("textInput")).toHaveValue("Cutla");
expect((await page.locator("tbody > tr").allTextContents()).length).toEqual(
6,
1,
);
});
});
37 changes: 37 additions & 0 deletions containers/ecr-viewer/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions containers/ecr-viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"next-auth": "^4.24.7",
"next-router-mock": "^0.9.13",
"next-runtime-env": "^3.2.2",
"nuqs": "^2.3.0",
"pg-promise": "^11.6.0",
"react": "^18",
"react-dom": "^18",
Expand Down
3 changes: 3 additions & 0 deletions containers/ecr-viewer/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export default defineConfig({
trace: "retain-on-failure",
video: "retain-on-failure",
},
expect: {
timeout: 15_000,
},
/* Configure projects for major browsers */
projects: [
{
Expand Down
122 changes: 122 additions & 0 deletions containers/ecr-viewer/src/app/components/BaseEcrTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { SearchParams } from "nuqs";
import { loadSearchParams } from "./searchParams";
import { Table } from "@trussworks/react-uswds";
import { SortButton } from "./SortButton";

export const sortDirection = ["asc", "desc"] as const;
export const columnIds = [
"patient",
"date_created",
"report_date",
"reportable_condition",
"rule_summary",
] as const;
export type ColumnId = (typeof columnIds)[number];
type SortDirection = (typeof sortDirection)[number];
type Column = {
id: ColumnId;
title: string;
className: string;
dataSortable: boolean;
};
type AriaSortType = "none" | "ascending" | "descending" | "other";

const headers: Column[] = [
{
id: "patient",
title: "Patient",
className: "library-patient-column",
dataSortable: true,
},
{
id: "date_created",
title: "Received Date",
className: "library-received-date-column",
dataSortable: true,
},
{
id: "report_date",
title: "Encounter Date",
className: "library-encounter-date-column",
dataSortable: true,
},
{
id: "reportable_condition",
title: "Reportable Condition",
className: "library-condition-column",
dataSortable: false,
},
{
id: "rule_summary",
title: "RCKMS Rule Summary",
className: "library-rule-column",
dataSortable: false,
},
];

interface BaseEcrTableProps {
searchParams: SearchParams;
children?: React.ReactNode;
}

/**
* Functional component for rendering the eCR library table.
* @param props - The properties passed to the component.
* @param props.searchParams - List of search params
* @param props.children - The rows to display in the table
* @returns - The JSX element representing the eCR table.
*/
export const BaseEcrTable = async ({
searchParams,
children,
}: BaseEcrTableProps) => {
const { columnId, direction } = await loadSearchParams(searchParams);
return (
<div className="ecr-library-wrapper width-full overflow-auto">
<Table
bordered={false}
fullWidth={true}
striped={true}
fixed={true}
className={"table-ecr-library margin-0"}
data-testid="table"
>
<thead className={"position-sticky top-0"}>
<tr>
{headers.map((column) => (
<th
id={`${column.id}-header`}
key={`${column.title}`}
scope="col"
role="columnheader"
className={column.className}
data-sortable={column.dataSortable}
aria-sort={
columnId === column.id
? getAriaSortValue(direction)
: undefined
}
>
<div className={"display-flex width-full"}>
{column.title}
{column.dataSortable && <SortButton columnName={column.id} />}
</div>
</th>
))}
</tr>
</thead>
<tbody>{children}</tbody>
</Table>
</div>
);
};

const getAriaSortValue = (
sortDirection: SortDirection | undefined,
): AriaSortType | undefined => {
if (sortDirection === "asc") {
return "ascending";
} else if (sortDirection === "desc") {
return "descending";
}
};
56 changes: 56 additions & 0 deletions containers/ecr-viewer/src/app/components/DataRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use client";
import React from "react";
import { EcrDisplay } from "@/app/services/listEcrDataService";
import { toSentenceCase } from "@/app/services/formatService";
import { useSearchParams } from "next/navigation";
import { noData } from "../view-data/utils/utils";
import Link from "next/link";
import { saveToSessionStorage } from "./utils";

/**
* Formats a single row of the eCR table.
* @param props - The properties passed to the component.
* @param props.item - The eCR data to be formatted.
* @returns A JSX table row element representing the eCR data.
*/
export const DataRow = ({ item }: { item: EcrDisplay }) => {
const patient_first_name = toSentenceCase(item.patient_first_name);
const patient_last_name = toSentenceCase(item.patient_last_name);

const searchParams = useSearchParams();

const conditionsList = (
<ul className="ecr-table-list">
{item.reportable_conditions.map((rc, index) => (
<li key={index}>{rc}</li>
))}
</ul>
);

const summariesList = (
<ul className="ecr-table-list">
{item.rule_summaries.map((rs, index) => (
<li key={index}>{rs}</li>
))}
</ul>
);
const saveUrl = () => {
saveToSessionStorage("urlParams", searchParams.toString());
};

return (
<tr>
<td>
<Link onClick={saveUrl} href={`/view-data?id=${item.ecrId}`}>
{patient_first_name} {patient_last_name}
</Link>
<br />
<div>{"DOB: " + item.patient_date_of_birth || ""}</div>
</td>
<td>{item.date_created}</td>
<td>{item.patient_report_date || noData}</td>
<td>{conditionsList}</td>
<td>{summariesList}</td>
</tr>
);
};
Loading
Loading