-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(new): warn about potential duplicate patient (#2187) #2240
feat(new): warn about potential duplicate patient (#2187) #2240
Conversation
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/hospitalrun/hospitalrun-frontend/dqbxrat2q |
src/patients/new/NewPatient.tsx
Outdated
loggedPatient.givenName === patient.givenName && | ||
loggedPatient.familyName === patient.familyName && | ||
loggedPatient.sex === patient.sex && | ||
loggedPatient.dateOfBirth === patient.dateOfBirth |
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 that we should extra this to a helper util file called is-possible-duplicate-patient.ts
. The file can then export one function isPossibleDuplicatePatient(newPatient, existingPatient)
.
With this, we can then unit test that capability independently, plus reuse if necessary.
<p> | ||
Possible duplicate of:{' '} | ||
{duplicatePatient !== undefined && ( | ||
<Link to={`/patients/${duplicatePatient.id}`}>{duplicatePatient.fullName}</Link> | ||
)} | ||
</p> | ||
<p>Are you sure you want to create this patient?</p> |
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 maybe this could go in a warning alert to bring more attention to the warning we are providing.
<p> | ||
Possible duplicate of:{' '} | ||
{duplicatePatient !== undefined && ( | ||
<Link to={`/patients/${duplicatePatient.id}`}>{duplicatePatient.fullName}</Link> | ||
)} | ||
</p> | ||
<p>Are you sure you want to create this patient?</p> |
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.
All text should be provided through the internationalization process.
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.
Just for clarification, do you mean using the translator? For example:
<Alert color="danger" message={t('addTheTextToBeInternationalizedHere')} />
<div className="row"> | ||
<div className="col-md-12"> | ||
<p> | ||
Possible duplicate of:{' '} |
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.
Needs to be internationalized.
src/patients/new/NewPatient.tsx
Outdated
|
||
const [patient, setPatient] = useState({} as Patient) | ||
const [duplicatePatient, setDuplicatePatient] = useState({} as Patient) |
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 it makes more sense to represent this state as
useState<Patient | undefiend>(undefined)
. I think more clearly represents the presence/absence of a duplicate patient.
@@ -21,8 +22,11 @@ const NewPatient = () => { | |||
const history = useHistory() | |||
const dispatch = useDispatch() | |||
const { createError } = useSelector((state: RootState) => state.patient) | |||
const { patients } = Object(useSelector((state: RootState) => state.patients)) |
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 line can be simplified to:
const { patients } = useSelector((state: RootState) => state.patients)
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 originally had that line, but the tests would always fail. The message is:
TypeError: Cannot destructure property 'patients' of '(0 , _reactRedux.useSelector)(...)' as it is undefined.
The only solution I found was adding the Object(...) at the beginning. I can't seem to get it working without it.
src/patients/new/NewPatient.tsx
Outdated
|
||
const [patient, setPatient] = useState({} as Patient) | ||
const [duplicatePatient, setDuplicatePatient] = useState({} as Patient) |
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.
After thinking about this functionality some more and seeing it action. I think it make sense to support possibly finding multiple duplicates?
If there were already two other patients named "Test User" born on 7/16/2000 and are male. I think all of the should appear in the warning.
src/patients/new/NewPatient.tsx
Outdated
const onSave = () => { | ||
dispatch(createPatient(patient, onSuccessfulSave)) | ||
let isDuplicatePatient = false | ||
const patientsObj = {} | ||
Object.assign(patientsObj, patients) | ||
Object.keys(patientsObj).forEach((patientInfo: any) => { | ||
const loggedPatient = patients[patientInfo] | ||
if ( | ||
loggedPatient.givenName === patient.givenName && | ||
loggedPatient.familyName === patient.familyName && | ||
loggedPatient.sex === patient.sex && | ||
loggedPatient.dateOfBirth === patient.dateOfBirth | ||
) { | ||
setShowDuplicateNewPatientModal(true) | ||
setDuplicatePatient(loggedPatient as Patient) | ||
isDuplicatePatient = true | ||
} | ||
}) | ||
if (!isDuplicatePatient) { | ||
dispatch(createPatient(patient, onSuccessfulSave)) | ||
} | ||
} |
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.
After adding support for finding all possible duplicate patients, rather than just the first, this function would be a good candidate for Arrays.filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter.
const onSave = () => {
const duplicatePatients = patients.filter((existingPatient) => isPossibleDuplicatePatient(patient, existingPatient));
if(duplicatePatients.length > 0) {
setShowDuplicateNewPatientModal(true)
setDuplicatePatient(existingPatient)
} else {
dispatch(createPatient(patient, onSuccessfulSave))
}
}
@@ -10,6 +10,7 @@ import Patient from '../../shared/model/Patient' | |||
import { RootState } from '../../shared/store' | |||
import GeneralInformation from '../GeneralInformation' | |||
import { createPatient } from '../patient-slice' | |||
import DuplicateNewPatientModal from './DuplicateNewPatientModal' |
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 should be some tests to test this new workflow.
Basically, have an already existing patient in the redux store, try to create a new patient with the same information, and test to make sure that the new modal shows.
const onContinueButtonClickSpy = jest.fn() | ||
const store = mockStore({ | ||
patient: { | ||
patient: { | ||
id: '1234', | ||
}, | ||
}, | ||
} as any) | ||
|
||
const wrapper = mount( | ||
<Provider store={store}> | ||
<DuplicateNewPatientModal | ||
show | ||
toggle={jest.fn()} | ||
onCloseButtonClick={jest.fn()} | ||
onContinueButtonClick={onContinueButtonClickSpy} | ||
/> | ||
</Provider>, | ||
) | ||
wrapper.update() |
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 code block is duplicated several times in this file. I think we can extract it to a setup function that looks like:
const setup = () => {
const onContinueButtonClickSpy = jest.fn()
const store = mockStore({
patient: {
patient: {
id: '1234',
},
},
} as any)
const wrapper = mount(
<Provider store={store}>
<DuplicateNewPatientModal
show
toggle={jest.fn()}
onCloseButtonClick={jest.fn()}
onContinueButtonClick={onContinueButtonClickSpy}
/>
</Provider>,
)
wrapper.update()
return { wrapper: wrapper as ReactWrapper }
}
Sorry, I accidentally requested a merge to master (did not make the changes yet). I am making the changes now. |
…into duplicate-patient-modal
…into duplicate-patient-modal
3b961c6
to
8ad58a0
Compare
Recently Pushed Requested Changes1. Helper util file (is-possible-duplicate-patient.ts)Created helper util file to allow for reusability if necessary. 2. Support for finding multiple duplicate patientsNewPatient.tsxDuplicateNewPatientModal.tsxUsed the 3. New alert and internationalized textDuplicateNewPatientModal.tsxAdded an alert to bring more attention to the warning being provided. Also, all the text is internationalized (still missing english translation key in console). Modal (Multiple Patients)Modal (Single Patient)4. Setup function in test fileDuplicateNewPatientModal.test.tsxUsing the setup functionSince this code block was duplicated multiple times, it was extracted to a setup function for easy reusability. 5. Test case for new modalNewPatient.test.tsxNewPatient.tsxA test needed to be created in order to test the new modal feature. Given some existing patient in the redux store, if a newly created patient had the same information as the existing one, then the modal should render (or in this case return true). Other Things
|
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.
Few comments on the code! I really like the new functionality for the multiple duplicate patients!
const { duplicatePatient, show, toggle, onCloseButtonClick, onContinueButtonClick } = props | ||
|
||
const alertMessage = | ||
'Patient with matching information found in database. Are you sure you want to create this patient?' |
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 alert message needs to have the string internationalized.
<Alert color="danger" title={t('Warning!')} message={t(alertMessage)} /> | ||
<div className="row"> | ||
<div className="col-md-12"> | ||
{`${t('Possible duplicate patient')}: `} |
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 value passed to be a key that is defined in the locales
folder.
|
||
const body = ( | ||
<> | ||
<Alert color="danger" title={t('Warning!')} message={t(alertMessage)} /> |
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.
Thoughts on having this as a warning color rather than danger?
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 it makes sense. It's more of a warning message than an error message, and it still stands out.
@@ -0,0 +1,13 @@ | |||
import Patient from '../../shared/model/Patient' | |||
|
|||
export function isPossibleDuplicatePatient(newPatient: Patient, existingPatient: Patient) { |
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.
as trivial as it is, we should have a test around this functionality.
@@ -0,0 +1,13 @@ | |||
import Patient from '../../shared/model/Patient' | |||
|
|||
export function isPossibleDuplicatePatient(newPatient: Patient, existingPatient: Patient) { |
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 would expect a function named isPossibleDuplicatePatient
to return a boolean rather than a object.
I think this function can be simplified as:
export function isPossibleDuplicatePatient(newPatient: Patient, existingPatient: Patient) {
return newPatient.givenName === existingPatient.givenName &&
newPatient.familyName === existingPatient.familyName &&
newPatient.sex === existingPatient.sex &&
newPatient.dateOfBirth === existingPatient.dateOfBirth
}
<div className="col-md-12"> | ||
{`${t('Possible duplicate patient')}: `} | ||
{duplicatePatient !== undefined && | ||
Object.entries(duplicatePatient).length === 1 && | ||
Object.entries(duplicatePatient).map(([key, patient]) => ( | ||
<Link key={key.toString()} to={`/patients/${patient.id}`}> | ||
{patient.fullName} | ||
</Link> | ||
))} | ||
{duplicatePatient !== undefined && | ||
Object.entries(duplicatePatient).length > 1 && | ||
Object.entries(duplicatePatient).map(([key, patient]) => ( | ||
<li key={key.toString()}> | ||
<Link to={`/patients/${patient.id}`}>{patient.fullName}</Link> | ||
</li> | ||
))} | ||
</div> |
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 that it is ok if it always displays a list no matter the number of duplicate patients returned. If we do that, then we can simplify this code.
…into duplicate-patient-modal
…ospitalrun-frontend into duplicate-patient-modal
03250c9
to
924cf9d
Compare
Newly Pushed Changes1. Changed alert color and internationalized textI changed the color of the alert to "warning" instead of danger, and internationalized the text by adding them in the 2. Changed
|
Fixes #2187
Changes proposed in this pull request:
No new dependency added