Skip to content

Commit

Permalink
filter presets
Browse files Browse the repository at this point in the history
  • Loading branch information
dehall committed Jun 26, 2024
1 parent 179173d commit 2fd7da0
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 29 deletions.
78 changes: 78 additions & 0 deletions src/ui/components/PatientViewer/FilterPresets.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

// map a list to a group of fhir ORs, eg [1,2,3] --> string "'1' | '2' | '3'"
const fhirList = (list) => list.map(i => `'${i}'`).join(' | ');


const DR_CONDITIONS = [
'44054006', // diabetes
'15777000', // prediabetes
'1551000119108', // NPDR
'1501000119109', // PDR
'97331000119101', // DME
'60951000119105', // blindness
];

const SDOH_CONDITIONS = [
'314529007',
'5251000175109',
'424393004',
'160903007',
'706893006',
'73595000',
'160904001',
'741062008',
'10939881000119105',
'422650009',
'423315002',
'706893006',
'266948004',
'5251000175109'
];

const FILTER_PRESETS = Object.freeze({
"Hide Resolved Conditions": {
description: "Hides conditions with an abatement date",
mode: 'exclude',
filterOnGroupByEncounter: false,
filters: {
Condition: ['Condition.abatement'] // is not null
}
},
"Hide Stopped Medications": {
description: "Hides medications with a status of 'stopped'",
mode: 'exclude',
filterOnGroupByEncounter: false,
filters: {
MedicationRequest: ["MedicationRequest.status = 'stopped'"]
}
},
'Disease Focus: Diabetic Retinopathy': {
description: 'Keeps entries relevant to Diabetic Retinopathy',
mode: 'include',
filterOnGroupByEncounter: true,
filters: {
Encounter: ["Encounter.type.coding.code = '185349003'"],
Condition: [`Condition.code.coding.code in (${fhirList(DR_CONDITIONS)})`],
Observation: []
}
},
'Hide SDOH Conditions': {
description: 'Hides most SDOH conditions, such as "stress", employment status, etc',
mode: 'exclude',
filterOnGroupByEncounter: true,
filters: {
Condition: [`Condition.code.coding.code in (${fhirList(SDOH_CONDITIONS)})`]
}
}
// Coming soon...
// 'Cardiology': {
// description: 'Keeps entries relevant to Cardiology',
// mode: 'include',
// filters: {

// }
// }

});

export default FILTER_PRESETS;
45 changes: 21 additions & 24 deletions src/ui/components/PatientViewer/PatientViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ import csvToFhir from './csvToFhir';

import { evaluateResource, appliesToResource } from '../../fhirpath_utils';

import FILTER_PRESETS from './FilterPresets';


const getDropzone = (setLoading, callback) => {
const onDrop = files => {
const reader = new FileReader();
Expand Down Expand Up @@ -116,15 +119,16 @@ const PatientViewer = props => {
setIsLoading(false);
}



const [isGroupByEncounter, setIsGroupByEncounter] = useLocalStorage("group-by-encounter", false);
const [filters, setFilters] = useLocalStorage("filters", {});
const [filterMode, setFilterMode] = useLocalStorage("filter-mode", "include");

// TODO: probably a better way to make these generic. don't want to pass around 100 variables for different settings
const [hideStoppedMeds, setHideStoppedMeds] = useLocalStorage("Hide Stopped Medications", false);
const [hideResolvedConditions, setHideResolvedConditions] = useLocalStorage("Hide Resolved Conditions", false);
const loadedPresets = [];
for (const presetKey of Object.keys(FILTER_PRESETS)) {
const [isPresetLoaded,] = useLocalStorage(presetKey, false);

if (isPresetLoaded) {
loadedPresets.push(presetKey);
}
}

useEffect(() => {
if (id && !bundle) {
Expand Down Expand Up @@ -152,14 +156,17 @@ const PatientViewer = props => {

let allResources = bundle.entry.map(e => e.resource);

if (Object.keys(filters).length) {
for (const presetKey of loadedPresets) {
const preset = FILTER_PRESETS[presetKey];
if (isGroupByEncounter && !preset.filterOnGroupByEncounter) continue;
allResources = allResources.filter(r => {
const filtersByResourceType = filters[r.resourceType];
const filtersByResourceType = preset.filters[r.resourceType];
if (!filtersByResourceType) return true;

const anyMatch = filtersByResourceType.some(f => appliesToResource(r, f));
return filterMode === 'exclude' ? !anyMatch : anyMatch;
return preset.mode === 'exclude' ? !anyMatch : anyMatch;
});

}

const patient = allResources.find(r => r.resourceType === 'Patient');
Expand All @@ -186,9 +193,7 @@ const PatientViewer = props => {
<>
<LinksByType />
<EntireRecord
allResources={allResources}
hideResolvedConditions={hideResolvedConditions}
hideStoppedMeds={hideStoppedMeds} />
allResources={allResources} />
</>
)}

Expand Down Expand Up @@ -229,18 +234,10 @@ const LinksByType = () => {
};

const EntireRecord = props => {
const { allResources, hideStoppedMeds, hideResolvedConditions } = props;
const { allResources } = props;
const getByType = type => allResources.filter(r => r.resourceType === type);
let conditions = getByType('Condition');
if (hideResolvedConditions) {
conditions = conditions.filter(c => !c.abatementDateTime);
}

let medications = getByType('MedicationRequest');
if (hideStoppedMeds) {
medications = medications.filter(m => m.status !== 'stopped');
}

const conditions = getByType('Condition');
const medications = getByType('MedicationRequest');
const meds = getByType('Medication');
medications.forEach(m => {
if (m.medicationReference) {
Expand Down
16 changes: 11 additions & 5 deletions src/ui/components/PatientViewer/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import TextField from '@mui/material/TextField';

import InfoIcon from '@mui/icons-material/Info';

import FILTER_PRESETS from './FilterPresets';

const style = {
position: 'absolute',
Expand All @@ -31,10 +32,11 @@ const style = {
const CONFIG_OPTIONS = [
// { key: "filters", defaultValue: "{}",
// description: "TBD" },
{ key: "Hide Resolved Conditions", defaultValue: false, type: "boolean",
description: "If true, conditions with an abatement date will be hidden" },
{ key: "Hide Stopped Medications", defaultValue: false, type: "boolean",
description: "If true, medications with a status of 'stopped' will be hidden" },
// { key: "Hide Resolved Conditions", defaultValue: false, type: "boolean",
// description: "If true, conditions with an abatement date will be hidden" },
// { key: "Hide Stopped Medications", defaultValue: false, type: "boolean",
// description: "If true, medications with a status of 'stopped' will be hidden" },
...Object.entries(FILTER_PRESETS).map(([key, value]) => ({ key, description: value.description, type: "boolean" }))
];

const Settings = () => {
Expand All @@ -61,7 +63,11 @@ const Settings = () => {
for (const configOpt of CONFIG_OPTIONS) {
const key = configOpt.key;

if (configOpt.type == 'boolean') {
if (configOpt.type == 'separator') {
fields.push((<hr />));
} else if (configOpt.type == 'header') {
fields.push((<Typography component="h4"> { configOpt.key }</Typography>));
} else if (configOpt.type == 'boolean') {
fields.push((<Fragment key={key}>
{key}
<Checkbox
Expand Down

0 comments on commit 2fd7da0

Please sign in to comment.