diff --git a/src/__tests__/patients/edit/EditPatient.test.tsx b/src/__tests__/patients/edit/EditPatient.test.tsx
index 7a632f89a3..717a724428 100644
--- a/src/__tests__/patients/edit/EditPatient.test.tsx
+++ b/src/__tests__/patients/edit/EditPatient.test.tsx
@@ -9,6 +9,7 @@ import { act } from 'react-dom/test-utils'
import configureMockStore, { MockStore } from 'redux-mock-store'
import thunk from 'redux-thunk'
import { Button } from '@hospitalrun/components'
+import { addDays, endOfToday } from 'date-fns'
import EditPatient from '../../../patients/edit/EditPatient'
import GeneralInformation from '../../../patients/GeneralInformation'
import Patient from '../../../model/Patient'
@@ -119,6 +120,71 @@ describe('Edit Patient', () => {
expect(store.getActions()).toContainEqual(patientSlice.updatePatientSuccess(patient))
})
+ it('should pass no given name error when form doesnt contain a given name on save button click', async () => {
+ let wrapper: any
+ await act(async () => {
+ wrapper = await setup()
+ })
+
+ const givenName = wrapper.findWhere((w: any) => w.prop('name') === 'givenName')
+ expect(givenName.prop('value')).toBe('')
+
+ const generalInformationForm = wrapper.find(GeneralInformation)
+ expect(generalInformationForm.prop('errorMessage')).toBe('')
+
+ const saveButton = wrapper.find(Button).at(0)
+ const onClick = saveButton.prop('onClick') as any
+ expect(saveButton.text().trim()).toEqual('actions.save')
+
+ act(() => {
+ onClick()
+ })
+
+ wrapper.update()
+ expect(wrapper.find(GeneralInformation).prop('errorMessage')).toMatch(
+ 'patient.errors.updatePatientError',
+ )
+ expect(wrapper.find(GeneralInformation).prop('feedbackFields').givenName).toMatch(
+ 'patient.errors.patientGivenNameFeedback',
+ )
+ expect(wrapper.update.isInvalid === true)
+ })
+
+ it('should pass invalid date of birth error when input date is grater than today on save button click', async () => {
+ let wrapper: any
+ await act(async () => {
+ wrapper = await setup()
+ })
+
+ const generalInformationForm = wrapper.find(GeneralInformation)
+
+ act(() => {
+ generalInformationForm.prop('onFieldChange')(
+ 'dateOfBirth',
+ addDays(endOfToday(), 10).toISOString(),
+ )
+ })
+
+ wrapper.update()
+
+ const saveButton = wrapper.find(Button).at(0)
+ const onClick = saveButton.prop('onClick') as any
+ expect(saveButton.text().trim()).toEqual('actions.save')
+
+ await act(async () => {
+ await onClick()
+ })
+
+ wrapper.update()
+ expect(wrapper.find(GeneralInformation).prop('errorMessage')).toMatch(
+ 'patient.errors.updatePatientError',
+ )
+ expect(wrapper.find(GeneralInformation).prop('feedbackFields').dateOfBirth).toMatch(
+ 'patient.errors.patientDateOfBirthFeedback',
+ )
+ expect(wrapper.update.isInvalid === true)
+ })
+
it('should navigate to /patients/:id when cancel is clicked', async () => {
let wrapper: any
await act(async () => {
diff --git a/src/__tests__/patients/new/NewPatient.test.tsx b/src/__tests__/patients/new/NewPatient.test.tsx
index 5010329724..cd9a85f262 100644
--- a/src/__tests__/patients/new/NewPatient.test.tsx
+++ b/src/__tests__/patients/new/NewPatient.test.tsx
@@ -10,6 +10,7 @@ import configureMockStore, { MockStore } from 'redux-mock-store'
import thunk from 'redux-thunk'
import * as components from '@hospitalrun/components'
+import { addDays, endOfToday } from 'date-fns'
import NewPatient from '../../../patients/new/NewPatient'
import GeneralInformation from '../../../patients/GeneralInformation'
import Patient from '../../../model/Patient'
@@ -95,7 +96,45 @@ describe('New Patient', () => {
wrapper.update()
expect(wrapper.find(GeneralInformation).prop('errorMessage')).toMatch(
- 'patient.errors.patientGivenNameRequiredOnCreate',
+ 'patient.errors.createPatientError',
+ )
+ expect(wrapper.find(GeneralInformation).prop('feedbackFields').givenName).toMatch(
+ 'patient.errors.patientGivenNameFeedback',
+ )
+ expect(wrapper.update.isInvalid === true)
+ })
+
+ it('should pass invalid date of birth error when input date is grater than today on save button click', async () => {
+ let wrapper: any
+ await act(async () => {
+ wrapper = await setup()
+ })
+
+ const generalInformationForm = wrapper.find(GeneralInformation)
+
+ act(() => {
+ generalInformationForm.prop('onFieldChange')(
+ 'dateOfBirth',
+ addDays(endOfToday(), 10).toISOString(),
+ )
+ })
+
+ wrapper.update()
+
+ const saveButton = wrapper.find(components.Button).at(0)
+ const onClick = saveButton.prop('onClick') as any
+ expect(saveButton.text().trim()).toEqual('actions.save')
+
+ await act(async () => {
+ await onClick()
+ })
+
+ wrapper.update()
+ expect(wrapper.find(GeneralInformation).prop('errorMessage')).toMatch(
+ 'patient.errors.createPatientError',
+ )
+ expect(wrapper.find(GeneralInformation).prop('feedbackFields').dateOfBirth).toMatch(
+ 'patient.errors.patientDateOfBirthFeedback',
)
expect(wrapper.update.isInvalid === true)
})
diff --git a/src/components/input/DatePickerWithLabelFormGroup.tsx b/src/components/input/DatePickerWithLabelFormGroup.tsx
index b6fc61f4b6..e1f137b0e8 100644
--- a/src/components/input/DatePickerWithLabelFormGroup.tsx
+++ b/src/components/input/DatePickerWithLabelFormGroup.tsx
@@ -8,10 +8,12 @@ interface Props {
isEditable?: boolean
onChange?: (date: Date) => void
isRequired?: boolean
+ feedback?: string
+ isInvalid?: boolean
}
const DatePickerWithLabelFormGroup = (props: Props) => {
- const { onChange, label, name, isEditable, value, isRequired } = props
+ const { onChange, label, name, isEditable, value, isRequired, feedback, isInvalid } = props
const id = `${name}DatePicker`
return (
@@ -24,6 +26,8 @@ const DatePickerWithLabelFormGroup = (props: Props) => {
timeIntervals={30}
withPortal={false}
disabled={!isEditable}
+ feedback={feedback}
+ isInvalid={isInvalid}
onChange={(inputDate) => {
if (onChange) {
onChange(inputDate)
diff --git a/src/locales/enUs/translations/patient/index.ts b/src/locales/enUs/translations/patient/index.ts
index 95c36e0973..5332c7073b 100644
--- a/src/locales/enUs/translations/patient/index.ts
+++ b/src/locales/enUs/translations/patient/index.ts
@@ -1,6 +1,5 @@
export default {
patient: {
- code: 'Code',
firstName: 'First Name',
lastName: 'Last Name',
suffix: 'Suffix',
@@ -85,9 +84,10 @@ export default {
private: 'Private',
},
errors: {
- patientGivenNameRequiredOnCreate: 'Could not create new patient.',
- patientGivenNameRequiredOnUpdate: 'Could not update patient.',
+ createPatientError: 'Could not create new patient.',
+ updatePatientError: 'Could not update patient.',
patientGivenNameFeedback: 'Given Name is required.',
+ patientDateOfBirthFeedback: 'Date of Birth can not be greater than today',
},
},
}
diff --git a/src/locales/ptBr/translations/patient/index.ts b/src/locales/ptBr/translations/patient/index.ts
index 71b1bbcb40..571a1ff816 100644
--- a/src/locales/ptBr/translations/patient/index.ts
+++ b/src/locales/ptBr/translations/patient/index.ts
@@ -64,10 +64,10 @@ export default {
private: 'Particular',
},
errors: {
- patientGivenNameRequiredOnCreate: 'Nome do Paciente é necessário.',
- // todo Portuguese translation
- patientGivenNameRequiredOnUpdate: '',
- patientGivenNameFeedback: '',
+ createPatientError: 'Não foi possível criar um paciente.',
+ updatePatientError: 'Não foi possível atualizar o paciente',
+ patientGivenNameFeedback: 'Nome do Paciente é necessário.',
+ patientDateOfBirthFeedback: 'Data de Nascimento não pode ser maior que hoje.',
},
},
}
diff --git a/src/patients/GeneralInformation.tsx b/src/patients/GeneralInformation.tsx
index bd580ea680..93efcb6ce4 100644
--- a/src/patients/GeneralInformation.tsx
+++ b/src/patients/GeneralInformation.tsx
@@ -9,25 +9,28 @@ import TextInputWithLabelFormGroup from '../components/input/TextInputWithLabelF
import SelectWithLabelFormGroup from '../components/input/SelectWithLableFormGroup'
import DatePickerWithLabelFormGroup from '../components/input/DatePickerWithLabelFormGroup'
+interface Feedback {
+ givenName: string
+ dateOfBirth: string
+}
+
+interface InvalidFields {
+ givenName: boolean
+ dateOfBirth: boolean
+}
+
interface Props {
patient: Patient
isEditable?: boolean
errorMessage?: string
onFieldChange?: (key: string, value: string | boolean) => void
- isInvalid?: boolean
- patientGivenNameFeedback?: string
+ invalidFields?: InvalidFields
+ feedbackFields?: Feedback
}
const GeneralInformation = (props: Props) => {
const { t } = useTranslation()
- const {
- patient,
- isEditable,
- onFieldChange,
- errorMessage,
- isInvalid,
- patientGivenNameFeedback,
- } = props
+ const { patient, isEditable, onFieldChange, errorMessage, invalidFields, feedbackFields } = props
const onSelectChange = (event: React.ChangeEvent, fieldName: string) =>
onFieldChange && onFieldChange(fieldName, event.target.value)
@@ -81,8 +84,8 @@ const GeneralInformation = (props: Props) => {
onInputElementChange(event, 'givenName')
}}
isRequired
- isInvalid={isInvalid}
- feedback={patientGivenNameFeedback}
+ isInvalid={invalidFields?.givenName}
+ feedback={feedbackFields?.givenName}
/>
@@ -163,6 +166,8 @@ const GeneralInformation = (props: Props) => {
? new Date(patient.dateOfBirth)
: undefined
}
+ isInvalid={invalidFields?.dateOfBirth}
+ feedback={feedbackFields?.dateOfBirth}
onChange={(date: Date) => {
onDateOfBirthChange(date)
}}
diff --git a/src/patients/edit/EditPatient.tsx b/src/patients/edit/EditPatient.tsx
index ea45f85338..bb9bdce13d 100644
--- a/src/patients/edit/EditPatient.tsx
+++ b/src/patients/edit/EditPatient.tsx
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import { Spinner, Button, Toast } from '@hospitalrun/components'
+import { parseISO } from 'date-fns'
import GeneralInformation from '../GeneralInformation'
import useTitle from '../../page-header/useTitle'
import Patient from '../../model/Patient'
@@ -27,8 +28,14 @@ const EditPatient = () => {
const [patient, setPatient] = useState({} as Patient)
const [errorMessage, setErrorMessage] = useState('')
- const [isInvalid, setIsInvalid] = useState(false)
- const [patientGivenNameFeedback, setPatientGivenNameFeedback] = useState('')
+ const [invalidFields, setInvalidFields] = useState({
+ givenName: false,
+ dateOfBirth: false,
+ })
+ const [feedbackFields, setFeedbackFields] = useState({
+ givenName: '',
+ dateOfBirth: '',
+ })
const { patient: reduxPatient, isLoading } = useSelector((state: RootState) => state.patient)
useTitle(
@@ -68,12 +75,40 @@ const EditPatient = () => {
)
}
- const onSave = () => {
+ const validateInput = () => {
+ let inputIsValid = true
+
if (!patient.givenName) {
- setErrorMessage(t('patient.errors.patientGivenNameRequiredOnUpdate'))
- setIsInvalid(true)
- setPatientGivenNameFeedback(t('patient.errors.patientGivenNameFeedback'))
- } else {
+ inputIsValid = false
+ setErrorMessage(t('patient.errors.updatePatientError'))
+ setInvalidFields((prevState) => ({
+ ...prevState,
+ givenName: true,
+ }))
+ setFeedbackFields((prevState) => ({
+ ...prevState,
+ givenName: t('patient.errors.patientGivenNameFeedback'),
+ }))
+ }
+ if (patient.dateOfBirth) {
+ if (parseISO(patient.dateOfBirth) > new Date(Date.now())) {
+ inputIsValid = false
+ setErrorMessage(t('patient.errors.updatePatientError'))
+ setInvalidFields((prevState) => ({
+ ...prevState,
+ dateOfBirth: true,
+ }))
+ setFeedbackFields((prevState) => ({
+ ...prevState,
+ dateOfBirth: t('patient.errors.patientDateOfBirthFeedback'),
+ }))
+ }
+ }
+ return inputIsValid
+ }
+
+ const onSave = () => {
+ if (validateInput()) {
dispatch(
updatePatient(
{
@@ -104,8 +139,8 @@ const EditPatient = () => {
patient={patient}
onFieldChange={onFieldChange}
errorMessage={errorMessage}
- isInvalid={isInvalid}
- patientGivenNameFeedback={patientGivenNameFeedback}
+ invalidFields={invalidFields}
+ feedbackFields={feedbackFields}
/>
diff --git a/src/patients/new/NewPatient.tsx b/src/patients/new/NewPatient.tsx
index 5e60756fbe..e6a0867f48 100644
--- a/src/patients/new/NewPatient.tsx
+++ b/src/patients/new/NewPatient.tsx
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
import { useDispatch } from 'react-redux'
import { Button, Toast } from '@hospitalrun/components'
+import { parseISO } from 'date-fns'
import GeneralInformation from '../GeneralInformation'
import useTitle from '../../page-header/useTitle'
import Patient from '../../model/Patient'
@@ -23,8 +24,14 @@ const NewPatient = () => {
const [patient, setPatient] = useState({} as Patient)
const [errorMessage, setErrorMessage] = useState('')
- const [isInvalid, setIsInvalid] = useState(false)
- const [patientGivenNameFeedback, setPatientGivenNameFeedback] = useState('')
+ const [invalidFields, setInvalidFields] = useState({
+ givenName: false,
+ dateOfBirth: false,
+ })
+ const [feedbackFields, setFeedbackFields] = useState({
+ givenName: '',
+ dateOfBirth: '',
+ })
useTitle(t('patients.newPatient'))
useAddBreadcrumbs(breadcrumbs, true)
@@ -42,12 +49,40 @@ const NewPatient = () => {
)
}
- const onSave = () => {
+ const validateInput = () => {
+ let inputIsValid = true
+
if (!patient.givenName) {
- setErrorMessage(t('patient.errors.patientGivenNameRequiredOnCreate'))
- setIsInvalid(true)
- setPatientGivenNameFeedback(t('patient.errors.patientGivenNameFeedback'))
- } else {
+ inputIsValid = false
+ setErrorMessage(t('patient.errors.createPatientError'))
+ setInvalidFields((prevState) => ({
+ ...prevState,
+ givenName: true,
+ }))
+ setFeedbackFields((prevState) => ({
+ ...prevState,
+ givenName: t('patient.errors.patientGivenNameFeedback'),
+ }))
+ }
+ if (patient.dateOfBirth) {
+ if (parseISO(patient.dateOfBirth) > new Date(Date.now())) {
+ inputIsValid = false
+ setErrorMessage(t('patient.errors.createPatientError'))
+ setInvalidFields((prevState) => ({
+ ...prevState,
+ dateOfBirth: true,
+ }))
+ setFeedbackFields((prevState) => ({
+ ...prevState,
+ dateOfBirth: t('patient.errors.patientDateOfBirthFeedback'),
+ }))
+ }
+ }
+ return inputIsValid
+ }
+
+ const onSave = () => {
+ if (validateInput()) {
dispatch(
createPatient(
{
@@ -65,6 +100,7 @@ const NewPatient = () => {
...patient,
[key]: value,
})
+ setErrorMessage('')
}
return (
@@ -74,8 +110,8 @@ const NewPatient = () => {
patient={patient}
onFieldChange={onFieldChange}
errorMessage={errorMessage}
- isInvalid={isInvalid}
- patientGivenNameFeedback={patientGivenNameFeedback}
+ invalidFields={invalidFields}
+ feedbackFields={feedbackFields}
/>