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

Commit

Permalink
feat(careplan): adds ability to add a new care plan
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmeyer committed Jun 4, 2020
1 parent 3c6ffc6 commit 0aa0cf9
Show file tree
Hide file tree
Showing 10 changed files with 375 additions and 3 deletions.
25 changes: 22 additions & 3 deletions src/components/input/SelectWithLableFormGroup.tsx
Expand Up @@ -10,18 +10,37 @@ interface Props {
value: string
label: string
name: string
isRequired?: boolean
isEditable?: boolean
options: Option[]
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void
feedback?: string
isInvalid?: boolean
}

const SelectWithLabelFormGroup = (props: Props) => {
const { value, label, name, isEditable, options, onChange } = props
const {
value,
label,
name,
isEditable,
options,
onChange,
isRequired,
feedback,
isInvalid,
} = props
const id = `${name}Select`
return (
<div className="form-group">
<Label text={label} htmlFor={id} />
<Select disabled={!isEditable} onChange={onChange} value={value}>
<Label text={label} htmlFor={id} isRequired={isRequired} />
<Select
disabled={!isEditable}
onChange={onChange}
value={value}
feedback={feedback}
isInvalid={isInvalid}
>
<option disabled value="">
-- Choose --
</option>
Expand Down
12 changes: 12 additions & 0 deletions src/locales/enUs/translations/patient/index.ts
Expand Up @@ -93,6 +93,18 @@ export default {
},
noLabsMessage: 'No labs requests for this person.',
},
carePlan: {
new: 'Add Care Plan',
label: 'Care Plans',
title: 'Title',
description: 'Description',
status: 'Status',
condition: 'Condition',
intent: 'Intent',
startDate: 'Start Date',
endDate: 'End Date',
note: 'Note',
},
types: {
charity: 'Charity',
private: 'Private',
Expand Down
28 changes: 28 additions & 0 deletions src/model/CarePlan.ts
@@ -0,0 +1,28 @@
export enum CarePlanStatus {
Draft = 'draft',
Active = 'active',
OnHold = 'on hold',
Revoked = 'revoked',
Completed = 'completed',
Unknown = 'unknown',
}

export enum CarePlanIntent {
Proposal = 'proposal',
Plan = 'plan',
Order = 'order',
Option = 'option',
}

export default interface CarePlan {
id: string
status: CarePlanStatus
intent: CarePlanIntent
title: string
description: string
startDate: string
endDate: string
createdOn: string
diagnosisId: string
note: string
}
2 changes: 2 additions & 0 deletions src/model/Patient.ts
@@ -1,5 +1,6 @@
import AbstractDBModel from './AbstractDBModel'
import Allergy from './Allergy'
import CarePlan from './CarePlan'
import ContactInformation from './ContactInformation'
import Diagnosis from './Diagnosis'
import Name from './Name'
Expand All @@ -18,4 +19,5 @@ export default interface Patient extends AbstractDBModel, Name, ContactInformati
allergies?: Allergy[]
diagnoses?: Diagnosis[]
notes?: Note[]
carePlans: CarePlan[]
}
2 changes: 2 additions & 0 deletions src/model/Permissions.ts
Expand Up @@ -14,6 +14,8 @@ enum Permissions {
ViewIncidents = 'read:incidents',
ViewIncident = 'read:incident',
ReportIncident = 'write:incident',
AddCarePlan = 'write:care_plan',
ReadCarePlan = 'read:care_plan',
}

export default Permissions
197 changes: 197 additions & 0 deletions src/patients/care-plans/AddCarePlanModal.tsx
@@ -0,0 +1,197 @@
import { Modal, Column, Row } from '@hospitalrun/components'
import { addMonths } from 'date-fns'
import React, { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'

import DatePickerWithLabelFormGroup from '../../components/input/DatePickerWithLabelFormGroup'
import SelectWithLabelFormGroup from '../../components/input/SelectWithLableFormGroup'
import TextFieldWithLabelFormGroup from '../../components/input/TextFieldWithLabelFormGroup'
import TextInputWithLabelFormGroup from '../../components/input/TextInputWithLabelFormGroup'
import CarePlan, { CarePlanIntent, CarePlanStatus } from '../../model/CarePlan'
import { RootState } from '../../store'
import { addCarePlan } from '../patient-slice'

interface Props {
show: boolean
onCloseButtonClick: () => void
}

const initialCarePlanState = {
title: '',
description: '',
startDate: new Date().toISOString(),
endDate: addMonths(new Date(), 1).toISOString(),
note: '',
intent: '',
status: '',
diagnosisId: '',
}

const AddCarePlanModal = (props: Props) => {
const { show, onCloseButtonClick } = props
const dispatch = useDispatch()
const { t } = useTranslation()
const { carePlanError, patient } = useSelector((state: RootState) => state.patient)
const [carePlan, setCarePlan] = useState(initialCarePlanState)

useEffect(() => {
setCarePlan(initialCarePlanState)
}, [show])

const onFieldChange = (name: string, value: string) => {
setCarePlan((previousCarePlan) => ({
...previousCarePlan,
[name]: value,
}))
}

const onSaveButtonClick = () => {
dispatch(addCarePlan(patient.id, carePlan as CarePlan))
}

const onClose = () => {
onCloseButtonClick()
}

const body = (
<>
<form>
<Row>
<Column sm={12}>
<TextInputWithLabelFormGroup
isRequired
value={carePlan.title}
label={t('patient.carePlan.title')}
name="title"
feedback={carePlanError?.title}
isInvalid={!!carePlanError?.title}
isEditable
onChange={(event) => onFieldChange('title', event.currentTarget.value)}
/>
</Column>
</Row>
<Row>
<Column sm={12}>
<TextFieldWithLabelFormGroup
isRequired
value={carePlan.description}
label={t('patient.carePlan.description')}
name="title"
feedback={carePlanError?.description}
isInvalid={!!carePlanError?.description}
isEditable
onChange={(event) => onFieldChange('description', event.currentTarget.value)}
/>
</Column>
</Row>
<Row>
<Column sm={12}>
<SelectWithLabelFormGroup
isRequired
value={carePlan.diagnosisId}
label={t('patient.carePlan.condition')}
name="title"
feedback={carePlanError?.condition}
isInvalid={!!carePlanError?.condition}
isEditable
onChange={(event) => onFieldChange('diagnosisId', event.currentTarget.value)}
options={patient.diagnoses?.map((d) => ({ label: d.name, value: d.id })) || []}
/>
</Column>
</Row>
<Row>
<Column sm={6}>
<SelectWithLabelFormGroup
isRequired
value={carePlan.status}
label={t('patient.carePlangi.condition')}
name="status"
feedback={carePlanError?.status}
isInvalid={!!carePlanError?.status}
isEditable
options={Object.values(CarePlanStatus).map((v) => ({ label: v, value: v }))}
onChange={(event) => onFieldChange('status', event.currentTarget.value)}
/>
</Column>
<Column sm={6}>
<SelectWithLabelFormGroup
isRequired
value={carePlan.intent}
label={t('patient.carePlan.intent')}
name="intent"
feedback={carePlanError?.intent}
isInvalid={!!carePlanError?.intent}
isEditable
options={Object.values(CarePlanIntent).map((v) => ({ label: v, value: v }))}
onChange={(event) => onFieldChange('intent', event.currentTarget.value)}
/>
</Column>
</Row>
<Row>
<Column sm={6}>
<DatePickerWithLabelFormGroup
isRequired
value={carePlan.startDate ? new Date(carePlan.startDate) : new Date()}
label={t('patient.carePlan.startDate')}
name="startDate"
feedback={carePlanError?.startDate}
isInvalid={!!carePlanError?.startDate}
isEditable
onChange={(date) => onFieldChange('startDate', date.toISOString())}
/>
</Column>
<Column sm={6}>
<DatePickerWithLabelFormGroup
isRequired
value={carePlan.endDate ? new Date(carePlan.endDate) : new Date()}
label={t('patient.carePlan.endDate')}
name="endDate"
feedback={carePlanError?.endDate}
isInvalid={!!carePlanError?.endDate}
isEditable
onChange={(date) => onFieldChange('endDate', date.toISOString())}
/>
</Column>
</Row>
<Row>
<Column sm={12}>
<TextFieldWithLabelFormGroup
isRequired
value={carePlan.note}
label={t('patient.carePlan.note')}
name="note"
feedback={carePlanError?.note}
isInvalid={!!carePlanError?.note}
isEditable
onChange={(event) => onFieldChange('note', event.currentTarget.value)}
/>
</Column>
</Row>
</form>
</>
)

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

export default AddCarePlanModal
70 changes: 70 additions & 0 deletions src/patients/care-plans/CarePlanTab.tsx
@@ -0,0 +1,70 @@
import { Button } from '@hospitalrun/components'
import format from 'date-fns/format'
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'

import Permissions from '../../model/Permissions'
import { RootState } from '../../store'
import AddCarePlanModal from './AddCarePlanModal'

interface Props {
patientId: string
}

export const CarePlanTab = (props: Props) => {
const { t } = useTranslation()

const { permissions } = useSelector((state: RootState) => state.user)
const { patient } = useSelector((state: RootState) => state.patient)
const [showAddCarePlanModal, setShowAddCarePlanModal] = useState(false)
const { patientId } = props
console.log(patientId)
console.log(patient.carePlans)
return (
<>
<div className="row">
<div className="col-md-12 d-flex justify-content-end">
{permissions.includes(Permissions.AddCarePlan) && (
<Button
outlined
color="success"
icon="add"
iconLocation="left"
onClick={() => setShowAddCarePlanModal(true)}
>
{t('patient.carePlan.new')}
</Button>
)}
</div>
</div>
<br />
<table className="table table-hover">
<thead className="thead-light ">
<tr>
<th>{t('patient.carePlan.title')}</th>
<th>{t('patient.carePlan.startDate')}</th>
<th>{t('patient.carePlan.endDate')}</th>
<th>{t('patient.carePlan.status')}</th>
</tr>
</thead>
<tbody>
{patient.carePlans?.map((carePlan) => (
<tr key={carePlan.id}>
<td>{carePlan.title}</td>
<td>{format(new Date(carePlan.startDate), 'yyyy-MM-dd')}</td>
<td>{format(new Date(carePlan.endDate), 'yyyy-MM-dd')}</td>
<td>{carePlan.status}</td>
</tr>
))}
</tbody>
</table>
<AddCarePlanModal
show={showAddCarePlanModal}
onCloseButtonClick={() => setShowAddCarePlanModal(false)}
/>
</>
)
}

export default CarePlanTab

0 comments on commit 0aa0cf9

Please sign in to comment.