Skip to content

Commit

Permalink
fix: fold in parsing with sanitizing, add keys, remove arrs
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmcgrath13 committed Nov 18, 2024
1 parent fb53555 commit ac97dbc
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 55 deletions.
7 changes: 3 additions & 4 deletions containers/ecr-viewer/src/app/services/formatService.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from "react";
import { ToolTipElement } from "@/app/view-data/components/ToolTipElement";
import { ContactPoint } from "fhir/r4";
import { sanitizeAndMap } from "../view-data/utils/utils";
import parse from "html-react-parser";
import { parseSanitizeAndMap } from "../view-data/utils/utils";

interface Metadata {
[key: string]: string;
Expand All @@ -27,7 +26,7 @@ export interface TableJson {
tables?: TableRow[][];
}

export type TableValue = string | React.JSX.Element | React.JSX.Element[];
export type TableValue = string | React.JSX.Element;

/**
* Formats a person's name using given name(s), family name, optional prefix(es), and optional suffix(es).
Expand Down Expand Up @@ -501,7 +500,7 @@ function getElementContent(el: Element | Node): TableValue {
const rawValue = (el as Element)?.innerHTML ?? el.textContent;
const value = rawValue?.trim() ?? "";
if (value === "") return value;
const res = parse(sanitizeAndMap(value));
let res = parseSanitizeAndMap(value);
return res;
}

Expand Down
19 changes: 12 additions & 7 deletions containers/ecr-viewer/src/app/services/labsService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { Bundle, Device, Observation, Organization, Reference } from "fhir/r4";
import {
PathMappings,
noData,
sanitizeAndMap,
parseSanitizeAndMap,
} from "@/app/view-data/utils/utils";
import { evaluate } from "@/app/view-data/utils/evaluate";
import parse from "html-react-parser";
import { AccordionLabResults } from "@/app/view-data/components/AccordionLabResults";
import {
formatDateTime,
Expand Down Expand Up @@ -264,9 +263,15 @@ const returnAnalysisTime = (
}

const analysisTimeArrayFormatted = (fieldVals as TableValue[]).map(
(dateTime) => {
const dateTimeNode = parse(`<p>${dateTime}</p>`);
console.log({ dateTime, typeofdate: typeof dateTimeNode, dateTimeNode });
(rawDateTime) => {
let dateTime;
if (typeof rawDateTime === "string") {
dateTime = rawDateTime;
} else if (typeof rawDateTime.props.children === "string") {
dateTime = rawDateTime.props.children;
} else {
return "";
}
return formatDateTime(dateTime);
},
);
Expand Down Expand Up @@ -347,15 +352,15 @@ export const evaluateDiagnosticReportData = (
infoPath: "observationDeviceReference",
applyToValue: (ref) => {
const device = evaluateReference(fhirBundle, mappings, ref) as Device;
return parse(sanitizeAndMap(device.deviceName?.[0]?.name ?? ""));
return parseSanitizeAndMap(device.deviceName?.[0]?.name ?? "");
},
className: "minw-10 width-20",
},
{
columnName: "Lab Comment",
infoPath: "observationNote",
hiddenBaseText: "comment",
applyToValue: (v) => parse(sanitizeAndMap(v)),
applyToValue: (v) => parseSanitizeAndMap(v),
className: "minw-10 width-20",
},
];
Expand Down
29 changes: 16 additions & 13 deletions containers/ecr-viewer/src/app/tests/services/labsService.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const labReportNormalJsonObject = {
Value: { value: "Not Detected", metadata: {} },
"Ref Range": { value: "Not Detected", metadata: {} },
"Test Method": {
value: "LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM",
value: <p>LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM</p>,
metadata: {},
},
"Analysis Time": {
Expand Down Expand Up @@ -74,7 +74,7 @@ const labReportNormalJsonObject = {
Value: { value: "Not Detected", metadata: {} },
"Ref Range": { value: "Not Detected", metadata: {} },
"Test Method": {
value: "LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM",
value: <p>LAB DEVICE: BIOFIRE® FILMARRAY® 2.0 SYSTEM</p>,
metadata: {},
},
"Analysis Time": {
Expand Down Expand Up @@ -131,19 +131,22 @@ const labReportNormalJsonObject = {
[
{
"Performing Organization": {
value:
"PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)",
value: (
<p>
PROVIDENCE ST. JOSEPH MEDICAL CENTER LABORATORY (CLIA 05D0672675)
</p>
),
metadata: {
"data-id":
"Result.1.2.840.114350.1.13.297.3.7.2.798268.1670845.PerformingLab",
},
},
Address: { value: "501 S. Buena Vista Street", metadata: {} },
Address: { value: <p>501 S. Buena Vista Street</p>, metadata: {} },
"City/State/ZIP Code": {
value: "Burbank, CA 91505",
value: <p>Burbank, CA 91505</p>,
metadata: {},
},
"Phone Number": { value: "818-847-6000", metadata: {} },
"Phone Number": { value: <p>818-847-6000</p>, metadata: {} },
},
],
],
Expand Down Expand Up @@ -240,34 +243,34 @@ describe("Labs Utils", () => {

it("extracts string of all results of a search for specified lab report", () => {
const searchKey = "Collection Time";
const expectedResult = "09/28/2022 1:51 PM PDT";
const expectedResult = ["09/28/2022 1:51 PM PDT"];

const result = searchResultRecord(labHTMLJson, searchKey);

expect(result).toBe(expectedResult);
expect(result).toStrictEqual(expectedResult);
});

it("returns an empty string of results if none are found for search key", () => {
const invalidSearchKey = "foobar";
const expectedResult = "";
const expectedResult = [];

const result = searchResultRecord(labHTMLJson, invalidSearchKey);

expect(result).toBe(expectedResult);
expect(result).toStrictEqual(expectedResult);
});
});

describe("returnFieldValueFromLabHtmlString", () => {
it("extracts correct field value from within a lab report", () => {
const fieldName = "Analysis Time";
const expectedResult = "09/28/2022 1:59 PM PDT";
const expectedResult = ["09/28/2022 1:59 PM PDT"];

const result = returnFieldValueFromLabHtmlString(
labReportNormalJsonObject,
fieldName,
);

expect(result).toBe(expectedResult);
expect(result).toStrictEqual(expectedResult);
});

it("returns NoData if none are found for field name", () => {
Expand Down
48 changes: 34 additions & 14 deletions containers/ecr-viewer/src/app/tests/utils.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { isDataAvailable, sanitizeAndMap } from "@/app/view-data/utils/utils";
import {
isDataAvailable,
parseSanitizeAndMap,
} from "@/app/view-data/utils/utils";
import { loadYamlConfig } from "@/app/api/utils";
import { Bundle } from "fhir/r4";
import BundleWithTravelHistory from "./assets/BundleTravelHistory.json";
Expand All @@ -10,7 +13,7 @@ import BundleWithPendingResultsOnly from "./assets/BundlePendingResultsOnly.json
import BundleWithScheduledOrdersOnly from "./assets/BundleScheduledOrdersOnly.json";
import BundleNoActiveProblems from "./assets/BundleNoActiveProblems.json";
import BundleCareTeam from "./assets/BundleCareTeam.json";
import React from "react";
import React, { Fragment } from "react";
import { render, screen } from "@testing-library/react";
import { CarePlanActivity } from "fhir/r4b";
import { evaluate } from "@/app/view-data/utils/evaluate";
Expand Down Expand Up @@ -551,27 +554,44 @@ describe("Utils", () => {
});
});

describe("sanitizeAndMap", () => {
describe("parseSanitizeAndMap", () => {
it("should leave alone nice safe HTML", () => {
const html = "<p>hi there</p>";
const actual = sanitizeAndMap(html);
expect(actual).toBe(html);
const str = "<p>hi there</p>";
const jsx = <p>hi there</p>;
const actual = parseSanitizeAndMap(str);
expect(actual).toStrictEqual(jsx);
});

it("should map xml-y HTML", () => {
const html = `<paragraph>hi there</paragraph><content ID="abc">I'm content</content><list><item>one</item><item>two</item></list>`;
const actual = sanitizeAndMap(html);
expect(actual).toBe(
`<p>hi there</p><span>I'm content</span><ul><li>one</li><li>two</li></ul>`,
const str = `<paragraph>hi there</paragraph><content ID="abc">I'm content</content><list><item>one</item><item>two</item></list>`;
const jsx = (
<>
<p>hi there</p>
<span>I'm content</span>
<ul>
<li>one</li>
<li>two</li>
</ul>
</>
);
const actual = parseSanitizeAndMap(str);
expect(actual).toStrictEqual(jsx);
});

it("should remove comments", () => {
const html = `<!-- Data ID: 123 --><paragraph>hi there</paragraph><content ID="abc">I'm content</content><list><item>one</item><item>two</item></list>`;
const actual = sanitizeAndMap(html);
expect(actual).toBe(
`<p>hi there</p><span>I'm content</span><ul><li>one</li><li>two</li></ul>`,
const str = `<!-- Data ID: 123 --><paragraph>hi there</paragraph>I'm content<list><item>one</item><item>two</item></list>`;
const jsx = (
<>
<p key="el-0">hi there</p>
<Fragment key="el-1">I'm content</Fragment>
<ul key="el-2">
<li>one</li>
<li>two</li>
</ul>
</>
);
const actual = parseSanitizeAndMap(str);
expect(actual).toEqual(jsx);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const DataDisplay: React.FC<{
item.dividerLine == null || item.dividerLine == undefined
? true
: item.dividerLine;
console.log(item.value);
return (
<div>
<div className="grid-row">
Expand Down
11 changes: 4 additions & 7 deletions containers/ecr-viewer/src/app/view-data/components/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
PathMappings,
evaluateData,
noData,
sanitizeAndMap,
parseSanitizeAndMap,
} from "@/app/view-data/utils/utils";
import {
Bundle,
Expand All @@ -40,7 +40,6 @@ import {
Procedure,
} from "fhir/r4";
import { evaluate } from "@/app/view-data/utils/evaluate";
import parse from "html-react-parser";
import { DisplayDataProps } from "@/app/view-data/components/DataDisplay";
import {
AdministeredMedication,
Expand Down Expand Up @@ -212,7 +211,7 @@ export const returnProblemsTable = (
{
columnName: "Comments",
infoPath: "activeProblemsComments",
applyToValue: (v) => parse(sanitizeAndMap(v)),
applyToValue: (v) => parseSanitizeAndMap(v),
hiddenBaseText: "comment",
},
];
Expand Down Expand Up @@ -499,10 +498,8 @@ export const evaluateClinicalData = (
const clinicalNotes: DisplayDataProps[] = [
{
title: "Miscellaneous Notes",
value: parse(
sanitizeAndMap(
evaluateValue(fhirBundle, mappings["historyOfPresentIllness"]),
) || "",
value: parseSanitizeAndMap(
evaluateValue(fhirBundle, mappings["historyOfPresentIllness"]) ?? "",
),
},
];
Expand Down
50 changes: 40 additions & 10 deletions containers/ecr-viewer/src/app/view-data/utils/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";
import React, { Fragment } from "react";
import { removeHtmlElements } from "@/app/services/formatService";
import { DisplayDataProps } from "@/app/view-data/components/DataDisplay";
import sanitizeHtml from "sanitize-html";
import parse from "html-react-parser";

export interface PathMappings {
[key: string]: string;
Expand Down Expand Up @@ -64,13 +65,42 @@ export const isDataAvailable = (item: DisplayDataProps): Boolean => {
* @param val - The string of content to sanitize and map.
* @returns - Returns sanitized and mapped content.
*/
export const sanitizeAndMap = (val: string): string => {
return sanitizeHtml(val, {
transformTags: {
paragraph: "p",
list: "ul",
item: "li",
content: "span",
},
});
export const parseSanitizeAndMap = (
val: string,
): string | React.JSX.Element => {
const parsed = parse(
sanitizeHtml(val, {
transformTags: {
paragraph: "p",
list: "ul",
item: "li",
content: "span",
},
}),
);

if (Array.isArray(parsed)) {
if (parsed.length === 0) {
return "";
} else if (parsed.length === 1) {
return parsed[0];
}

const res = (
<>
{parsed.map((item, ind) => {
// Make sure items always have a key
const key = `el-${ind}`;
return typeof item === "string" ? (
<Fragment key={key}>{item}</Fragment>
) : (
{ ...item, key }
);
})}
</>
);
return res;
}

return parsed;
};

0 comments on commit ac97dbc

Please sign in to comment.