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

Feature/add notes to patients #1896

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6ecd7dd
Merge pull request #1 from HospitalRun/master
wwbarros Mar 1, 2020
0fec46f
Merge pull request #2 from HospitalRun/master
wwbarros Mar 2, 2020
53f07fb
Merge pull request #3 from HospitalRun/master
wwbarros Mar 8, 2020
0639e17
Merge pull request #4 from HospitalRun/master
wwbarros Mar 11, 2020
b43ae11
feat(notes): add notes to pacient
wwbarros Mar 12, 2020
85f83de
Merge branch 'master' into feature/add-notes-to-patients
Mar 12, 2020
b4f52f9
Merge branch 'master' into feature/add-notes-to-patients
Mar 13, 2020
fdbf89e
Merge branch 'master' into feature/add-notes-to-patients
Mar 13, 2020
007f779
Merge branch 'master' into feature/add-notes-to-patients
Mar 13, 2020
6f09d6c
Merge branch 'master' into feature/add-notes-to-patients
Mar 14, 2020
8363f65
Merge branch 'master' into feature/add-notes-to-patients
Mar 14, 2020
494bebe
Merge branch 'master' into feature/add-notes-to-patients
Mar 15, 2020
05a1339
Merge branch 'master' into feature/add-notes-to-patients
Mar 15, 2020
9d22dd1
Merge branch 'master' into feature/add-notes-to-patients
Mar 15, 2020
409feca
Merge branch 'master' into feature/add-notes-to-patients
Mar 16, 2020
e5583f9
Merge branch 'master' into feature/add-notes-to-patients
Mar 16, 2020
45aff0f
Merge branch 'master' into feature/add-notes-to-patients
Mar 16, 2020
9106487
Merge branch 'master' into feature/add-notes-to-patients
Mar 17, 2020
7b92279
Merge branch 'master' into feature/add-notes-to-patients
Mar 18, 2020
9e90182
Merge branch 'master' into feature/add-notes-to-patients
Mar 18, 2020
09b97fc
Merge branch 'master' into feature/add-notes-to-patients
Mar 18, 2020
42ee418
Merge branch 'master' into feature/add-notes-to-patients
Mar 19, 2020
607d2b3
Merge branch 'master' into feature/add-notes-to-patients
Mar 19, 2020
503c0d2
Merge branch 'master' into feature/add-notes-to-patients
Mar 19, 2020
2c3d37c
Merge branch 'master' into feature/add-notes-to-patients
Mar 19, 2020
bfb648f
Merge branch 'master' into feature/add-notes-to-patients
Mar 19, 2020
2ee94d2
Merge branch 'master' into feature/add-notes-to-patients
Mar 21, 2020
f525861
Merge branch 'master' into feature/add-notes-to-patients
Mar 21, 2020
5491e66
Merge branch 'master' into feature/add-notes-to-patients
Mar 21, 2020
5385b0f
Merge branch 'master' into feature/add-notes-to-patients
Mar 21, 2020
92ef93d
Merge branch 'master' into feature/add-notes-to-patients
matteovivona Mar 31, 2020
90a5d1d
Merge branch 'master' into feature/add-notes-to-patients
Apr 1, 2020
c715b06
Merge branch 'master' into feature/add-notes-to-patients
Apr 1, 2020
c6a206b
Merge branch 'master' into feature/add-notes-to-patients
Apr 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/__tests__/patients/view/ViewPatient.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import RelatedPersonTab from 'patients/related-persons/RelatedPersonTab'
import * as ButtonBarProvider from 'page-header/ButtonBarProvider'
import Allergies from 'patients/allergies/Allergies'
import Diagnoses from 'patients/diagnoses/Diagnoses'
import NotesTab from 'patients/notes/NoteTab'
import Patient from '../../../model/Patient'
import PatientRepository from '../../../clients/db/PatientRepository'
import * as titleUtil from '../../../page-header/useTitle'
Expand Down Expand Up @@ -127,12 +128,13 @@ describe('ViewPatient', () => {
const tabs = tabsHeader.find(Tab)
expect(tabsHeader).toHaveLength(1)

expect(tabs).toHaveLength(5)
expect(tabs).toHaveLength(6)
expect(tabs.at(0).prop('label')).toEqual('patient.generalInformation')
expect(tabs.at(1).prop('label')).toEqual('patient.relatedPersons.label')
expect(tabs.at(2).prop('label')).toEqual('scheduling.appointments.label')
expect(tabs.at(3).prop('label')).toEqual('patient.allergies.label')
expect(tabs.at(4).prop('label')).toEqual('patient.diagnoses.label')
expect(tabs.at(5).prop('label')).toEqual('patient.notes.label')
})

it('should mark the general information tab as active and render the general information component when route is /patients/:id', async () => {
Expand Down Expand Up @@ -237,4 +239,28 @@ describe('ViewPatient', () => {
expect(diagnosesTab).toHaveLength(1)
expect(diagnosesTab.prop('patient')).toEqual(patient)
})

it('should mark the notes tab as active when it is clicked and render the note component when route is /patients/:id/notes', async () => {
let wrapper: any
await act(async () => {
wrapper = await setup()
})

await act(async () => {
const tabsHeader = wrapper.find(TabsHeader)
const tabs = tabsHeader.find(Tab)
tabs.at(5).prop('onClick')()
})

wrapper.update()

const tabsHeader = wrapper.find(TabsHeader)
const tabs = tabsHeader.find(Tab)
const notesTab = wrapper.find(NotesTab)

expect(history.location.pathname).toEqual(`/patients/${patient.id}/notes`)
expect(tabs.at(5).prop('active')).toBeTruthy()
expect(notesTab).toHaveLength(1)
expect(notesTab.prop('patient')).toEqual(patient)
})
})
12 changes: 12 additions & 0 deletions src/locales/enUs/translations/patient/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ export default {
addDiagnosisAbove: 'Add a diagnosis using the button above.',
successfullyAdded: 'Successfully added a new diagnosis!',
},
note: 'Note',
notes: {
label: 'Notes',
new: 'New Note',
warning: {
noNotes: 'No Notes',
},
error: {
noteRequired: 'Note is required.',
},
addNoteAbove: 'Add a note using the button above.',
},
types: {
charity: 'Charity',
private: 'Private',
Expand Down
1 change: 1 addition & 0 deletions src/locales/enUs/translations/patients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export default {
newPatient: 'New Patient',
successfullyCreated: 'Successfully created patient',
successfullyAddedRelatedPerson: 'Successfully added the new related person',
successfullyAddedNote: 'Successfully added the new note',
},
}
4 changes: 4 additions & 0 deletions src/model/Note.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default interface Note {
noteDate: Date
jackcmeyer marked this conversation as resolved.
Show resolved Hide resolved
text: string
}
2 changes: 2 additions & 0 deletions src/model/Patient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ContactInformation from './ContactInformation'
import RelatedPerson from './RelatedPerson'
import Allergy from './Allergy'
import Diagnosis from './Diagnosis'
import Note from './Note'

export default interface Patient extends AbstractDBModel, Name, ContactInformation {
sex: string
Expand All @@ -16,4 +17,5 @@ export default interface Patient extends AbstractDBModel, Name, ContactInformati
relatedPersons?: RelatedPerson[]
allergies?: Allergy[]
diagnoses?: Diagnosis[]
notes?: Note[]
}
90 changes: 90 additions & 0 deletions src/patients/notes/NewNoteModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useState } from 'react'
import { Modal, Alert, RichText, Label } from '@hospitalrun/components'
import { useTranslation } from 'react-i18next'
import Note from '../../model/Note'

interface Props {
show: boolean
toggle: () => void
onCloseButtonClick: () => void
onSave: (note: Note) => void
}

const NewNoteModal = (props: Props) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add tests for this modal.

const { show, toggle, onCloseButtonClick, onSave } = props
const { t } = useTranslation()
const [errorMessage, setErrorMessage] = useState('')
const [note, setNote] = useState({
noteDate: new Date(),
text: '',
})

const onFieldChange = (key: string, value: string | any) => {
setNote({
...note,
[key]: value,
})
}

const onRichTextElementChange = (
jackcmeyer marked this conversation as resolved.
Show resolved Hide resolved
event: React.KeyboardEvent<HTMLTextAreaElement>,
fieldName: string,
) => {
onFieldChange(fieldName, event)
}

const body = (
<form>
{errorMessage && <Alert color="danger" title={t('states.error')} message={errorMessage} />}
<div className="row">
<div className="col-md-12">
<div className="form-group">
<Label text={t('patient.note')} htmlFor="noteText" />
<RichText
id="noteText"
value={note.text}
onChange={(event: React.KeyboardEvent<HTMLTextAreaElement>) => {
onRichTextElementChange(event, 'text')
}}
/>
</div>
</div>
</div>
</form>
)

return (
<Modal
show={show}
toggle={toggle}
title={t('patient.notes.new')}
body={body}
closeButton={{
children: t('actions.cancel'),
color: 'danger',
onClick: onCloseButtonClick,
}}
successButton={{
children: t('patient.notes.new'),
color: 'success',
icon: 'add',
iconLocation: 'left',
onClick: () => {
let newErrorMessage = ''

if (!note) {
newErrorMessage += `${t('patient.notes.error.noteRequired')} `
}

if (!newErrorMessage) {
onSave(note as Note)
} else {
setErrorMessage(newErrorMessage.trim())
}
jackcmeyer marked this conversation as resolved.
Show resolved Hide resolved
},
}}
/>
)
}

export default NewNoteModal
96 changes: 96 additions & 0 deletions src/patients/notes/NoteTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* eslint-disable react/no-danger */
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { useTranslation } from 'react-i18next'
import { Button, List, ListItem, Toast, Alert } from '@hospitalrun/components'
import NewNoteModal from 'patients/notes/NewNoteModal'
import Note from 'model/Note'
import Patient from 'model/Patient'
import { updatePatient } from 'patients/patient-slice'
import { RootState } from '../../store'
import Permissions from '../../model/Permissions'

interface Props {
patient: Patient
}

const NoteTab = (props: Props) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add tests for the notes tab:

  1. renders an add new button for someone with permissions
  2. doesn't render the button if no permissions
  3. renders a warning message if no notes
  4. renders a list of notes
  5. Clicking button displays modal
  6. Saving calls the update patient action
  7. On successful save, a toast appears

const dispatch = useDispatch()
const { patient } = props
const { t } = useTranslation()
const { permissions } = useSelector((state: RootState) => state.user)
const [showNewNoteModal, setShowNoteModal] = useState<boolean>(false)

const onNewNoteClick = () => {
setShowNoteModal(true)
}

const closeNewNoteModal = () => {
setShowNoteModal(false)
}

const onAddNoteSuccess = () => {
Toast('success', t('Success!'), t('patients.successfullyAddedNote'))
}

const onNoteSave = (note: Note) => {
const newNotes: Note[] = []

if (patient.notes) {
newNotes.push(...patient.notes)
}

newNotes.push(note)

const patientToUpdate = {
...patient,
notes: newNotes,
}

dispatch(updatePatient(patientToUpdate, onAddNoteSuccess))
closeNewNoteModal()
}
return (
<div>
<div className="row">
<div className="col-md-12 d-flex justify-content-end">
{permissions.includes(Permissions.WritePatients) && (
<Button
outlined
color="success"
icon="add"
iconLocation="left"
onClick={onNewNoteClick}
>
{t('patient.notes.new')}
</Button>
)}
</div>
</div>
<br />
{(!patient.notes || patient.notes.length === 0) && (
<Alert
color="warning"
title={t('patient.notes.warning.noNotes')}
message={t('patient.notes.addNoteAbove')}
/>
)}
<List>
{patient.notes?.map((a: Note) => (
<ListItem>
{new Date(a.noteDate).toLocaleString()}
<div dangerouslySetInnerHTML={{ __html: a.text }} />
</ListItem>
))}
</List>
<NewNoteModal
show={showNewNoteModal}
toggle={closeNewNoteModal}
onCloseButtonClick={closeNewNoteModal}
onSave={onNoteSave}
/>
</div>
)
}

export default NoteTab
9 changes: 9 additions & 0 deletions src/patients/view/ViewPatient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import GeneralInformation from '../GeneralInformation'
import RelatedPerson from '../related-persons/RelatedPersonTab'
import useAddBreadcrumbs from '../../breadcrumbs/useAddBreadcrumbs'
import AppointmentsList from '../appointments/AppointmentsList'
import Note from '../notes/NoteTab'

const getPatientCode = (p: Patient): string => {
if (p) {
Expand Down Expand Up @@ -107,6 +108,11 @@ const ViewPatient = () => {
label={t('patient.diagnoses.label')}
onClick={() => history.push(`/patients/${patient.id}/diagnoses`)}
/>
<Tab
active={location.pathname === `/patients/${patient.id}/notes`}
label={t('patient.notes.label')}
onClick={() => history.push(`/patients/${patient.id}/notes`)}
/>
</TabsHeader>
<Panel>
<Route exact path="/patients/:id">
Expand All @@ -124,6 +130,9 @@ const ViewPatient = () => {
<Route exact path="/patients/:id/diagnoses">
<Diagnoses patient={patient} />
</Route>
<Route exact path="/patients/:id/notes">
<Note patient={patient} />
</Route>
</Panel>
</div>
)
Expand Down