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

Add date of death, age at death, detailed ethnicity, and detailed race #2786

Merged
merged 2 commits into from
Oct 18, 2024
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

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions containers/ecr-viewer/src/app/api/fhirPath.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ patientCounty: "Bundle.entry.resource.where(resourceType = 'Patient').address.fi
patientIds: "Bundle.entry.resource.where(resourceType = 'Patient').identifier"
patientDOB: "Bundle.entry.resource.where(resourceType = 'Patient').birthDate"
patientVitalStatus: "Bundle.entry.resource.where(resourceType = 'Patient').deceasedBoolean"
patientDOD: "Bundle.entry.resource.where(resourceType = 'Patient').deceasedDate"
patientGender: "Bundle.entry.resource.where(resourceType = 'Patient').gender"
patientRace: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race').extension.where(url = 'ombCategory').valueCoding.display"
patinetRaceExtension: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race').extension.where(url = 'detailed').valueCoding.display"
patientEthnicity: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.first().valueCoding.display"
patientRaceDetailed: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race').extension.where(url = 'detailed').valueCoding.display"
patientEthnicity: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.where(url = 'ombCategory').valueCoding.display"
patientEthnicityDetailed: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.where(url = 'detailed').valueCoding.display"
patientLanguage: "Bundle.entry.resource.where(resourceType = 'Patient').communication.first().language.coding.first().display"
patientTribalAffiliation: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url='http: //hl7.org/fhir/us/ecr/StructureDefinition/us-ph-tribal-affiliation-extension').extension.where(url='TribeName').value.display"
patientEmergencyContact: "Bundle.entry.resource.where(resourceType = 'Patient').contact.first()"
Expand Down
83 changes: 70 additions & 13 deletions containers/ecr-viewer/src/app/services/evaluateFhirDataService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,37 @@ export const evaluatePatientRace = (
mappings: PathMappings,
) => {
const raceCat = evaluate(fhirBundle, mappings.patientRace)[0];
const raceDetailedExt =
evaluate(fhirBundle, mappings.patinetRaceExtension)[0] ?? "";
const raceDetailed =
evaluate(fhirBundle, mappings.patientRaceDetailed)[0] ?? "";

if (raceDetailedExt) {
return `${raceCat}, ${raceDetailedExt}`;
if (raceDetailed) {
return raceCat + "\n" + raceDetailed;
} else {
return raceCat;
}
};

/**
* Evaluates the patients ethnicity from the FHIR bundle and formats for display.
* @param fhirBundle - The FHIR bundle containing patient contact info.
* @param mappings - The object containing the fhir paths.
* @returns - The patient's ethnicity information, including additional ethnicity extension (if available).
*/
export const evaluatePatientEthnicity = (
fhirBundle: Bundle,
mappings: PathMappings,
) => {
const ethnicity = evaluate(fhirBundle, mappings.patientEthnicity)[0] ?? "";
const ethnicityDetailed =
evaluate(fhirBundle, mappings.patientEthnicityDetailed)[0] ?? "";

if (ethnicityDetailed) {
return ethnicity + "\n" + ethnicityDetailed;
} else {
return ethnicity;
}
};

/**
* Evaluates patient address from the FHIR bundle and formats it into structured data for display.
* @param fhirBundle - The FHIR bundle containing patient contact info.
Expand Down Expand Up @@ -157,22 +178,49 @@ const evaluateTravelHistory = (
};

/**
* Calculates the age of a patient to a given date or today.
* Calculates the age of a patient to a given date or today, unless DOD exists.
* @param fhirBundle - The FHIR bundle containing patient information.
* @param fhirPathMappings - The mappings for retrieving patient date of birth.
* @param [givenDate] - Optional. The target date to calculate the age. Defaults to the current date if not provided.
* @returns - The age of the patient in years, or undefined if date of birth is not available.
* @returns - The age of the patient in years, or undefined if date of birth is not available or if date of death exists.
*/
export const calculatePatientAge = (
fhirBundle: Bundle,
fhirPathMappings: PathMappings,
givenDate?: string,
) => {
const patientDOBString = evaluate(fhirBundle, fhirPathMappings.patientDOB)[0];
if (patientDOBString) {
const patientDODString = evaluate(fhirBundle, fhirPathMappings.patientDOD)[0];
if (patientDOBString && !patientDODString && !givenDate) {
const patientDOB = new Date(patientDOBString);
const targetDate = givenDate ? new Date(givenDate) : new Date();
return dateFns.differenceInYears(targetDate, patientDOB);
return dateFns.differenceInYears(new Date(), patientDOB);
} else if (patientDOBString && givenDate) {
const patientDOB = new Date(patientDOBString);
return dateFns.differenceInYears(new Date(givenDate), patientDOB);
} else {
return undefined;
}
};

/**
* Calculates Patient Age at Death if DOB and DOD exist, otherwise returns undefined
* @param fhirBundle - The FHIR bundle containing patient information.
* @param fhirPathMappings - The mappings for retrieving patient date of birth and date of death.
* @returns - The age of the patient at death in years, or undefined if date of birth or date of death is not available.
*/
export const calculatePatientAgeAtDeath = (
fhirBundle: Bundle,
fhirPathMappings: PathMappings,
) => {
const patientDOBString = evaluate(fhirBundle, fhirPathMappings.patientDOB)[0];
const patientDODString = evaluate(fhirBundle, fhirPathMappings.patientDOD)[0];

if (patientDOBString && patientDODString) {
const patientDOB = new Date(patientDOBString);
const patientDOD = new Date(patientDODString);
return dateFns.differenceInYears(patientDOD, patientDOB);
} else {
return undefined;
}
};

Expand Down Expand Up @@ -247,11 +295,20 @@ export const evaluateDemographicsData = (
title: "Current Age",
value: calculatePatientAge(fhirBundle, mappings)?.toString(),
},
{
title: "Age at Death",
value: calculatePatientAgeAtDeath(fhirBundle, mappings),
},
{
title: "Vital Status",
value: evaluate(fhirBundle, mappings.patientVitalStatus)[0]
? "Deceased"
: "Alive",
value:
evaluate(fhirBundle, mappings.patientVitalStatus)[0] === false
? "Alive"
: "Deceased",
},
{
title: "Date of Death",
value: evaluate(fhirBundle, mappings.patientDOD)[0],
},
{ title: "Sex", value: evaluate(fhirBundle, mappings.patientGender)[0] },
{
Expand All @@ -260,7 +317,7 @@ export const evaluateDemographicsData = (
},
{
title: "Ethnicity",
value: evaluate(fhirBundle, mappings.patientEthnicity)[0],
value: evaluatePatientEthnicity(fhirBundle, mappings),
},
{
title: "Tribal Affiliation",
Expand Down
7 changes: 7 additions & 0 deletions containers/ecr-viewer/src/app/tests/assets/BundlePatient.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@
"display": "Hispanic or Latino"
}
},
{
"url": "detailed",
"valueCoding": {
"code": "2106-3",
"display": "White"
}
},
{
"url": "text",
"valueString": "Hispanic or Latino"
Expand Down
143 changes: 143 additions & 0 deletions containers/ecr-viewer/src/app/tests/assets/BundlePatientDeceased.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{
"fullUrl": "urn:uuid:6b6b3c4c-4884-4a96-b6ab-c46406839cea",
"resource": {
"resourceType": "Patient",
"id": "6b6b3c4c-4884-4a96-b6ab-c46406839cea",
"meta": {
"profile": [
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
],
"source": [
"ecr"
]
},
"identifier": [
{
"system": "urn:oid:2.16.840.1.113883.3.3316.100",
"value": "10308625"
}
],
"name": [
{
"family": "CASTILLO",
"given": [
"ABEL"
]
}
],
"birthDate": "2015-04-15",
"deceasedBoolean": true,
"deceasedDate": "2020-02-27",
"gender": "male",
"extension": [
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
"extension": [
{
"url": "ombCategory",
"valueCoding": {
"code": "2054-5",
"display": "Black or African American"
}
},
{
"url": "detailed",
"valueCoding": {
"code": "2076-8",
"display": "African"
}
},
{
"url": "text",
"valueString": "Black or African American"
}
]
},
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
"extension": [
{
"url": "ombCategory",
"valueCoding": {
"code": "2135-2",
"display": "Hispanic or Latino"
}
},
{
"url": "detailed",
"valueCoding": {
"code": "2106-3",
"display": "White"
}
},
{
"url": "text",
"valueString": "Hispanic or Latino"
}
]
},
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex",
"extension": [
{
"url": "value",
"valueCodeableConcept": {
"coding": [
{
"code": "M",
"display": "Male",
"system": "urn:oid:2.16.840.1.113883.5.1"
}
]
}
}
]
}
],
"address": [
{
"line": [
"1050 CARPENTER ST"
],
"city": "EDWARDS",
"state": "CA",
"country": "US",
"postalCode": "93523-2800"
}
],
"telecom": [
{
"system": "phone",
"value": "+18184195968",
"use": "home"
},
{
"system": "email",
"value": "[email protected]"
}
],
"communication": [
{
"language": {
"coding": [
{
"system": "urn:ietf:bcp:47",
"code": "en",
"display": "English"
}
]
}
}
]
},
"request": {
"method": "PUT",
"url": "Patient/6b6b3c4c-4884-4a96-b6ab-c46406839cea"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp
<div
class="grid-col maxw7 text-pre-line"
>
Alive
Deceased
</div>
</div>
<div
Expand Down Expand Up @@ -284,6 +284,44 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp
class="section__line_gray"
/>
</div>
<div>
<div
class="grid-row"
>
<div
class="data-title padding-right-1"
>
Age at Death
</div>
<div
class="grid-col maxw7 text-pre-line text-italic text-base"
>
No data
</div>
</div>
<div
class="section__line_gray"
/>
</div>
<div>
<div
class="grid-row"
>
<div
class="data-title padding-right-1"
>
Date of Death
</div>
<div
class="grid-col maxw7 text-pre-line text-italic text-base"
>
No data
</div>
</div>
<div
class="section__line_gray"
/>
</div>
<div>
<div
class="grid-row"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
evaluateFacilityId,
evaluateIdentifiers,
evaluatePatientRace,
evaluatePatientEthnicity,
evaluatePractitionerRoleReference,
evaluateReference,
evaluateValue,
Expand Down Expand Up @@ -107,7 +108,17 @@ describe("Evaluate Patient Race", () => {
BundleWithPatient as unknown as Bundle,
mappings,
);
expect(actual).toEqual("Black or African American, African");
expect(actual).toEqual("Black or African American\nAfrican");
});
});

describe("Evaluate Patient Ethnicity", () => {
it("should return ethnicity category and extension if available", () => {
const actual = evaluatePatientEthnicity(
BundleWithPatient as unknown as Bundle,
mappings,
);
expect(actual).toEqual("Hispanic or Latino\nWhite");
});
});

Expand Down
Loading
Loading