Skip to content

Commit

Permalink
Merge pull request HospitalRun#16 from zemoso-int/FE_APPOINTMENT
Browse files Browse the repository at this point in the history
Fe appointment
  • Loading branch information
vasanthk97 authored Sep 30, 2022
2 parents a43e6df + efb9940 commit c11a06e
Show file tree
Hide file tree
Showing 17 changed files with 650 additions and 236 deletions.
15 changes: 11 additions & 4 deletions src/patients/appointments/AppointmentsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,22 @@ const AppointmentsList = ({ patient }: Props) => {
label: t('scheduling.appointment.startDate'),
key: 'startDateTime',
formatter: (row) =>
row.startDateTime
? format(new Date(row.startDateTime), 'yyyy-MM-dd, hh:mm a')
: '',
row.start ? format(new Date(row.start), 'yyyy-MM-dd, hh:mm a') : '',
},
{
label: t('scheduling.appointment.endDate'),
key: 'endDateTime',
formatter: (row) =>
row.endDateTime ? format(new Date(row.endDateTime), 'yyyy-MM-dd, hh:mm a') : '',
row.start
? format(
new Date(
new Date(row.start).setMinutes(
new Date(row.start).getMinutes() + row.minutesDuration,
),
),
'yyyy-MM-dd, hh:mm a',
)
: '',
},
{ label: t('scheduling.appointment.location'), key: 'location' },
{ label: t('scheduling.appointment.type'), key: 'type' },
Expand Down
14 changes: 8 additions & 6 deletions src/patients/history/mappers/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,22 @@ export const convertLab = (lab: Lab): PatientHistoryRecord[] => {

export const convertAppointment = (appt: Appointment): PatientHistoryRecord[] => {
const apptEvents = []
if (appt.startDateTime) {
if (appt.start) {
apptEvents.push({
date: new Date(appt.startDateTime),
date: new Date(appt.start),
type: HistoryRecordType.APPOINTMENT,
info: `Started - ${appt.type}`,
info: `Started - ${appt.appointmentType.text}`,
recordId: appt.id,
id: `startedAppt${appt.id}`,
})
}
if (appt.endDateTime) {
if (new Date(appt.start).setMinutes(new Date(appt.start).getMinutes() + appt.minutesDuration)) {
apptEvents.push({
date: new Date(appt.endDateTime),
date: new Date(
new Date(appt.start).setMinutes(new Date(appt.start).getMinutes() + appt.minutesDuration),
),
type: HistoryRecordType.APPOINTMENT,
info: `Ended - ${appt.type}`,
info: `Ended - ${appt.appointmentType.text}`,
recordId: appt.id,
id: `endedAppt${appt.id}`,
})
Expand Down
2 changes: 1 addition & 1 deletion src/patients/search/ViewPatients.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button } from '@hospitalrun/components'
import React, { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { useHistory } from 'react-router'
import { useHistory } from 'react-router-dom'

import useAddBreadcrumbs from '../../page-header/breadcrumbs/useAddBreadcrumbs'
import { useButtonToolbarSetter } from '../../page-header/button-toolbar/ButtonBarProvider'
Expand Down
30 changes: 26 additions & 4 deletions src/patients/visits/FilterPatientModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import React, { useState } from 'react'
import { Label, Modal, Select } from '@hospitalrun/components'
import useTranslator from '../../shared/hooks/useTranslator'
import { Button } from 'react-bootstrap'
import { appointmentTypes } from '../../scheduling/appointments/constants/Appointment'
import {
appointmentStatus,
appointmentTypes,
} from '../../scheduling/appointments/constants/Appointment'
// import { getAllPatients } from '../../scheduling/appointments/service/Patients'

interface Props {
show: boolean
Expand All @@ -11,13 +15,21 @@ interface Props {
}

const FilterPatientModal = ({ show, onCloseButtonClick, onFieldChange }: Props) => {
// const func = () => {
// console.log('ALL PATIENTS DATA', getAllPatients())
// }

// useEffect(() => {
// func()
// }, [])

const { t } = useTranslator()

const [patientId, setpatientId] = useState('')
const [patientStatus, setPatientStatus] = useState('')
const [appointmentType, setappointmentType] = useState('')

const clearValues = () => {
setpatientId('')
setPatientStatus('')
setappointmentType('')
}

Expand All @@ -28,13 +40,23 @@ const FilterPatientModal = ({ show, onCloseButtonClick, onFieldChange }: Props)
<Label text={t('scheduling.appointment.type')} title="type" />
<Select
id="type"
defaultSelected={appointmentTypes.filter(({ value }) => value === appointmentType)}
options={appointmentTypes}
onChange={(values) => setappointmentType(values[0])}
/>
</div>
<div className="form-group">
<Label text="Status" title="Status" />
<Select
defaultSelected={appointmentStatus.filter(({ value }) => value == patientStatus)}
id="status"
options={appointmentStatus}
onChange={(values) => setPatientStatus(values[0])}
/>
</div>
<Button
onClick={() => {
onFieldChange && onFieldChange(patientId, appointmentType)
onFieldChange && onFieldChange(patientStatus, appointmentType)
clearValues()
onCloseButtonClick()
}}
Expand Down
167 changes: 103 additions & 64 deletions src/scheduling/appointments/AppointmentDetailForm.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,67 @@
import { Select, Typeahead, Label, Alert } from '@hospitalrun/components'
import React from 'react'

import { Select, Label, Alert } from '@hospitalrun/components'
import { addMinutes, roundToNearestMinutes } from 'date-fns'
import moment from 'moment'
import React, { useEffect, useState } from 'react'
import { AsyncTypeahead } from 'react-bootstrap-typeahead'
import DateTimePickerWithLabelFormGroup from '../../shared/components/input/DateTimePickerWithLabelFormGroup'
import { SelectOption } from '../../shared/components/input/SelectOption'
import TextFieldWithLabelFormGroup from '../../shared/components/input/TextFieldWithLabelFormGroup'
import TextInputWithLabelFormGroup from '../../shared/components/input/TextInputWithLabelFormGroup'
import PatientRepository from '../../shared/db/PatientRepository'
import useTranslator from '../../shared/hooks/useTranslator'
import Appointment from '../../shared/model/Appointment'
import Patient from '../../shared/model/Patient'
import { appointmentTypes, appointmentStatus } from '../appointments/constants/Appointment'
import { getAllPatients } from './service/Patients'

interface Props {
appointment: Appointment
patient?: Patient
isEditable: boolean
error?: any
onFieldChange?: (key: string, value: string | boolean) => void
onFieldChange?: (key: string, value: string | boolean | Date | number) => void
setAppointment?: (appointment: Appointment) => void
}

const AppointmentDetailForm = (props: Props) => {
const { onFieldChange, appointment, patient, isEditable, error } = props
const { appointment, patient, isEditable, error, setAppointment } = props
const { t } = useTranslator()
const [patientDetails, setPatientDetails] = useState<any>()
const [options, setOptions] = useState<any[]>([])
const [isLoading, setIsLoading] = useState<boolean>(false)

const startDateTime = roundToNearestMinutes(new Date(), { nearestTo: 15 })
const endDateTime = addMinutes(startDateTime, 60)

if (!appointment.start) {
appointment.start = String(new Date(Date.now()))
}

if (!appointment.end) {
appointment.end = String(endDateTime)
}

if (!appointment.minutesDuration) {
appointment.minutesDuration = Math.round(
Math.floor(
(new Date(appointment.end).getTime() - new Date(appointment.start).getTime()) / 60000 / 5,
) * 5,
)
}

const onDateChange = (date: Date, fieldName: string) =>
onFieldChange && onFieldChange(fieldName, date.toISOString())
// const selectedValues: any[] = []

const onInputElementChange = (event: React.ChangeEvent<HTMLInputElement>, fieldName: string) =>
onFieldChange && onFieldChange(fieldName, event.target.value)
// const patientName: string = String(patient)
// console.log(patientName)
// if (patientName) {
// selectedValues.push(patientName)
// console.log('selected values', selectedValues)
// }

const typeOptions: SelectOption[] = [
{ label: t('scheduling.appointment.types.checkup'), value: 'checkup' },
{ label: t('scheduling.appointment.types.emergency'), value: 'emergency' },
{ label: t('scheduling.appointment.types.followUp'), value: 'follow up' },
{ label: t('scheduling.appointment.types.routine'), value: 'routine' },
{ label: t('scheduling.appointment.types.walkIn'), value: 'walk in' },
]
useEffect(() => {
console.log('appointment details', appointment)
if (!patientDetails) {
;(async () => {
setPatientDetails(await getAllPatients())
})()
}
}, [])

return (
<>
Expand All @@ -47,19 +74,32 @@ const AppointmentDetailForm = (props: Props) => {
isRequired
text={t('scheduling.appointment.patient')}
/>
<Typeahead
<AsyncTypeahead
id="patientTypeahead"
disabled={!isEditable || patient !== undefined}
value={patient?.fullName}
defaultInputValue={patient ? String(patient) : ''}
placeholder={t('scheduling.appointment.patient')}
onChange={(p: Patient[]) =>
onFieldChange && p[0] && onFieldChange('patient', p[0].id)
}
onSearch={async (query: string) => PatientRepository.search(query)}
searchAccessor="fullName"
renderMenuItemChildren={(p: Patient) => <div>{`${p.fullName} (${p.code})`}</div>}
onChange={(p: any) => {
appointment.patientId = p[0] && p[0].resource.id
}}
onSearch={async (query: string) => {
setIsLoading(true)
setOptions(
patientDetails?.filter((detail: any) =>
String(detail.resource.name[0].text)
.toLowerCase()
.includes(query.toLowerCase()),
),
)
setIsLoading(false)
}}
options={options}
labelKey={(option) => `${option.resource?.name[0].text} `}
renderMenuItemChildren={(p: any) => {
return <div>{`${p.resource.name[0].text} ${p.resource.id}`}</div>
}}
isInvalid={!!error?.patient}
feedback={t(error?.patient)}
isLoading={isLoading}
/>
</div>
</div>
Expand All @@ -69,45 +109,35 @@ const AppointmentDetailForm = (props: Props) => {
<DateTimePickerWithLabelFormGroup
name="startDate"
label={t('scheduling.appointment.startDate')}
value={
appointment.startDateTime && appointment.startDateTime.length > 0
? new Date(appointment.startDateTime)
: undefined
}
value={appointment?.start ? new Date(appointment.start) : new Date(Date.now())}
isEditable={isEditable}
isInvalid={error?.startDateTime}
feedback={t(error?.startDateTime)}
onChange={(date: Date) => {
onDateChange(date, 'startDateTime')
appointment.start = String(date)
if (setAppointment) setAppointment(appointment)
}}
isRequired
/>
</div>
<div className="col">
<DateTimePickerWithLabelFormGroup
name="endDate"
label={t('scheduling.appointment.endDate')}
value={
appointment.endDateTime && appointment.endDateTime.length > 0
? new Date(appointment.endDateTime)
: undefined
appointment?.start && appointment.minutesDuration
? moment(appointment.start).add(appointment.minutesDuration, 'minute').toDate()
: endDateTime
}
isEditable={isEditable}
onChange={(date: Date) => {
onDateChange(date, 'endDateTime')
}}
/>
</div>
</div>
<div className="row">
<div className="col">
<TextInputWithLabelFormGroup
name="location"
label={t('scheduling.appointment.location')}
value={appointment.location}
isEditable={isEditable}
onChange={(event) => {
onInputElementChange(event, 'location')
appointment.end = String(date)
var difference =
new Date(appointment.end).getTime() - new Date(appointment.start).getTime()
appointment.minutesDuration = Math.round(difference / 60000)
if (setAppointment) setAppointment(appointment)
}}
isRequired
/>
</div>
</div>
Expand All @@ -117,25 +147,34 @@ const AppointmentDetailForm = (props: Props) => {
<Label text={t('scheduling.appointment.type')} title="type" />
<Select
id="type"
options={typeOptions}
defaultSelected={typeOptions.filter(({ value }) => value === appointment.type)}
onChange={(values) => onFieldChange && onFieldChange('type', values[0])}
options={appointmentTypes}
defaultSelected={appointmentTypes.filter(
({ value }) => value === appointment?.appointmentType?.text,
)}
onChange={(values) => {
appointment.appointmentType = { text: values[0] }
if (setAppointment) setAppointment(appointment)
}}
disabled={!isEditable}
/>
</div>
</div>
</div>
<div className="row">
<div className="col">
<div className="form-group">
<TextFieldWithLabelFormGroup
name="reason"
label={t('scheduling.appointment.reason')}
value={appointment.reason}
isEditable={isEditable}
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>
onFieldChange && onFieldChange('reason', event.currentTarget.value)
}
<div className="form-group" data-testid="typeSelect">
<Label text="Status" title="Status" />
<Select
id="status"
options={appointmentStatus}
defaultSelected={appointmentStatus.filter(
({ value }) => value == appointment?.status,
)}
onChange={(values) => {
appointment.status = values[0]
if (setAppointment) setAppointment(appointment)
}}
disabled={!isEditable}
/>
</div>
</div>
Expand Down
Loading

0 comments on commit c11a06e

Please sign in to comment.