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

(feat) add config to display encounter type in generic widgets #1450

Merged
merged 6 commits into from
Nov 9, 2023
Merged
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
5 changes: 5 additions & 0 deletions packages/esm-generic-patient-widgets-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ export const configSchema = {
_description: 'Type of display for data',
_default: 'dateTime',
},
showEncounterType: {
_type: Type.Boolean,
_description: 'Display Encounter type column',
_default: false,
},
};

export interface ConfigObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface ObsTableProps {
const ObsTable: React.FC<ObsTableProps> = ({ patientUuid }) => {
const { t } = useTranslation();
const config = useConfig();
const { data: obss, error, isLoading, isValidating } = useObs(patientUuid);
const { data: obss, error, isLoading, isValidating } = useObs(patientUuid, config.showEncounterType);
const uniqueDates = [...new Set(obss.map((o) => o.issued))].sort();
const obssByDate = uniqueDates.map((date) => obss.filter((o) => o.issued === date));

Expand All @@ -34,12 +34,17 @@ const ObsTable: React.FC<ObsTableProps> = ({ patientUuid }) => {
})),
];

if (config.showEncounterType) {
tableHeaders.splice(1, 0, { key: 'encounter', header: t('encounterType', 'Encounter type'), isSortable: true });
}

const tableRows = React.useMemo(
() =>
obssByDate?.map((obss, index) => {
const rowData = {
id: `${index}`,
date: formatDatetime(new Date(obss[0].effectiveDateTime), { mode: 'wide' }),
encounter: obss[0].encounter.name,
};

for (const obs of obss) {
Expand Down
135 changes: 73 additions & 62 deletions packages/esm-generic-patient-widgets-app/src/resources/useObs.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,41 @@
import useSWR from 'swr';
import { openmrsFetch, fhirBaseUrl, useConfig, FHIRResource, FHIRCode } from '@openmrs/esm-framework';
import { openmrsFetch, fhirBaseUrl, useConfig } from '@openmrs/esm-framework';
import { ConfigObject } from '../config-schema';

export const pageSize = 100;

export function useObs(patientUuid: string): UseObsResult {
const { encounterTypes, data } = useConfig();

const urlEncounterTypes: string = encounterTypes.length ? `&encounter.type=${encounterTypes.toString()}` : '';
export interface UseObsResult {
data: Array<ObsResult>;
error: Error;
isLoading: boolean;
isValidating: boolean;
}

const {
data: result,
error,
isLoading,
isValidating,
} = useSWR<{ data: ObsFetchResponse }, Error>(
`${fhirBaseUrl}/Observation?subject:Patient=${patientUuid}&code=` +
data.map((d) => d.concept).join(',') +
'&_summary=data&_sort=-date' +
`&_count=${pageSize}` +
urlEncounterTypes,
openmrsFetch,
);
type ObsResult = fhir.Observation & {
conceptUuid: string;
dataType?: string;
valueDateTime?: string;
encounter?: {
name?: string;
};
};

const observations =
result?.data?.entry?.map((entry) => {
const observation: ObsResult = {
...entry.resource,
conceptUuid: entry.resource.code.coding.filter((c) => isUuid(c.code))[0]?.code,
};
export const pageSize = 100;

if (entry.resource.hasOwnProperty('valueDateTime')) {
observation.dataType = 'DateTime';
}
export function useObs(patientUuid: string, includeEncounters: boolean = false): UseObsResult {
const { encounterTypes, data } = useConfig<ConfigObject>();
const urlEncounterTypes: string = encounterTypes.length ? `&encounter.type=${encounterTypes.toString()}` : '';

if (entry.resource.hasOwnProperty('valueString')) {
observation.dataType = 'Text';
}
let url = `${fhirBaseUrl}/Observation?subject:Patient=${patientUuid}&code=${data
.map((d) => d.concept)
.join(',')}&_summary=data&_sort=-date&_count=${pageSize}${urlEncounterTypes}`;

if (entry.resource.hasOwnProperty('valueQuantity')) {
observation.dataType = 'Number';
}
if (includeEncounters) {
url += '&_include=Observation:encounter';
}

if (entry.resource.hasOwnProperty('valueCodeableConcept')) {
observation.dataType = 'Coded';
}
const { data: result, error, isLoading, isValidating } = useSWR<{ data: fhir.Bundle }, Error>(url, openmrsFetch);

return observation;
}) ?? [];
const encounters = includeEncounters ? getEncountersByResources(result?.data?.entry) : [];
const observations = filterAndMapObservations(result?.data?.entry, encounters);

return {
data: observations,
Expand All @@ -56,31 +45,53 @@ export function useObs(patientUuid: string): UseObsResult {
};
}

interface ObsFetchResponse {
entry: Array<{
resource: FHIRResource['resource'];
}>;
id: string;
meta: {
lastUpdated: string;
};
resourceType: string;
total: number;
type: string;
}
function filterAndMapObservations(
entries: Array<fhir.BundleEntry>,
encounters: Array<{ reference: string; display: string }>,
): ObsResult[] {
return (
entries
?.filter((entry) => entry?.resource?.resourceType === 'Observation')
?.map((entry) => {
const resource = entry.resource as fhir.Observation;
const observation: ObsResult = {
...resource,
conceptUuid: resource.code.coding.find((c) => isUuid(c.code))?.code,
};
if (resource.hasOwnProperty('valueDateTime')) {
observation.dataType = 'DateTime';
}

export interface UseObsResult {
data: Array<ObsResult>;
error: Error;
isLoading: boolean;
isValidating: boolean;
if (entry.resource.hasOwnProperty('valueString')) {
observation.dataType = 'Text';
}

if (entry.resource.hasOwnProperty('valueQuantity')) {
observation.dataType = 'Number';
}

if (entry.resource.hasOwnProperty('valueCodeableConcept')) {
observation.dataType = 'Coded';
}

observation.encounter.name = encounters.find(
(e) =>
e.reference === (resource as fhir.Observation & { encounter: { reference?: string } }).encounter.reference,
)?.display;

return observation;
}) || []
);
}

type ObsResult = FHIRResource['resource'] & {
conceptUuid: string;
dataType?: string;
valueDateTime?: string;
};
function getEncountersByResources(resources: Array<fhir.BundleEntry>) {
return resources
?.filter((entry) => entry?.resource?.resourceType === 'Encounter')
.map((entry: fhir.BundleEntry) => ({
reference: `Encounter/${entry.resource.id}`,
display: (entry.resource as fhir.Encounter).type?.[0]?.coding?.[0]?.display || '--',
}));
}

function isUuid(input: string) {
return input.length === 36;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"chartView": "Chart View",
"dateAndTime": "Date and time",
"displaying": "Displaying",
"encounterType": "Encounter type",
"tableView": "Table View"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"chartView": "عرض الرسم البياني",
"dateAndTime": "Date and time",
"dateAndTime": "التاريخ والوقت",
"displaying": "عرض",
"encounterType": "نوع اللقاء",
"tableView": "عرض الجدول"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"chartView": "Chart View",
"dateAndTime": "Date and time",
"displaying": "Displaying",
"encounterType": "Encounter type",
"tableView": "Table View"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"chartView": "Vista de gráfico",
"dateAndTime": "Date and time",
"dateAndTime": "Fecha y hora",
"displaying": "Visualización",
"encounterType": "Tipo de encuentro",
"tableView": "Vista de tabla"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"chartView": "Vue graphique",
"dateAndTime": "Date and time",
"dateAndTime": "Date et heure",
"displaying": "En cours d'affichage",
"encounterType": "Type de rencontre",
"tableView": "Vue tabulaire"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"chartView": "תצוגת תרשים",
"dateAndTime": "Date and time",
"dateAndTime": "תאריך ושעה",
"displaying": "מציג",
"encounterType": "סוג הביקור",
"tableView": "תצוגת טבלה"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"chartView": "មើលគំនូសតាង",
"dateAndTime": "កាលបរិច្ឆេទ និងម៉ោង",
"displaying": "ការបង្ហាញ",
"encounterType": "ប្រភេទនៃការជួបប្រទះ",
"tableView": "មើលតារាង"
}