diff --git a/src/HospitalRun.tsx b/src/HospitalRun.tsx index b79f6a3a01..aa2a4b83ab 100644 --- a/src/HospitalRun.tsx +++ b/src/HospitalRun.tsx @@ -9,6 +9,7 @@ import Permissions from './model/Permissions' import Dashboard from './dashboard/Dashboard' import Patients from './patients/list/Patients' import NewPatient from './patients/new/NewPatient' +import EditPatient from './patients/edit/EditPatient' import ViewPatient from './patients/view/ViewPatient' import { RootState } from './store' import Navbar from './components/Navbar' @@ -42,6 +43,15 @@ const HospitalRun = () => { path="/patients/new" component={NewPatient} /> + { + const patient = { + id: '123', + prefix: 'prefix', + givenName: 'givenName', + familyName: 'familyName', + suffix: 'suffix', + sex: 'male', + type: 'charity', + occupation: 'occupation', + preferredLanguage: 'preferredLanguage', + phoneNumber: 'phoneNumber', + email: 'email@email.com', + address: 'address', + friendlyId: 'P00001', + dateOfBirth: new Date().toISOString(), + isApproximateDateOfBirth: false, + } as Patient + + let wrapper: ReactWrapper + let history = createMemoryHistory() + + beforeEach(() => { + history = createMemoryHistory() + wrapper = mount( + + ) + , + ) + }) + + beforeEach(() => { + jest.restoreAllMocks() + }) + + it('should render the sex select', () => { + const sexSelect = wrapper.findWhere((w: any) => w.prop('name') === 'sex') + expect(sexSelect.prop('value')).toEqual(patient.sex) + expect(sexSelect.prop('label')).toEqual('patient.sex') + expect(sexSelect.prop('isEditable')).toBeFalsy() + }) + + it('should render the patient type select', () => { + const typeSelect = wrapper.findWhere((w: any) => w.prop('name') === 'type') + expect(typeSelect.prop('value')).toEqual(patient.type) + expect(typeSelect.prop('label')).toEqual('patient.type') + expect(typeSelect.prop('isEditable')).toBeFalsy() + }) + + it('should render the date of the birth of the patient', () => { + const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'dateOfBirth') + expect(dateOfBirthInput.prop('value')).toEqual(new Date(patient.dateOfBirth)) + expect(dateOfBirthInput.prop('label')).toEqual('patient.dateOfBirth') + expect(dateOfBirthInput.prop('isEditable')).toBeFalsy() + }) + + it('should render the occupation of the patient', () => { + const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'occupation') + expect(dateOfBirthInput.prop('value')).toEqual(patient.occupation) + expect(dateOfBirthInput.prop('label')).toEqual('patient.occupation') + expect(dateOfBirthInput.prop('isEditable')).toBeFalsy() + }) + + it('should render the preferred language of the patient', () => { + const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'preferredLanguage') + expect(dateOfBirthInput.prop('value')).toEqual(patient.preferredLanguage) + expect(dateOfBirthInput.prop('label')).toEqual('patient.preferredLanguage') + expect(dateOfBirthInput.prop('isEditable')).toBeFalsy() + }) + + it('should render the phone number of the patient', () => { + const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'phoneNumber') + expect(dateOfBirthInput.prop('value')).toEqual(patient.phoneNumber) + expect(dateOfBirthInput.prop('label')).toEqual('patient.phoneNumber') + expect(dateOfBirthInput.prop('isEditable')).toBeFalsy() + }) + + it('should render the email of the patient', () => { + const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'email') + expect(dateOfBirthInput.prop('value')).toEqual(patient.email) + expect(dateOfBirthInput.prop('label')).toEqual('patient.email') + expect(dateOfBirthInput.prop('isEditable')).toBeFalsy() + }) + + it('should render the address of the patient', () => { + const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'address') + expect(dateOfBirthInput.prop('value')).toEqual(patient.address) + expect(dateOfBirthInput.prop('label')).toEqual('patient.address') + expect(dateOfBirthInput.prop('isEditable')).toBeFalsy() + }) + + it('should render the age and date of birth as approximate if patient.isApproximateDateOfBirth is true', async () => { + let wrapper: any + patient.isApproximateDateOfBirth = true + await act(async () => { + wrapper = await mount( + + ) + , + ) + }) + + wrapper.update() + + const ageInput = wrapper.findWhere((w: any) => w.prop('name') === 'approximateAge') + expect(ageInput.prop('value')).toEqual('0') + expect(ageInput.prop('label')).toEqual('patient.approximateAge') + expect(ageInput.prop('isEditable')).toBeFalsy() + }) +}) diff --git a/src/clients/db/Repository.ts b/src/clients/db/Repository.ts index 1be35e5d42..0a113da33b 100644 --- a/src/clients/db/Repository.ts +++ b/src/clients/db/Repository.ts @@ -39,11 +39,11 @@ export default class Repository { } async findAll(): Promise { - const allPatients = await this.db.allDocs({ + const allDocs = await this.db.allDocs({ include_docs: true, }) - return allPatients.rows.map(mapRow) + return allDocs.rows.map(mapRow) } async save(entity: T): Promise { @@ -57,16 +57,15 @@ export default class Repository { return this.save(entity) } - const { id, rev, ...dataToSave } = entity - try { - await this.find(entity.id) + const existingEntity = await this.find(entity.id) + const { id, rev, ...restOfDoc } = existingEntity const entityToUpdate = { _id: id, _rev: rev, - ...dataToSave, + ...restOfDoc, + ...entity, } - await this.db.put(entityToUpdate) return this.find(entity.id) } catch (error) { diff --git a/src/components/input/DatePickerWithLabelFormGroup.tsx b/src/components/input/DatePickerWithLabelFormGroup.tsx index d0b038b43e..be7e41522c 100644 --- a/src/components/input/DatePickerWithLabelFormGroup.tsx +++ b/src/components/input/DatePickerWithLabelFormGroup.tsx @@ -5,7 +5,7 @@ interface Props { name: string label: string value: Date | undefined - isEditable: boolean + isEditable?: boolean onChange?: (date: Date) => void } diff --git a/src/components/input/DateTimePickerWithLabelFormGroup.tsx b/src/components/input/DateTimePickerWithLabelFormGroup.tsx index 72e6cdc241..ff7c649d60 100644 --- a/src/components/input/DateTimePickerWithLabelFormGroup.tsx +++ b/src/components/input/DateTimePickerWithLabelFormGroup.tsx @@ -5,7 +5,7 @@ interface Props { name: string label: string value: Date | undefined - isEditable: boolean + isEditable?: boolean onChange?: (date: Date) => void } diff --git a/src/components/input/SelectWithLableFormGroup.tsx b/src/components/input/SelectWithLableFormGroup.tsx index 619e9dd3be..e7451d1e43 100644 --- a/src/components/input/SelectWithLableFormGroup.tsx +++ b/src/components/input/SelectWithLableFormGroup.tsx @@ -10,7 +10,7 @@ interface Props { value: string label: string name: string - isEditable: boolean + isEditable?: boolean options: Option[] onChange?: (event: React.ChangeEvent) => void } @@ -37,7 +37,6 @@ const SelectWithLabelFormGroup = (props: Props) => { SelectWithLabelFormGroup.defaultProps = { value: '', - isEditable: true, } export default SelectWithLabelFormGroup diff --git a/src/components/input/TextFieldWithLabelFormGroup.tsx b/src/components/input/TextFieldWithLabelFormGroup.tsx index c99390e8ad..25328cdb41 100644 --- a/src/components/input/TextFieldWithLabelFormGroup.tsx +++ b/src/components/input/TextFieldWithLabelFormGroup.tsx @@ -5,7 +5,7 @@ interface Props { value: string label: string name: string - isEditable: boolean + isEditable?: boolean placeholder?: string onChange?: (event: React.ChangeEvent) => void } @@ -21,10 +21,6 @@ const TextFieldWithLabelFormGroup = (props: Props) => { ) } -TextFieldWithLabelFormGroup.defaultProps = { - isEditable: true, -} - TextFieldWithLabelFormGroup.defaultProps = { value: '', } diff --git a/src/components/input/TextInputWithLabelFormGroup.tsx b/src/components/input/TextInputWithLabelFormGroup.tsx index eaf453e942..9946243d82 100644 --- a/src/components/input/TextInputWithLabelFormGroup.tsx +++ b/src/components/input/TextInputWithLabelFormGroup.tsx @@ -5,7 +5,7 @@ interface Props { value: string label: string name: string - isEditable: boolean + isEditable?: boolean type: 'text' | 'email' | 'number' placeholder?: string onChange?: (event: React.ChangeEvent) => void @@ -31,7 +31,6 @@ const TextInputWithLabelFormGroup = (props: Props) => { TextInputWithLabelFormGroup.defaultProps = { value: '', - isEditable: true, type: 'text', } diff --git a/src/locales/en-US/translation.json b/src/locales/en-US/translation.json index 5fc4da63cf..a5939dcd45 100644 --- a/src/locales/en-US/translation.json +++ b/src/locales/en-US/translation.json @@ -7,7 +7,9 @@ "viewPatients": "View Patients", "viewPatient": "View Patient", "newPatient": "New Patient", - "successfullyCreated": "Successfully created patient" + "editPatient": "Edit Patient", + "successfullyCreated": "Successfully created patient", + "successfullyUpdated": "Successfully updated patient" }, "patient": { "suffix": "Suffix", diff --git a/src/patients/new/NewPatientForm.tsx b/src/patients/GeneralInformation.tsx similarity index 60% rename from src/patients/new/NewPatientForm.tsx rename to src/patients/GeneralInformation.tsx index c4ae863e17..cb90c9a13e 100644 --- a/src/patients/new/NewPatientForm.tsx +++ b/src/patients/GeneralInformation.tsx @@ -1,85 +1,40 @@ -import React, { useState } from 'react' +import React from 'react' +import { Panel, Button, Checkbox } from '@hospitalrun/components' + +import { useHistory } from 'react-router' import { useTranslation } from 'react-i18next' -import { Alert, Button, Checkbox } from '@hospitalrun/components' -import { startOfDay, subYears } from 'date-fns' -import SelectWithLabelFormGroup from '../../components/input/SelectWithLableFormGroup' -import TextFieldWithLabelFormGroup from '../../components/input/TextFieldWithLabelFormGroup' -import TextInputWithLabelFormGroup from '../../components/input/TextInputWithLabelFormGroup' -import DatePickerWithLabelFormGroup from '../../components/input/DatePickerWithLabelFormGroup' -import Patient from '../../model/Patient' -import { getPatientName } from '../util/patient-name-util' +import { startOfDay, subYears, differenceInYears } from 'date-fns' + +import Patient from '../model/Patient' +import TextFieldWithLabelFormGroup from '../components/input/TextFieldWithLabelFormGroup' +import TextInputWithLabelFormGroup from '../components/input/TextInputWithLabelFormGroup' +import SelectWithLabelFormGroup from '../components/input/SelectWithLableFormGroup' +import DatePickerWithLabelFormGroup from '../components/input/DatePickerWithLabelFormGroup' interface Props { - onCancel: () => void - onSave: (patient: Patient) => void + patient: Patient + isEditable?: boolean + onCancel?: () => void + onSave?: () => void + onFieldChange?: (key: string, value: string | boolean) => void } -const NewPatientForm = (props: Props) => { +const GeneralInformation = (props: Props) => { const { t } = useTranslation() - const [isEditable] = useState(true) - const { onCancel, onSave } = props - const [approximateAge, setApproximateAge] = useState(0) - const [errorMessage, setErrorMessage] = useState('') - const [patient, setPatient] = useState({ - givenName: '', - familyName: '', - suffix: '', - prefix: '', - dateOfBirth: '', - isApproximateDateOfBirth: false, - sex: '', - phoneNumber: '', - email: '', - address: '', - preferredLanguage: '', - occupation: '', - type: '', - fullName: '', - }) - - const onSaveButtonClick = async () => { - if (!patient.givenName) { - setErrorMessage(t('patient.errors.patientGivenNameRequired')) - } else { - const newPatient = { - prefix: patient.prefix, - familyName: patient.familyName, - givenName: patient.givenName, - suffix: patient.suffix, - sex: patient.sex, - dateOfBirth: patient.dateOfBirth, - isApproximateDateOfBirth: patient.isApproximateDateOfBirth, - type: patient.type, - occupation: patient.occupation, - preferredLanguage: patient.preferredLanguage, - phoneNumber: patient.phoneNumber, - email: patient.email, - address: patient.address, - fullName: getPatientName(patient.givenName, patient.familyName, patient.suffix), - } as Patient - - onSave(newPatient) - } - } + const { patient, isEditable, onCancel, onSave, onFieldChange } = props + const history = useHistory() - const onFieldChange = (key: string, value: string) => { - setPatient({ - ...patient, - [key]: value, - }) - } + const onSelectChange = (event: React.ChangeEvent, fieldName: string) => + onFieldChange && onFieldChange(fieldName, event.target.value) - const onSelectChange = (event: React.ChangeEvent, fieldName: string) => { - onFieldChange(fieldName, event.target.value) - } + const onDateOfBirthChange = (date: Date) => + onFieldChange && onFieldChange('dateOfBirth', date.toISOString()) - const onDateOfBirthChange = (date: Date) => { - onFieldChange('dateOfBirth', date.toISOString()) - } + const onInputElementChange = (event: React.ChangeEvent, fieldName: string) => + onFieldChange && onFieldChange(fieldName, event.target.value) - const onInputElementChange = (event: React.ChangeEvent, fieldName: string) => { - onFieldChange(fieldName, event.target.value) - } + const onCheckboxChange = (event: React.ChangeEvent, fieldName: string) => + onFieldChange && onFieldChange(fieldName, event.target.checked) const onApproximateAgeChange = (event: React.ChangeEvent) => { let approximateAgeNumber @@ -89,16 +44,15 @@ const NewPatientForm = (props: Props) => { approximateAgeNumber = parseFloat(event.target.value) } - setApproximateAge(approximateAgeNumber) const approximateDateOfBirth = subYears(new Date(), approximateAgeNumber) - setPatient({ ...patient, dateOfBirth: startOfDay(approximateDateOfBirth).toISOString() }) + if (onFieldChange) { + onFieldChange('dateOfBirth', startOfDay(approximateDateOfBirth).toISOString()) + } } return (
-
-

{t('patient.basicInformation')}

- {errorMessage && } +
{
- 0 ? new Date(patient.dateOfBirth) : undefined} - onChange={(date: Date) => { - onDateOfBirthChange(date) - }} - /> + {patient.isApproximateDateOfBirth ? ( + + ) : ( + 0 + ? new Date(patient.dateOfBirth) + : undefined + } + onChange={(date: Date) => { + onDateOfBirthChange(date) + }} + /> + )}
{ - setPatient({ ...patient, isApproximateDateOfBirth: event.target.checked }) - }} + disabled={!isEditable} + onChange={(event) => onCheckboxChange(event, 'isApproximateDateOfBirth')} />
- {patient.isApproximateDateOfBirth && ( -
- -
- )}
@@ -239,8 +195,9 @@ const NewPatientForm = (props: Props) => { />
- -

{t('patient.contactInformation')}

+ +
+
{ name="address" value={patient.address} isEditable={isEditable} - onChange={(event: React.ChangeEvent) => { - onFieldChange('address', event.currentTarget.value) - }} + onChange={(event: React.ChangeEvent) => + onFieldChange && onFieldChange('address', event.currentTarget.value)} />
- {isEditable && ( -
-
- - -
-
- )} - +
+ {isEditable ? ( +
+ + +
+ ) : ( +
+ +
+ )}
) } -export default NewPatientForm +export default GeneralInformation diff --git a/src/patients/edit/EditPatient.tsx b/src/patients/edit/EditPatient.tsx new file mode 100644 index 0000000000..0678cbdd44 --- /dev/null +++ b/src/patients/edit/EditPatient.tsx @@ -0,0 +1,86 @@ +import React, { useEffect, useState } from 'react' +import { useHistory, useParams } from 'react-router' +import { useTranslation } from 'react-i18next' +import { useDispatch, useSelector } from 'react-redux' +import { Spinner } from '@hospitalrun/components' + +import GeneralInformation from '../GeneralInformation' +import useTitle from '../../page-header/useTitle' +import Patient from '../../model/Patient' +import { updatePatient, fetchPatient } from '../patient-slice' +import { RootState } from '../../store' +import { getPatientFullName, getPatientName } from '../util/patient-name-util' + +const getFriendlyId = (p: Patient): string => { + if (p) { + return p.friendlyId + } + + return '' +} + +const EditPatient = () => { + const { t } = useTranslation() + const history = useHistory() + const dispatch = useDispatch() + + const [patient, setPatient] = useState({} as Patient) + const { patient: reduxPatient } = useSelector((state: RootState) => state.patient) + + useTitle( + `${t('patients.editPatient')}: ${getPatientFullName(reduxPatient)} (${getFriendlyId( + reduxPatient, + )})`, + ) + + useEffect(() => { + setPatient(reduxPatient) + }, [reduxPatient]) + + const { id } = useParams() + useEffect(() => { + if (id) { + dispatch(fetchPatient(id)) + } + }, [id, dispatch]) + + const onCancel = () => { + history.goBack() + } + + const onSave = () => { + dispatch( + updatePatient( + { + ...patient, + fullName: getPatientName(patient.givenName, patient.familyName, patient.suffix), + }, + history, + ), + ) + } + + const onFieldChange = (key: string, value: string | boolean) => { + setPatient({ + ...patient, + [key]: value, + }) + } + + // see comment in ViewPatient + if (!reduxPatient) { + return + } + + return ( + + ) +} + +export default EditPatient diff --git a/src/patients/new/NewPatient.tsx b/src/patients/new/NewPatient.tsx index 836f17d597..68beb31ad8 100644 --- a/src/patients/new/NewPatient.tsx +++ b/src/patients/new/NewPatient.tsx @@ -1,27 +1,55 @@ -import React from 'react' +import React, { useState } from 'react' import { useHistory } from 'react-router' import { useTranslation } from 'react-i18next' import { useDispatch } from 'react-redux' -import NewPatientForm from './NewPatientForm' + +import GeneralInformation from '../GeneralInformation' import useTitle from '../../page-header/useTitle' import Patient from '../../model/Patient' -import { createPatient } from '../patients-slice' +import { createPatient } from '../patient-slice' +import { getPatientName } from '../util/patient-name-util' const NewPatient = () => { const { t } = useTranslation() const history = useHistory() const dispatch = useDispatch() + + const [patient, setPatient] = useState({} as Patient) + useTitle(t('patients.newPatient')) const onCancel = () => { - history.push('/patients') + history.goBack() + } + + const onSave = () => { + dispatch( + createPatient( + { + ...patient, + fullName: getPatientName(patient.givenName, patient.familyName, patient.suffix), + }, + history, + ), + ) } - const onSave = (patient: Patient) => { - dispatch(createPatient(patient, history)) + const onFieldChange = (key: string, value: string | boolean) => { + setPatient({ + ...patient, + [key]: value, + }) } - return + return ( + + ) } export default NewPatient diff --git a/src/patients/patient-slice.ts b/src/patients/patient-slice.ts index 03ea2bf49e..15f93f0c10 100644 --- a/src/patients/patient-slice.ts +++ b/src/patients/patient-slice.ts @@ -1,7 +1,9 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import { Toast } from '@hospitalrun/components' import Patient from '../model/Patient' import PatientRepository from '../clients/db/PatientRepository' import { AppThunk } from '../store' +import il8n from '../i18n' interface PatientState { isLoading: boolean @@ -26,11 +28,15 @@ const patientSlice = createSlice({ initialState, reducers: { getPatientStart: startLoading, + createPatientStart: startLoading, updatePatientStart: startLoading, getPatientSuccess(state, { payload }: PayloadAction) { state.isLoading = false state.patient = payload }, + createPatientSuccess(state) { + state.isLoading = false + }, updatePatientSuccess(state, { payload }: PayloadAction) { state.isLoading = false state.patient = payload @@ -41,6 +47,8 @@ const patientSlice = createSlice({ export const { getPatientStart, getPatientSuccess, + createPatientStart, + createPatientSuccess, updatePatientStart, updatePatientSuccess, } = patientSlice.actions @@ -51,10 +59,32 @@ export const fetchPatient = (id: string): AppThunk => async (dispatch) => { dispatch(getPatientSuccess(patient)) } -export const updatePatient = (patient: Patient): AppThunk => async (dispatch) => { +export const createPatient = (patient: Patient, history: any): AppThunk => async (dispatch) => { + dispatch(createPatientStart()) + const newPatient = await PatientRepository.save(patient) + dispatch(createPatientSuccess()) + history.push(`/patients/${newPatient.id}`) + Toast( + 'success', + il8n.t('Success!'), + `${il8n.t('patients.successfullyCreated')} ${patient.givenName} ${patient.familyName} ${ + patient.suffix + }`, + ) +} + +export const updatePatient = (patient: Patient, history: any): AppThunk => async (dispatch) => { dispatch(updatePatientStart()) const updatedPatient = await PatientRepository.saveOrUpdate(patient) dispatch(updatePatientSuccess(updatedPatient)) + history.push(`/patients/${updatedPatient.id}`) + Toast( + 'success', + il8n.t('Success!'), + `${il8n.t('patients.successfullyUpdated')} ${patient.givenName} ${patient.familyName} ${ + patient.suffix + }`, + ) } export default patientSlice.reducer diff --git a/src/patients/patients-slice.ts b/src/patients/patients-slice.ts index e2007e5cb4..e35e157b96 100644 --- a/src/patients/patients-slice.ts +++ b/src/patients/patients-slice.ts @@ -1,9 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import { Toast } from '@hospitalrun/components' import Patient from '../model/Patient' import PatientRepository from '../clients/db/PatientRepository' import { AppThunk } from '../store' -import il8n from '../i18n' interface PatientsState { isLoading: boolean @@ -24,36 +22,13 @@ const patientsSlice = createSlice({ initialState, reducers: { getPatientsStart: startLoading, - createPatientStart: startLoading, getAllPatientsSuccess(state, { payload }: PayloadAction) { state.isLoading = false state.patients = payload }, - createPatientSuccess(state) { - state.isLoading = false - }, }, }) -export const { - getPatientsStart, - getAllPatientsSuccess, - createPatientStart, - createPatientSuccess, -} = patientsSlice.actions - -export const createPatient = (patient: Patient, history: any): AppThunk => async (dispatch) => { - dispatch(createPatientStart()) - const newPatient = await PatientRepository.save(patient) - dispatch(createPatientSuccess()) - history.push(`/patients/${newPatient.id}`) - Toast( - 'success', - il8n.t('Success!'), - `${il8n.t('patients.successfullyCreated')} ${patient.givenName} ${patient.familyName} ${ - patient.suffix - }`, - ) -} +export const { getPatientsStart, getAllPatientsSuccess } = patientsSlice.actions export const fetchPatients = (): AppThunk => async (dispatch) => { dispatch(getPatientsStart()) diff --git a/src/patients/related-persons/NewRelatedPersonModal.tsx b/src/patients/related-persons/NewRelatedPersonModal.tsx index 91c0b6e466..ee23cc8e41 100644 --- a/src/patients/related-persons/NewRelatedPersonModal.tsx +++ b/src/patients/related-persons/NewRelatedPersonModal.tsx @@ -63,6 +63,7 @@ const NewRelatedPersonModal = (props: Props) => { name="type" label={t('patient.relatedPersons.relationshipType')} value={relatedPerson.type} + isEditable onChange={(event: React.ChangeEvent) => { onInputElementChange(event, 'type') }} diff --git a/src/patients/related-persons/RelatedPersonTab.tsx b/src/patients/related-persons/RelatedPersonTab.tsx index 2069429d0a..ed4b8f839a 100644 --- a/src/patients/related-persons/RelatedPersonTab.tsx +++ b/src/patients/related-persons/RelatedPersonTab.tsx @@ -9,6 +9,7 @@ import { useDispatch, useSelector } from 'react-redux' import { RootState } from 'store' import Permissions from 'model/Permissions' import PatientRepository from 'clients/db/PatientRepository' +import { useHistory } from 'react-router' interface Props { patient: Patient @@ -16,6 +17,7 @@ interface Props { const RelatedPersonTab = (props: Props) => { const dispatch = useDispatch() + const history = useHistory() const { patient } = props const { t } = useTranslation() const { permissions } = useSelector((state: RootState) => state.user) @@ -49,20 +51,16 @@ const RelatedPersonTab = (props: Props) => { } const onRelatedPersonSave = (relatedPerson: RelatedPerson) => { - const newRelatedPersons: RelatedPerson[] = [] - - if (patient.relatedPersons) { - newRelatedPersons.push(...patient.relatedPersons) - } - - newRelatedPersons.push(relatedPerson) - const patientToUpdate = { ...patient, - relatedPersons: newRelatedPersons, } - dispatch(updatePatient(patientToUpdate)) + if (!patientToUpdate.relatedPersons) { + patientToUpdate.relatedPersons = [] + } + + patientToUpdate.relatedPersons.push(relatedPerson) + dispatch(updatePatient(patientToUpdate, history)) closeNewRelatedPersonModal() } diff --git a/src/patients/view/GeneralInformation.tsx b/src/patients/view/GeneralInformation.tsx deleted file mode 100644 index 82240f3e99..0000000000 --- a/src/patients/view/GeneralInformation.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import React from 'react' -import { Panel } from '@hospitalrun/components' -import { differenceInYears } from 'date-fns' -import Patient from 'model/Patient' -import { useTranslation } from 'react-i18next' -import TextFieldWithLabelFormGroup from '../../components/input/TextFieldWithLabelFormGroup' -import TextInputWithLabelFormGroup from '../../components/input/TextInputWithLabelFormGroup' -import SelectWithLabelFormGroup from '../../components/input/SelectWithLableFormGroup' -import DatePickerWithLabelFormGroup from '../../components/input/DatePickerWithLabelFormGroup' - -interface Props { - patient: Patient -} - -const getPatientAge = (dateOfBirth: string | undefined): string => { - if (!dateOfBirth) { - return '' - } - - const dob = new Date(dateOfBirth) - return differenceInYears(new Date(), dob).toString() -} - -const getPatientDateOfBirth = (dateOfBirth: string | undefined): Date | undefined => { - if (!dateOfBirth) { - return undefined - } - - return new Date(dateOfBirth) -} - -const GeneralInformation = (props: Props) => { - const { t } = useTranslation() - const { patient } = props - return ( -
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
-
-
- -
-
-
-
- ) -} - -export default GeneralInformation diff --git a/src/patients/view/ViewPatient.tsx b/src/patients/view/ViewPatient.tsx index 6fec74aacd..57577e0d63 100644 --- a/src/patients/view/ViewPatient.tsx +++ b/src/patients/view/ViewPatient.tsx @@ -3,12 +3,13 @@ import { useDispatch, useSelector } from 'react-redux' import { useParams, withRouter, Route, useHistory, useLocation } from 'react-router-dom' import { Panel, Spinner, TabsHeader, Tab } from '@hospitalrun/components' import { useTranslation } from 'react-i18next' + import useTitle from '../../page-header/useTitle' import { fetchPatient } from '../patient-slice' import { RootState } from '../../store' import { getPatientFullName } from '../util/patient-name-util' import Patient from '../../model/Patient' -import GeneralInformation from './GeneralInformation' +import GeneralInformation from '../GeneralInformation' import RelatedPerson from '../related-persons/RelatedPersonTab' const getFriendlyId = (p: Patient): string => { @@ -20,11 +21,13 @@ const getFriendlyId = (p: Patient): string => { } const ViewPatient = () => { - const history = useHistory() - const location = useLocation() const { t } = useTranslation() + const history = useHistory() const dispatch = useDispatch() + const location = useLocation() + const { patient } = useSelector((state: RootState) => state.patient) + useTitle(`${getPatientFullName(patient)} (${getFriendlyId(patient)})`) const { id } = useParams() @@ -34,6 +37,8 @@ const ViewPatient = () => { } }, [dispatch, id]) + // this check doesn't work as an empty object isn't falsy. would it be more correct to display + // the spinner when the Redux patient state isLoading is true? if (!patient) { return }