diff --git a/src/__tests__/patients/related-persons/AddRelatedPersonModal.test.tsx b/src/__tests__/patients/related-persons/AddRelatedPersonModal.test.tsx index 23b5348334..69671fc8b5 100644 --- a/src/__tests__/patients/related-persons/AddRelatedPersonModal.test.tsx +++ b/src/__tests__/patients/related-persons/AddRelatedPersonModal.test.tsx @@ -65,7 +65,7 @@ describe('Add Related Person Modal', () => { }) it('should render a relationship type text input', () => { - const relationshipTypeTextInput = wrapper.findWhere((w) => w.prop('name') === 'type') + const relationshipTypeTextInput = wrapper.findWhere((w: any) => w.prop('name') === 'type') expect(relationshipTypeTextInput).toHaveLength(1) expect(relationshipTypeTextInput.type()).toBe(TextInputWithLabelFormGroup) @@ -115,16 +115,16 @@ describe('Add Related Person Modal', () => { wrapper.update() act(() => { - const relationshipTypeTextInput = wrapper.findWhere((w) => w.prop('name') === 'type') + const relationshipTypeTextInput = wrapper.findWhere((w: any) => w.prop('name') === 'type') relationshipTypeTextInput.prop('onChange')({ target: { value: 'relationship' } }) }) wrapper.update() act(() => { - ;(wrapper.find(Modal).prop('successButton') as any).onClick( - {} as React.MouseEvent, - ) + const { onClick } = wrapper.find(Modal).prop('successButton') as any + onClick({} as React.MouseEvent) }) + expect(onSaveSpy).toHaveBeenCalledTimes(1) expect(onSaveSpy).toHaveBeenCalledWith({ patientId: '123', @@ -132,7 +132,35 @@ describe('Add Related Person Modal', () => { }) }) - it('should display an error message if given name or relationship type is not entered.', () => { + it('should display an error message if given name is not entered', () => { + act(() => { + const patientTypeahead = wrapper.find(Typeahead) + patientTypeahead.prop('onChange')([{ id: '123' }]) + }) + wrapper.update() + + act(() => { + wrapper + .find(Modal) + .prop('successButton') + .onClick({} as React.MouseEvent) + }) + + wrapper.update() + + const errorAlert = wrapper.find(Alert) + const relationshipTypeTextInput = wrapper.findWhere((w: any) => w.prop('name') === 'type') + expect(errorAlert).toHaveLength(1) + expect(errorAlert.prop('message')).toEqual( + 'patient.relatedPersons.error.unableToAddRelatedPerson', + ) + expect(relationshipTypeTextInput.prop('isInvalid')).toBeTruthy() + expect(relationshipTypeTextInput.prop('feedback')).toEqual( + 'patient.relatedPersons.error.relationshipTypeRequired', + ) + }) + + it('should display an error message if relationship type is not entered', () => { act(() => { wrapper .find(Modal) @@ -143,10 +171,15 @@ describe('Add Related Person Modal', () => { wrapper.update() const errorAlert = wrapper.find(Alert) - expect(onSaveSpy).not.toHaveBeenCalled() + const typeahead = wrapper.find(Typeahead) + const typeaheadError = wrapper.find('.related-person-feedback') expect(errorAlert).toHaveLength(1) expect(errorAlert.prop('message')).toEqual( - 'patient.relatedPersons.error.relatedPersonRequired patient.relatedPersons.error.relationshipTypeRequired', + 'patient.relatedPersons.error.unableToAddRelatedPerson', + ) + expect(typeahead.prop('isInvalid')).toBeTruthy() + expect(typeaheadError.text().trim()).toEqual( + 'patient.relatedPersons.error.relatedPersonRequired', ) }) }) diff --git a/src/locales/enUs/translations/patient/index.ts b/src/locales/enUs/translations/patient/index.ts index e599ffb33f..f371bfc413 100644 --- a/src/locales/enUs/translations/patient/index.ts +++ b/src/locales/enUs/translations/patient/index.ts @@ -25,6 +25,7 @@ export default { relatedPerson: 'Related Person', relatedPersons: { error: { + unableToAddRelatedPerson: 'Unable to add new related person.', relatedPersonRequired: 'Related Person is required.', relationshipTypeRequired: 'Relationship Type is required.', }, diff --git a/src/patients/related-persons/AddRelatedPersonModal.tsx b/src/patients/related-persons/AddRelatedPersonModal.tsx index 809c8e66e1..398cda0bb2 100644 --- a/src/patients/related-persons/AddRelatedPersonModal.tsx +++ b/src/patients/related-persons/AddRelatedPersonModal.tsx @@ -19,6 +19,8 @@ const AddRelatedPersonModal = (props: Props) => { const { show, toggle, onCloseButtonClick, onSave } = props const { t } = useTranslation() const [errorMessage, setErrorMessage] = useState('') + const [isRelatedPersonInvalid, setIsRelatedPersonInvalid] = useState(false) + const [isRelationshipInvalid, setIsRelationshipInvalid] = useState(false) const [relatedPerson, setRelatedPerson] = useState({ patientId: '', type: '', @@ -54,6 +56,7 @@ const AddRelatedPersonModal = (props: Props) => { searchAccessor="fullName" placeholder={t('patient.relatedPerson')} onChange={onPatientSelect} + isInvalid={isRelatedPersonInvalid} onSearch={async (query: string) => PatientRepository.search(query)} renderMenuItemChildren={(p: Patient) => { if (patientId() === p.id) { @@ -63,6 +66,11 @@ const AddRelatedPersonModal = (props: Props) => { return
{`${p.fullName} (${p.code})`}
}} /> + {isRelatedPersonInvalid && ( +
+ {t('patient.relatedPersons.error.relatedPersonRequired')} +
+ )} @@ -73,6 +81,8 @@ const AddRelatedPersonModal = (props: Props) => { label={t('patient.relatedPersons.relationshipType')} value={relatedPerson.type} isEditable + isInvalid={isRelationshipInvalid} + feedback={t('patient.relatedPersons.error.relationshipTypeRequired')} isRequired onChange={(event: React.ChangeEvent) => { onInputElementChange(event, 'type') @@ -100,19 +110,21 @@ const AddRelatedPersonModal = (props: Props) => { icon: 'add', iconLocation: 'left', onClick: () => { - let newErrorMessage = '' + let isValid = true if (!relatedPerson.patientId) { - newErrorMessage += `${t('patient.relatedPersons.error.relatedPersonRequired')} ` + isValid = false + setIsRelatedPersonInvalid(true) } if (!relatedPerson.type) { - newErrorMessage += `${t('patient.relatedPersons.error.relationshipTypeRequired')}` + isValid = false + setIsRelationshipInvalid(true) } - if (!newErrorMessage) { + if (isValid) { onSave(relatedPerson as RelatedPerson) } else { - setErrorMessage(newErrorMessage.trim()) + setErrorMessage(t('patient.relatedPersons.error.unableToAddRelatedPerson')) } }, }}