-
Notifications
You must be signed in to change notification settings - Fork 232
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) HIE-9: Add MPI workflows to OpenMRS frontend #1397
base: main
Are you sure you want to change the base?
Conversation
Size Change: -170 kB (-2.31%) Total Size: 7.2 MB
ℹ️ View Unchanged
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @reagan-meant! A few comments on this overall.
const { data: attributes, isLoading: isLoadingAttributes } = useInitialPersonAttributes(patientUuid); | ||
const { data: identifiers, isLoading: isLoadingIdentifiers } = useInitialPatientIdentifiers(patientUuid); | ||
const { data: relationships, isLoading: isLoadingRelationships } = useInitialPatientRelationships(patientUuid); | ||
import { useMpiPatient } from './mpi/mpi-patient.resource'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this import to be with the others?
const { freeTextFieldConceptUuid, fieldConfigurations } = useConfig<RegistrationConfig>(); | ||
const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(isLocal ? patientUuid : null); | ||
const { isLoading: isLoadingMpiPatient, patient: mpiPatient } = useMpiPatient(!isLocal ? patientUuid : null); | ||
const { data: deathInfo, isLoading: isLoadingDeathInfo } = useInitialPersonDeathInfo(isLocal ? patientUuid : null); | ||
const { data: attributes, isLoading: isLoadingAttributes } = useInitialPersonAttributes(isLocal ? patientUuid : null); | ||
const { data: identifiers, isLoading: isLoadingIdentifiers } = useInitialPatientIdentifiers( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like this hook would be better broken out into a useInitialFormValuesLocal(string)
and useInitialFormValueMpi(string)
.
|
||
useEffect(() => { | ||
const fetchValues = async () => { | ||
//check that patient is not dead |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
???
isLocal, | ||
]); | ||
|
||
useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern feels off. This feels like it should be split into it's own hook or something an ultimately useSWR()
if at all possible.
|
||
for (const identifier of patient.identifier) { | ||
for (const config of identifierConfig) { | ||
const identifierConfig = config.identifierTypeSystem === identifier.system ? config : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels much cleaner:
const identifierConfig = config.identifierTypeSystem === identifier.system ? config : null; | |
if (config.identifierTypeSystem !== identifier.system) { | |
continue; | |
} |
preferred: false, | ||
address1: '', | ||
})), | ||
age: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a birthdate, so we should be able to calculate the age. There's a helper for that in the framework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see... Can we omit it? It's weird, because there's no reasonable numeric representation of "age", i.e., this probably shouldn't be a number
at all.
dead: fhirPatient.deceasedBoolean, | ||
deathDate: fhirPatient.deceasedDateTime, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In FHIR, only one of these two properties will be set at any given time, so we need to be responsive to that. If deceasedBoolean
is set, deceasedDateTime
will be null
and vice-versa. At the very least, if deceasedDateTime
is non-null we can infer that the patient is deceased if the datetime is now or in the past.
display: fhirPatient.name[0].text | ||
? fhirPatient.name[0].text | ||
: `${fhirPatient.name[0].family} ${fhirPatient.name[0].given[0]}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name format here probably needs to be templateable.
display: fhirPatient.name[0].text | |
? fhirPatient.name[0].text | |
: `${fhirPatient.name[0].family} ${fhirPatient.name[0].given[0]}`, | |
display: fhirPatient.name[0].text ?? | |
`${fhirPatient.name[0].given[0]} ${fhirPatient.name[0].family}`, |
import { type SearchedPatient } from '../types'; | ||
import { getCoreTranslation } from '@openmrs/esm-framework'; | ||
export function inferModeFromSearchParams(searchParams: URLSearchParams) { | ||
return searchParams.get('mode')?.toLowerCase() === 'external' ? 'external' : 'internal'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should probably be mpi
and just no value, which can be interpretted as local
or whatever.
@@ -43,6 +44,7 @@ const patientSearchCustomRepresentation = `custom:(${patientProperties.join(',') | |||
*/ | |||
export function useInfinitePatientSearch( | |||
searchQuery: string, | |||
searchMode: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
searchMode: string, | |
searchMode: 'mpi' | null | undefined, |
@@ -407,6 +517,186 @@ describe('Registering a new patient', () => { | |||
}); | |||
}); | |||
|
|||
describe('Import an MPI patient record', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice Regan! I've left a few comments.
@@ -351,6 +352,21 @@ export const esmPatientRegistrationSchema = { | |||
}, | |||
}, | |||
}, | |||
identifier: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
identifierMappings
reads better.
identifier: { | ||
_type: Type.Array, | ||
_elements: { | ||
identifierTypeSystem: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fhirIdentifierSystem
reads better.
_type: Type.String, | ||
_description: 'Identifier system from the fhir server', | ||
}, | ||
identifierTypeUuid: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
openmrsIdentifierTypeUuid
would be more specific.
@@ -180,6 +188,64 @@ export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch | |||
return [initialFormValues, setInitialFormValues]; | |||
} | |||
|
|||
export function useInitialFormValueMpi(patientUuid: string): [FormValues, Dispatch<FormValues>] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it returns form values, let's rename this hook to something like: useMpiInitialFormValues
or useFormValuesWithMpi
or better.
/* const [sourceRecord, setSourceRecord ] = useState<string | undefined>() | ||
useDefineAppContext<MPIContext>("sourceRecord", { | ||
sourceRecord: sourceRecord | ||
}); */ | ||
|
||
const handleCreatePatientRecord = (externalId: string) => { | ||
//setSourceRecord(externalId); | ||
navigate({ | ||
to: `${window.getOpenmrsSpaBase()}patient-registration?sourceRecord=${externalId}`, | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you plan on cleaning this up?
{isMPIPatient && ( | ||
<div> | ||
<Tag className={styles.mpiTag} type="blue"> | ||
🌐 {'MPI'} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this tag should be wrapped in a t(...)
function to take advantage of translation overrides.
} | ||
|
||
interface PatientSearchResultsProps { | ||
searchResults: SearchedPatient[]; | ||
searchTerm: string; | ||
searchMode?: 'mpi' | null | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be a binary type? Something like:
searchMode?: 'local' | 'mpi';
And we default to local
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requirements
Summary
https://openmrs.atlassian.net/browse/HIE-9
Screenshots
Screen.Recording.2024-12-13.at.14.32.28.mov
Related Issue
See background conversation here
Other