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

feat(patients): add no patients exist #2235

Merged
merged 8 commits into from
Aug 5, 2020
32 changes: 29 additions & 3 deletions src/__tests__/patients/list/ViewPatients.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TextInput, Spinner, Table } from '@hospitalrun/components'
import { TextInput, Spinner, Table, Icon, Typography, Button } from '@hospitalrun/components'
import { mount } from 'enzyme'
import React from 'react'
import { act } from 'react-dom/test-utils'
Expand All @@ -11,6 +11,7 @@ import { mocked } from 'ts-jest/utils'
import * as ButtonBarProvider from '../../../page-header/button-toolbar/ButtonBarProvider'
import ViewPatients from '../../../patients/list/ViewPatients'
import * as patientSlice from '../../../patients/patients-slice'
import AddNewPatient from '../../../patients/view/AddNewPatient'
import { UnpagedRequest } from '../../../shared/db/PageRequest'
import PatientRepository from '../../../shared/db/PatientRepository'

Expand All @@ -35,12 +36,13 @@ describe('Patients', () => {
},
]

const setup = (isLoading?: boolean) => {
const setup = (isLoading?: boolean, currentPatients = patients, count = patients.length) => {
const store = mockStore({
patients: {
patients,
patients: currentPatients,
isLoading,
pageRequest: UnpagedRequest,
count,
},
})
return mount(
Expand Down Expand Up @@ -80,6 +82,30 @@ describe('Patients', () => {
expect(wrapper.find(Spinner)).toHaveLength(1)
})

it('should render no patients exists when no patients exist', () => {
const wrapper = setup(false, [], 0)

const addNewPatient = wrapper.find(AddNewPatient)
expect(addNewPatient).toHaveLength(1)

const icon = wrapper.find(Icon).first()
const typography = wrapper.find(Typography)
const button = wrapper.find(Button)
const iconType = icon.prop('icon')
const iconSize = icon.prop('size')
const typographyText = typography.prop('children')
const typographyVariant = typography.prop('variant')
const buttonIcon = button.prop('icon')
const buttonText = button.prop('children')

expect(iconType).toEqual('patients')
expect(iconSize).toEqual('6x')
expect(typographyText).toEqual('patients.noPatients')
expect(typographyVariant).toEqual('h5')
expect(buttonIcon).toEqual('patient-add')
expect(buttonText).toEqual('patients.newPatient')
})
Copy link
Member

Choose a reason for hiding this comment

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

This test is testing behavior inside the AddNewPatient component. I think instead, this test should test that the AddNewPatient component gets rendered and then this current test should be moved to an AddNewPatient test.


it('should render a table of patients', () => {
const wrapper = setup()

Expand Down
3 changes: 2 additions & 1 deletion src/__tests__/patients/patients-slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ describe('patients slice', () => {

await searchPatients('')(dispatch, getState, null)

expect(PatientRepository.findAll).toHaveBeenCalledTimes(1)
// expecting 2 here because searchPatients uses PatientRepository.count() which calls #findAll
expect(PatientRepository.findAll).toHaveBeenCalledTimes(2)
})

it('should dispatch the FETCH_PATIENTS_SUCCESS action', async () => {
Expand Down
34 changes: 20 additions & 14 deletions src/patients/list/ViewPatients.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useTranslator from '../../shared/hooks/useTranslator'
import useUpdateEffect from '../../shared/hooks/useUpdateEffect'
import { RootState } from '../../shared/store'
import { searchPatients } from '../patients-slice'
import AddNewPatient from '../view/AddNewPatient'

const breadcrumbs = [{ i18nKey: 'patients.label', location: '/patients' }]

Expand All @@ -22,7 +23,7 @@ const ViewPatients = () => {
useTitle(t('patients.label'))
useAddBreadcrumbs(breadcrumbs, true)
const dispatch = useDispatch()
const { patients, isLoading } = useSelector((state: RootState) => state.patients)
const { patients, isLoading, count } = useSelector((state: RootState) => state.patients)

const setButtonToolBar = useButtonToolbarSetter()

Expand All @@ -48,22 +49,23 @@ const ViewPatients = () => {
}, [dispatch, debouncedSearchText])

useEffect(() => {
setButtonToolBar([
<Button
key="newPatientButton"
outlined
color="success"
icon="patient-add"
onClick={() => history.push('/patients/new')}
>
{t('patients.newPatient')}
</Button>,
])

if (patients && patients.length > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

this patients variable represents the current patients in state.

This could be the default page of patients or a search result. When searching for patients and my search results return 0, I would not expect the new icon to appear.

I think that we should implement a new function called count in Repository that returns the number of documents that are available for a type.

Then here, we use that count function to determine if the new icon should display or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i get it, what i don't get is why do we need to implement count?

it seems like PatientRepository.findAll() returns all the existing patients in the db, we can use it as:

  1. implement a state called count
  2. at initial load, setCount(PatientRepository.findAll().length)
  3. if (count == 0) show addNewPations component, else show the table

but it seems that implementing a count in Repository seems like a better solution here, since it makes Repository more flexible for future issues/enhancements

setButtonToolBar([
<Button
key="newPatientButton"
outlined
color="success"
icon="patient-add"
onClick={() => history.push('/patients/new')}
>
{t('patients.newPatient')}
</Button>,
])
}
return () => {
setButtonToolBar([])
}
}, [dispatch, setButtonToolBar, t, history])
}, [dispatch, setButtonToolBar, t, history, patients])

const loadingIndicator = <Spinner color="blue" loading size={[10, 25]} type="ScaleLoader" />
const table = (
Expand Down Expand Up @@ -91,6 +93,10 @@ const ViewPatients = () => {
setSearchText(event.target.value)
}

if (count === 0) {
return <AddNewPatient />
}

return (
<div>
<Container>
Expand Down
11 changes: 9 additions & 2 deletions src/patients/patients-slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import { AppThunk } from '../shared/store'
interface PatientsState {
isLoading: boolean
patients: Patient[]
count: number
}

const initialState: PatientsState = {
isLoading: false,
patients: [],
count: 0,
}

function startLoading(state: PatientsState) {
Expand All @@ -28,9 +30,13 @@ const patientsSlice = createSlice({
state.isLoading = false
state.patients = payload
},
fetchCountSuccess(state, { payload }: PayloadAction<number>) {
state.count = payload
},
},
})
export const { fetchPatientsStart, fetchPatientsSuccess } = patientsSlice.actions

export const { fetchPatientsStart, fetchPatientsSuccess, fetchCountSuccess } = patientsSlice.actions

export const fetchPatients = (sortRequest: SortRequest = Unsorted): AppThunk => async (
dispatch,
Expand All @@ -53,7 +59,8 @@ export const searchPatients = (
} else {
patients = await PatientRepository.search(searchString)
}

const count = await PatientRepository.count()
dispatch(fetchCountSuccess(count))
dispatch(fetchPatientsSuccess(patients))
}

Expand Down
38 changes: 38 additions & 0 deletions src/patients/view/AddNewPatient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Button, Icon, Typography } from '@hospitalrun/components'
import React from 'react'
import { useHistory } from 'react-router-dom'

import useTranslator from '../../shared/hooks/useTranslator'

const AddNewPatient = () => {
Copy link
Member

Choose a reason for hiding this comment

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

Thoughts on NoPatientsExist for this component name? AddNewPatient could potentially be confusing with NewPatient component.

const history = useHistory()
const { t } = useTranslator()

return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<Icon icon="patients" outline={false} size="6x" />
</div>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<div style={{ textAlign: 'center', width: '60%', margin: 16 }}>
<Typography variant="h5">{t('patients.noPatients')}</Typography>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<Button
key="newPatientButton"
outlined
color="primary"
icon="patient-add"
onClick={() => history.push('/patients/new')}
>
{t('patients.newPatient')}
</Button>
</div>
</div>
</div>
)
}

export default AddNewPatient
5 changes: 5 additions & 0 deletions src/shared/db/Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ export default class Repository<T extends AbstractDBModel> {
// return pagedResult
// }

async count(): Promise<number> {
const result = await this.findAll()
return result.length
}

async search(criteria: any): Promise<T[]> {
const response = await this.db.find(criteria)
const data = await this.db.rel.parseRelDocs(this.type, response.docs)
Expand Down
1 change: 1 addition & 0 deletions src/shared/locales/ar/translations/patients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default {
patients: {
label: 'المرضى',
viewPatients: 'عرض المرضى',
noPatients: 'لا يوجد مرضى حاليا, قم بانشاء اول مريض حالا !',
viewPatient: 'عرض المريض',
editPatient: 'تغيير المريض',
newPatient: 'مريض جديد',
Expand Down
1 change: 1 addition & 0 deletions src/shared/locales/de/translations/patients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default {
patients: {
label: 'Patienten',
viewPatients: 'Patienten anzeigen',
noPatients: 'Es sind noch keine Patienten vorhanden, fügen Sie den Ersten hinzu',
viewPatient: 'Patient anzeigen',
editPatient: 'Patient bearbeiten',
newPatient: 'Neuer Patient',
Expand Down
1 change: 1 addition & 0 deletions src/shared/locales/enUs/translations/patients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default {
label: 'Patients',
patientsList: 'Patients List',
viewPatients: 'View Patients',
noPatients: "There are no patients yet, let's add the first one!",
viewPatient: 'View Patient',
newPatient: 'New Patient',
editPatient: 'Edit Patient',
Expand Down
1 change: 1 addition & 0 deletions src/shared/locales/fr/translations/patients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default {
label: 'Patients',
patientsList: 'Liste des patients',
viewPatients: 'Voir les patients',
noPatients: "Il n'y a aucun patient ici, voilà donc le premier",
viewPatient: 'Voir le patient',
editPatient: 'Modifier le patient',
newPatient: 'Nouveau patient',
Expand Down
1 change: 1 addition & 0 deletions src/shared/locales/ru/translations/patients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default {
patients: {
label: 'Пациенты',
viewPatients: 'Просмотр пациентов',
noPatients: 'Пациентов еще нет, давайте добавим первого!',
viewPatient: 'Просмотр пациента',
editPatient: 'Редактировать пациента',
newPatient: 'Новый пациент',
Expand Down