diff --git a/packages/esm-generic-patient-widgets-app/src/config-schema.ts b/packages/esm-generic-patient-widgets-app/src/config-schema.ts index 7cfe9b4a43..3776902844 100644 --- a/packages/esm-generic-patient-widgets-app/src/config-schema.ts +++ b/packages/esm-generic-patient-widgets-app/src/config-schema.ts @@ -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 { diff --git a/packages/esm-generic-patient-widgets-app/src/obs-table/obs-table.component.tsx b/packages/esm-generic-patient-widgets-app/src/obs-table/obs-table.component.tsx index 5e20971f8e..b2e0df77cb 100644 --- a/packages/esm-generic-patient-widgets-app/src/obs-table/obs-table.component.tsx +++ b/packages/esm-generic-patient-widgets-app/src/obs-table/obs-table.component.tsx @@ -22,7 +22,7 @@ interface ObsTableProps { const ObsTable: React.FC = ({ 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)); @@ -34,12 +34,17 @@ const ObsTable: React.FC = ({ 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) { diff --git a/packages/esm-generic-patient-widgets-app/src/resources/useObs.ts b/packages/esm-generic-patient-widgets-app/src/resources/useObs.ts index 9a374dbfc9..14cc76abd3 100644 --- a/packages/esm-generic-patient-widgets-app/src/resources/useObs.ts +++ b/packages/esm-generic-patient-widgets-app/src/resources/useObs.ts @@ -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; + 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(); + 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, @@ -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, + 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; - 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) { + 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; diff --git a/packages/esm-generic-patient-widgets-app/translations/am.json b/packages/esm-generic-patient-widgets-app/translations/am.json index f93cafe273..7b2512d798 100644 --- a/packages/esm-generic-patient-widgets-app/translations/am.json +++ b/packages/esm-generic-patient-widgets-app/translations/am.json @@ -2,5 +2,6 @@ "chartView": "Chart View", "dateAndTime": "Date and time", "displaying": "Displaying", + "encounterType": "Encounter type", "tableView": "Table View" } diff --git a/packages/esm-generic-patient-widgets-app/translations/ar.json b/packages/esm-generic-patient-widgets-app/translations/ar.json index b6f142f193..21d4e4828a 100644 --- a/packages/esm-generic-patient-widgets-app/translations/ar.json +++ b/packages/esm-generic-patient-widgets-app/translations/ar.json @@ -1,6 +1,7 @@ { "chartView": "عرض الرسم البياني", - "dateAndTime": "Date and time", + "dateAndTime": "التاريخ والوقت", "displaying": "عرض", + "encounterType": "نوع اللقاء", "tableView": "عرض الجدول" } diff --git a/packages/esm-generic-patient-widgets-app/translations/en.json b/packages/esm-generic-patient-widgets-app/translations/en.json index f93cafe273..7b2512d798 100644 --- a/packages/esm-generic-patient-widgets-app/translations/en.json +++ b/packages/esm-generic-patient-widgets-app/translations/en.json @@ -2,5 +2,6 @@ "chartView": "Chart View", "dateAndTime": "Date and time", "displaying": "Displaying", + "encounterType": "Encounter type", "tableView": "Table View" } diff --git a/packages/esm-generic-patient-widgets-app/translations/es.json b/packages/esm-generic-patient-widgets-app/translations/es.json index 873ec34ae0..c5da030a72 100644 --- a/packages/esm-generic-patient-widgets-app/translations/es.json +++ b/packages/esm-generic-patient-widgets-app/translations/es.json @@ -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" } diff --git a/packages/esm-generic-patient-widgets-app/translations/fr.json b/packages/esm-generic-patient-widgets-app/translations/fr.json index 00633ac910..25a41a5693 100644 --- a/packages/esm-generic-patient-widgets-app/translations/fr.json +++ b/packages/esm-generic-patient-widgets-app/translations/fr.json @@ -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" } diff --git a/packages/esm-generic-patient-widgets-app/translations/he.json b/packages/esm-generic-patient-widgets-app/translations/he.json index 7684aed1cb..28e76af74b 100644 --- a/packages/esm-generic-patient-widgets-app/translations/he.json +++ b/packages/esm-generic-patient-widgets-app/translations/he.json @@ -1,6 +1,7 @@ { "chartView": "תצוגת תרשים", - "dateAndTime": "Date and time", + "dateAndTime": "תאריך ושעה", "displaying": "מציג", + "encounterType": "סוג הביקור", "tableView": "תצוגת טבלה" } diff --git a/packages/esm-generic-patient-widgets-app/translations/km.json b/packages/esm-generic-patient-widgets-app/translations/km.json index 16ee5eca54..2ec4e32151 100644 --- a/packages/esm-generic-patient-widgets-app/translations/km.json +++ b/packages/esm-generic-patient-widgets-app/translations/km.json @@ -2,5 +2,6 @@ "chartView": "មើលគំនូសតាង", "dateAndTime": "កាលបរិច្ឆេទ និងម៉ោង", "displaying": "ការបង្ហាញ", + "encounterType": "ប្រភេទនៃការជួបប្រទះ", "tableView": "មើលតារាង" }