Skip to content
This repository has been archived by the owner on Jan 4, 2023. It is now read-only.

Display resource narrative #68

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@types/react-pdf": "^5.0.9",
"@types/react-redux": "^7.1.7",
"@types/react-syntax-highlighter": "^13.5.2",
"dompurify": "^2.3.5",
"eslint": "^7.11.0",
"faker": "^5.5.3",
"fishery": "^2.1.0",
Expand Down Expand Up @@ -68,6 +69,7 @@
]
},
"devDependencies": {
"@types/dompurify": "^2.3.3",
"@typescript-eslint/parser": "^5.3.1",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-typescript": "^2.5.0",
Expand Down
4 changes: 2 additions & 2 deletions src/app/routes/Patient.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo } from "react";

import type { IResourceList } from "@ahryman40k/ts-fhir-types/lib/R4";
import BackIcon from "@mui/icons-material/ArrowBack";
import { Button, CircularProgress, Container } from "@mui/material";
import { makeStyles } from "@mui/styles";
Expand All @@ -16,6 +15,7 @@ import ResourceFilterSelector from "features/resourceFilters/ResourceFilterSelec
import { selectResourceFilters } from "features/resourceFilters/resourceFilterSlice";
import ResourceCard from "features/resources/ResourceCard";
import { sortResourcesByDate } from "features/resources/utils";
import type { DomainResourceList } from "models/types";
import { useApiPatientEverythingListQuery } from "services/api/api";

const useStyles = makeStyles((theme) => ({
Expand Down Expand Up @@ -83,7 +83,7 @@ const Patient = (): JSX.Element => {
() =>
patientResources.reduce(
(
acc: Partial<Record<IResourceList["resourceType"], number>>,
acc: Partial<Record<DomainResourceList["resourceType"], number>>,
resource
) => ({
...acc,
Expand Down
3 changes: 2 additions & 1 deletion src/app/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import React from "react";
import { makeStyles } from "@mui/styles";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import { PUBLIC_URL } from "../../constants";
import { PUBLIC_URL } from "models/constants";

import Home from "./Home";
import PageNotFound from "./PageNotFound";
import Patient from "./Patient";
Expand Down
4 changes: 2 additions & 2 deletions src/common/components/DateInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React, { useMemo } from "react";

import type { IResourceList } from "@ahryman40k/ts-fhir-types/lib/R4";
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
import { Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { DateTime } from "luxon";

import { getResourceDateOrPeriod } from "features/resources/utils";
import type { DomainResourceList } from "models/types";

type DateInfoProps = {
resource: IResourceList;
resource: DomainResourceList;
};

const useStyles = makeStyles((theme) => ({
Expand Down
26 changes: 26 additions & 0 deletions src/common/components/InnerHTMLDiv.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";

import DOMPurify from "dompurify";

type InnerHTMLDivProps = Omit<
React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>,
"dangerouslySetInnerHTML"
> & {
innerHTML?: string;
};

const InnterHTMLDiv = ({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const InnterHTMLDiv = ({
const InnerHTMLDiv = ({

innerHTML,
...props
}: InnerHTMLDivProps): JSX.Element => {
const sanitizedHTML = innerHTML && DOMPurify.sanitize(innerHTML);
return (
<>
{sanitizedHTML && (
<div {...props} dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />
)}
</>
);
};

export default InnterHTMLDiv;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export default InnterHTMLDiv;
export default InnerHTMLDiv;

22 changes: 22 additions & 0 deletions src/common/components/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";

import {
Tooltip as MuiTooltip,
TooltipProps as MuiTooltipProps,
} from "@mui/material";

type TooltipProps = Omit<MuiTooltipProps, "title"> & {
title?: React.ReactNode;
};

const Tooltip = ({ title, children, ...props }: TooltipProps): JSX.Element => {
return title ? (
<MuiTooltip title={title} {...props}>
{children}
</MuiTooltip>
) : (
children
);
};

export default Tooltip;
5 changes: 3 additions & 2 deletions src/features/conditions/ConditionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { useTranslation } from "react-i18next";
import DateInfo from "common/components/DateInfo";
import Tag from "common/components/Tag";
import ResourceCardActions from "features/resources/ResourceCardActions";
import ResourceCardContent from "features/resources/ResourceCardContent";
import { getResourceTagValues } from "features/resources/utils";

import { TERMINOLOGY_SYSTEM_URL } from "../../constants";
import { TERMINOLOGY_SYSTEM_URL } from "models/constants";

const useStyles = makeStyles((theme) => ({
flexContainer: {
Expand Down Expand Up @@ -65,6 +65,7 @@ const ConditionCard = ({ condition }: ConditionCardProps): JSX.Element => {
</div>
}
/>
<ResourceCardContent resource={condition} />
{softwareName && (
<CardContent>
<Typography variant="caption">
Expand Down
5 changes: 3 additions & 2 deletions src/features/documentReferences/DocumentReferenceCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { useTranslation } from "react-i18next";
import DateInfo from "common/components/DateInfo";
import Tag from "common/components/Tag";
import ResourceCardActions from "features/resources/ResourceCardActions";

import { TERMINOLOGY_SYSTEM_URL } from "../../constants";
import ResourceCardContent from "features/resources/ResourceCardContent";
import { TERMINOLOGY_SYSTEM_URL } from "models/constants";

const useStyles = makeStyles((theme) => ({
flexContainer: {
Expand Down Expand Up @@ -48,6 +48,7 @@ const DocumentReferenceCard = ({
</div>
}
/>
<ResourceCardContent resource={documentReference} />
{softwareName && (
<CardContent>
<Typography variant="caption">
Expand Down
5 changes: 3 additions & 2 deletions src/features/encounters/EncounterCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { useTranslation } from "react-i18next";
import DateInfo from "common/components/DateInfo";
import Tag from "common/components/Tag";
import ResourceCardActions from "features/resources/ResourceCardActions";
import ResourceCardContent from "features/resources/ResourceCardContent";
import { getResourceTagValues } from "features/resources/utils";

import { TERMINOLOGY_SYSTEM_URL } from "../../constants";
import { TERMINOLOGY_SYSTEM_URL } from "models/constants";

const useStyles = makeStyles((theme) => ({
flexContainer: {
Expand Down Expand Up @@ -54,6 +54,7 @@ const EncounterCard = ({ encounter }: EncounterCardProps): JSX.Element => {
</div>
}
/>
<ResourceCardContent resource={encounter} />
{softwareName && (
<CardContent>
<Typography variant="caption">
Expand Down
17 changes: 12 additions & 5 deletions src/features/patients/PatientInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { DateTime } from "luxon";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";

import InnterHTMLDiv from "common/components/InnerHTMLDiv";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inner !

import Tooltip from "common/components/Tooltip";
import { useApiPatientsListQuery } from "services/api/api";

import { getINS, getIPP } from "./utils";
Expand Down Expand Up @@ -74,11 +76,16 @@ const PatientInfo = (): JSX.Element => {
<CircularProgress />
) : (
<>
<div className={classes.columnContainer}>
<Avatar classes={{ root: classes.avatar }}>
<PersonIcon fontSize="large" />
</Avatar>
</div>
<Tooltip
followCursor
title={<InnterHTMLDiv innerHTML={patient?.text?.div} />}
>
<div className={classes.columnContainer}>
<Avatar classes={{ root: classes.avatar }}>
<PersonIcon fontSize="large" />
</Avatar>
</div>
</Tooltip>
<div className={classes.columnContainer}>
<Typography
className={classes.nameTitle}
Expand Down
15 changes: 9 additions & 6 deletions src/features/resourceFilters/ResourceFilterSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useEffect, useMemo } from "react";

import type { IResourceList } from "@ahryman40k/ts-fhir-types/lib/R4";
import {
Checkbox,
CircularProgress,
Expand All @@ -13,6 +12,7 @@ import { makeStyles } from "@mui/styles";
import { useTranslation } from "react-i18next";

import { useAppDispatch, useAppSelector } from "app/store";
import type { DomainResourceList } from "models/types";

import {
resourceFilterSet,
Expand All @@ -32,8 +32,10 @@ const useStyles = makeStyles((theme) => ({
}));

type ResourceFilterSelectorProps = {
filters: Set<IResourceList["resourceType"]>;
resourceCountDict: Partial<Record<IResourceList["resourceType"], number>>;
filters: Set<DomainResourceList["resourceType"]>;
resourceCountDict: Partial<
Record<DomainResourceList["resourceType"], number>
>;
isFetching?: boolean;
};

Expand Down Expand Up @@ -65,9 +67,10 @@ const ResourceFilterSelector = ({
}
};

const handleFilterClick = (filter: IResourceList["resourceType"]) => () => {
dispatch(resourceFilterSet(filter));
};
const handleFilterClick =
(filter: DomainResourceList["resourceType"]) => () => {
dispatch(resourceFilterSet(filter));
};

return (
<Paper className={classes.container}>
Expand Down
10 changes: 5 additions & 5 deletions src/features/resourceFilters/resourceFilterSlice.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { IResourceList } from "@ahryman40k/ts-fhir-types/lib/R4";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";

import { RootState } from "app/store";
import type { DomainResourceList } from "models/types";

type ResourceFilterSlice = { filters: IResourceList["resourceType"][] };
type ResourceFilterSlice = { filters: DomainResourceList["resourceType"][] };

const initialState: ResourceFilterSlice = {
filters: [],
Expand All @@ -15,7 +15,7 @@ const resourceFilterSlice = createSlice({
reducers: {
resourceFilterSet: (
state,
{ payload }: PayloadAction<IResourceList["resourceType"]>
{ payload }: PayloadAction<DomainResourceList["resourceType"]>
) => {
if (state.filters.some((filter) => filter === payload)) {
state.filters = state.filters.filter((filter) => filter !== payload);
Expand All @@ -25,7 +25,7 @@ const resourceFilterSlice = createSlice({
},
resourceFilterListSet: (
state,
{ payload }: PayloadAction<IResourceList["resourceType"][]>
{ payload }: PayloadAction<DomainResourceList["resourceType"][]>
) => {
return { filters: payload };
},
Expand All @@ -42,6 +42,6 @@ export const {
} = resourceFilterSlice.actions;
export const selectResourceFilters = (
state: RootState
): IResourceList["resourceType"][] => state.resourceFilter.filters;
): DomainResourceList["resourceType"][] => state.resourceFilter.filters;

export default resourceFilterSlice.reducer;
6 changes: 4 additions & 2 deletions src/features/resources/ResourceCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo } from "react";

import type { IResourceList } from "@ahryman40k/ts-fhir-types/lib/R4";
import { Card, CardHeader } from "@mui/material";
import { makeStyles } from "@mui/styles";

Expand All @@ -9,8 +8,10 @@ import Tag from "common/components/Tag";
import ConditionCard from "features/conditions/ConditionCard";
import DocumentReferenceCard from "features/documentReferences/DocumentReferenceCard";
import EncounterCard from "features/encounters/EncounterCard";
import type { DomainResourceList } from "models/types";

import ResourceCardActions from "./ResourceCardActions";
import ResourceCardContent from "./ResourceCardContent";
import { getResourceTagValues } from "./utils";

const useStyles = makeStyles((theme) => ({
Expand All @@ -23,7 +24,7 @@ const useStyles = makeStyles((theme) => ({
}));

type ResourceCardProps = {
resource: IResourceList;
resource: DomainResourceList;
};

const ResourceCard = ({ resource }: ResourceCardProps): JSX.Element => {
Expand Down Expand Up @@ -55,6 +56,7 @@ const ResourceCard = ({ resource }: ResourceCardProps): JSX.Element => {
</div>
}
/>
<ResourceCardContent resource={resource} />
<ResourceCardActions resource={resource} />
</Card>
);
Expand Down
4 changes: 2 additions & 2 deletions src/features/resources/ResourceCardActions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo, useState } from "react";

import type { IResourceList } from "@ahryman40k/ts-fhir-types/lib/R4";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { CardActions, Collapse, Button, CardContent } from "@mui/material";
import { DefaultTheme, makeStyles } from "@mui/styles";
Expand All @@ -9,6 +8,7 @@ import SyntaxHighlighter from "react-syntax-highlighter";
import { monokai } from "react-syntax-highlighter/dist/esm/styles/hljs";

import PDFDialogButton from "common/components/PDFDialogButton";
import type { DomainResourceList } from "models/types";

const useStyles = makeStyles<DefaultTheme, { isExpanded: boolean }>(
(theme) => ({
Expand All @@ -33,7 +33,7 @@ const useStyles = makeStyles<DefaultTheme, { isExpanded: boolean }>(
);

type ResourceCardActionsType = {
resource: IResourceList;
resource: DomainResourceList;
};

const ResourceCardActions = ({
Expand Down
26 changes: 26 additions & 0 deletions src/features/resources/ResourceCardContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";

import { CardContent } from "@mui/material";

import InnterHTMLDiv from "common/components/InnerHTMLDiv";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inner !

import type { DomainResourceList } from "models/types";

type ResourceCardContentProps = {
resource: DomainResourceList;
};

const ResourceCardContent = ({
resource,
}: ResourceCardContentProps): JSX.Element => {
return (
<>
{resource.text?.div && (
<CardContent>
<InnterHTMLDiv innerHTML={resource.text.div} />
</CardContent>
)}
</>
);
};

export default ResourceCardContent;
2 changes: 1 addition & 1 deletion src/features/resources/__tests__/ResourceCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import userEvent from "@testing-library/user-event";
import { DateTime } from "luxon";

import { render, screen } from "common/tests/test-utils";
import { TERMINOLOGY_SYSTEM_URL } from "models/constants";
import {
carePlanFactory,
conditionFactory,
encounterFactory,
} from "services/api/factory";

import { TERMINOLOGY_SYSTEM_URL } from "../../../constants";
import ResourceCard from "../ResourceCard";

const condition = conditionFactory.build();
Expand Down
Loading