Skip to content
This repository has been archived by the owner on Jan 9, 2023. It is now read-only.

Commit

Permalink
feat(patients): adds ability to approximate age when creating patient
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmeyer committed Dec 18, 2019
1 parent 8ff0ac9 commit c8eba48
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 19 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"eslint-plugin-prettier": "~3.1.1",
"eslint-plugin-react": "~7.17.0",
"eslint-plugin-react-hooks": "~2.3.0",
"history": "~4.10.1",
"husky": "~3.1.0",
"jest": "~24.9.0",
"lint-staged": "~9.5.0",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"preferredLanguage": "Preferred Language",
"basicInformation": "Basic Information",
"contactInformation": "Contact Information",
"approximateAge": "Approximate Age",
"unknownDateOfBirth": "Unknown",
"types": {
"charity": "Charity",
"private": "Private"
Expand Down
66 changes: 64 additions & 2 deletions src/__tests__/patients/new/NewPatientForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import '../../../__mocks__/matchMediaMock'
import React from 'react'
import React, { ChangeEvent } from 'react'
import { shallow, mount } from 'enzyme'
import { Button } from '@hospitalrun/components'
import { Button, Checkbox } from '@hospitalrun/components'
import { render, act, fireEvent } from '@testing-library/react'
import { DateTime } from 'luxon'
import NewPatientForm from '../../../patients/new/NewPatientForm'
import TextInputWithLabelFormGroup from '../../../components/input/TextInputWithLabelFormGroup'
import SelectWithLabelFormGroup from '../../../components/input/SelectWithLableFormGroup'
Expand Down Expand Up @@ -98,6 +99,14 @@ describe('New Patient Form', () => {
expect(dateOfBirthTextInput.prop('label')).toEqual('patient.dateOfBirth')
})

it('should have a unknown checkbox', () => {
const wrapper = shallow(<NewPatientForm onCancel={onCancel} onSave={onSave} />)
const unknownCheckbox = wrapper.find(Checkbox)
expect(unknownCheckbox).toHaveLength(1)
expect(unknownCheckbox.prop('name')).toEqual('unknown')
expect(unknownCheckbox.prop('label')).toEqual('patient.unknownDateOfBirth')
})

it('should have a patient type dropdown with the proper options', () => {
const wrapper = shallow(<NewPatientForm onCancel={onCancel} onSave={onSave} />)
const patientTypeDropdown = wrapper.findWhere((w) => w.prop('name') === 'type')
Expand Down Expand Up @@ -194,6 +203,59 @@ describe('New Patient Form', () => {
})
})

describe('calculate approximate date of birth', () => {
it('should calculate the approximate date of birth on change and store the value in the date of birth input', () => {
const wrapper = shallow(<NewPatientForm onCancel={onCancel} onSave={onSave} />)
const unknownCheckbox = wrapper.find(Checkbox)

act(() => {
if (unknownCheckbox) {
unknownCheckbox.prop('onChange')!({ target: { checked: true } } as ChangeEvent<
HTMLInputElement
>)
}
})

const approximateAgeInput = wrapper.findWhere((w) => w.prop('name') === 'approximateAge')
act(() => {
approximateAgeInput.prop('onChange')({ target: { value: 5 } })
})

const dateOfBirthTextInput = wrapper.findWhere((w) => w.prop('name') === 'dateOfBirth')

expect(dateOfBirthTextInput.prop('value')).toEqual(
DateTime.local()
.minus({ year: 5 })
.toISODate(),
)
})
})

describe('on unknown checkbox click', () => {
it('should show a approximate age input box when checkbox is checked', () => {
const wrapper = shallow(<NewPatientForm onCancel={onCancel} onSave={onSave} />)
const approximateAgeInputBefore = wrapper.findWhere(
(w) => w.prop('name') === 'approximateAge',
)
expect(approximateAgeInputBefore).toHaveLength(0)

const unknownCheckbox = wrapper.find(Checkbox)

act(() => {
if (unknownCheckbox) {
unknownCheckbox.prop('onChange')!({ target: { checked: true } } as ChangeEvent<
HTMLInputElement
>)
}
})

const approximateAgeInputerAfter = wrapper.findWhere(
(w) => w.prop('name') === 'approximateAge',
)
expect(approximateAgeInputerAfter).toHaveLength(1)
})
})

describe('save button', () => {
it('should call the onSave prop with the Patient data', async () => {
const wrapper = render(<NewPatientForm onCancel={onCancel} onSave={onSave} />)
Expand Down
2 changes: 1 addition & 1 deletion src/components/input/TextInputWithLabelFormGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface Props {
label: string
name: string
isEditable: boolean
type: 'text' | 'email'
type: 'text' | 'email' | 'number'
placeholder?: string
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
}
Expand Down
4 changes: 4 additions & 0 deletions src/model/Patient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export default class Patient extends AbstractDBModel {

dateOfBirth?: string

isApproximateDateOfBirth?: boolean

phoneNumber?: string

email?: string
Expand All @@ -26,6 +28,7 @@ export default class Patient extends AbstractDBModel {
name: Name,
sex: string,
dateOfBirth?: string,
isApproximateDateOfBirth?: boolean,
phoneNumber?: string,
email?: string,
address?: string,
Expand All @@ -37,6 +40,7 @@ export default class Patient extends AbstractDBModel {
this.name = name
this.sex = sex
this.dateOfBirth = dateOfBirth
this.isApproximateDateOfBirth = isApproximateDateOfBirth
this.phoneNumber = phoneNumber
this.email = email
this.address = address
Expand Down
73 changes: 57 additions & 16 deletions src/patients/new/NewPatientForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@hospitalrun/components'
import { Button, Checkbox } from '@hospitalrun/components'
import { DateTime } from 'luxon'
import SelectWithLabelFormGroup from '../../components/input/SelectWithLableFormGroup'
import TextFieldWithLabelFormGroup from '../../components/input/TextFieldWithLabelFormGroup'
import TextInputWithLabelFormGroup from '../../components/input/TextInputWithLabelFormGroup'
Expand All @@ -17,13 +18,14 @@ const NewPatientForm = (props: Props) => {
const { t } = useTranslation()
const [isEditable] = useState(true)
const { onCancel, onSave } = props
const [approximateAge, setApproximateAge] = useState(0)
const [patient, setPatient] = useState({
givenName: '',
familyName: '',
suffix: '',
prefix: '',
dateOfBirth: '',
placeOfBirth: '',
isApproximateDateOfBirth: false,
sex: '',
phoneNumber: '',
email: '',
Expand Down Expand Up @@ -64,6 +66,21 @@ const NewPatientForm = (props: Props) => {
onFieldChange(fieldName, event.target.value)
}

const onApproximateAgeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
let approximateAgeNumber
if (Number.isNaN(parseFloat(event.target.value))) {
approximateAgeNumber = 0
} else {
approximateAgeNumber = parseFloat(event.target.value)
}

setApproximateAge(approximateAgeNumber)
const approximateDateOfBirth = DateTime.local().minus({
years: approximateAgeNumber,
})
setPatient({ ...patient, dateOfBirth: approximateDateOfBirth.toISODate() })
}

return (
<div>
<form>
Expand Down Expand Up @@ -133,17 +150,6 @@ const NewPatientForm = (props: Props) => {
}}
/>
</div>
<div className="col">
<DatePickerWithLabelFormGroup
name="dateOfBirth"
label={t('patient.dateOfBirth')}
isEditable={isEditable}
value={patient.dateOfBirth}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
onInputElementChange(event, 'dateOfBirth')
}}
/>
</div>
<div className="col">
<SelectWithLabelFormGroup
name="type"
Expand All @@ -161,7 +167,7 @@ const NewPatientForm = (props: Props) => {
</div>
</div>
<div className="row">
<div className="col-md-4">
<div className="col-md-6">
<TextInputWithLabelFormGroup
label={t('patient.occupation')}
name="occupation"
Expand All @@ -172,7 +178,7 @@ const NewPatientForm = (props: Props) => {
}}
/>
</div>
<div className="col-md-4">
<div className="col-md-6">
<TextInputWithLabelFormGroup
label={t('patient.preferredLanguage')}
name="preferredLanguage"
Expand All @@ -184,7 +190,42 @@ const NewPatientForm = (props: Props) => {
/>
</div>
</div>

<div className="row">
<div className="col-md-4">
<DatePickerWithLabelFormGroup
name="dateOfBirth"
label={t('patient.dateOfBirth')}
isEditable={isEditable && !patient.isApproximateDateOfBirth}
value={patient.dateOfBirth}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
onInputElementChange(event, 'dateOfBirth')
}}
/>
</div>
<div className="col-md-2">
<div className="form-group">
<Checkbox
label={t('patient.unknownDateOfBirth')}
name="unknown"
onChange={(event) => {
setPatient({ ...patient, isApproximateDateOfBirth: event.target.checked })
}}
/>
</div>
</div>
{patient.isApproximateDateOfBirth && (
<div className="col-md-3">
<TextInputWithLabelFormGroup
label={t('patient.approximateAge')}
name="approximateAge"
type="number"
value={`${approximateAge}`}
isEditable={isEditable}
onChange={onApproximateAgeChange}
/>
</div>
)}
</div>
<h3>{t('patient.contactInformation')}</h3>
<div className="row">
<div className="col">
Expand Down

0 comments on commit c8eba48

Please sign in to comment.