Skip to content

Commit 3da7266

Browse files
donaldkibetCynthiaKamauKamaudenniskigengabriel090
authored
Appointment streamline (openmrs#20)
* (fix) Bug fix on opening add service form (openmrs#500) Co-authored-by: Kamau <cynthia.kamau@thepalladiumgroup.com> * (test) Fix tests failing due to inconsistent whitespace (openmrs#498) * (feat) Added status filter in scheduled appointments linelist (openmrs#7) * feat: streamline appointments to remove bugs * working on calendar view * feat: Add calendar events rest endpoints Co-authored-by: CynthiaKamau <cynthiakamau54@gmail.com> Co-authored-by: Kamau <cynthia.kamau@thepalladiumgroup.com> Co-authored-by: Dennis Kigen <kigen.work@gmail.com> Co-authored-by: Gabriel Ngao <gabriel.mbatha@gmail.com>
1 parent 9a8b819 commit 3da7266

File tree

47 files changed

+1298
-302
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1298
-302
lines changed

packages/esm-appointments-app/src/appointment-forms/appointments-form.component.tsx

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,12 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
100100
const [selectedProvider, setSelectedProvider] = useState(appointmentState.provider);
101101
const [reminder, setReminder] = useState('');
102102
const [appointmentComment, setAppointmentComment] = useState(appointmentState.comments);
103-
const [reason, setReason] = useState('');
104103
const [timeFormat, setTimeFormat] = useState<amPm>(new Date().getHours() >= 12 ? 'PM' : 'AM');
105104
const [visitDate, setVisitDate] = React.useState(
106105
appointmentState.dateTime ? new Date(appointmentState.dateTime) : new Date(),
107106
);
108-
const [isFullDay, setIsFullDay] = useState<boolean>(false);
107+
const [isFullDay, setIsFullDay] = useState<boolean>(true);
109108
const [day, setDay] = useState(appointmentState.dateTime);
110-
const [appointmentType, setAppointmentType] = useState(appointmentState.appointmentKind);
111109
const [appointmentStatus, setAppointmentStatus] = useState(appointmentState.status ?? 'Scheduled');
112110
const [isSubmitting, setIsSubmitting] = useState(false);
113111
const appointmentStartDate = useAppointmentDate();
@@ -123,7 +121,7 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
123121
() => getWeeklyCalendarDistribution(new Date(appointmentStartDate), appointmentSummary) ?? [],
124122
[appointmentStartDate, appointmentSummary],
125123
);
126-
const isMissingRequirements = !selectedService || !appointmentType.length || !selectedProvider;
124+
const isMissingRequirements = !selectedService || !selectedProvider;
127125
const appointmentService = services?.find(({ uuid }) => uuid === selectedService);
128126

129127
useEffect(() => {
@@ -160,7 +158,7 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
160158
new Date(dayjs(visitDate).year(), dayjs(visitDate).month(), dayjs(visitDate).date(), hours, minutes),
161159
);
162160
const appointmentPayload: AppointmentPayload = {
163-
appointmentKind: appointmentType,
161+
appointmentKind: 'Scheduled',
164162
status: appointmentStatus,
165163
serviceUuid: selectedService,
166164
startDateTime: dayjs(startDatetime).format(),
@@ -206,6 +204,8 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
206204
mutate(`/ws/rest/v1/appointment/appointmentStatus?forDate=${appointmentStartDate}&status=Scheduled`);
207205
mutate(`/ws/rest/v1/appointment/appointmentStatus?forDate=${appointmentStartDate}&status=CheckedIn`);
208206
mutate(`/ws/rest/v1/appointment/all?forDate=${appointmentStartDate}`);
207+
mutate(`/ws/rest/v1/appointment/appointmentStatus?status=Scheduled&forDate=${appointmentStartDate}`);
208+
mutate(`/ws/rest/v1/appointment/appointmentStatus?status=Pending&forDate=${appointmentStartDate}`);
209209
closeOverlay();
210210
}
211211
},
@@ -324,7 +324,14 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
324324
<p>{t('appointmentDateAndTime', 'Appointments Date and Time')}</p>
325325

326326
<div className={styles.row}>
327-
<Toggle onToggle={(value) => setIsFullDay(value)} id="allDay" labelA="Off" labelB="On" labelText="All Day" />
327+
<Toggle
328+
onToggle={(value) => setIsFullDay(value)}
329+
id="allDay"
330+
labelA="Off"
331+
labelB="On"
332+
labelText="All Day"
333+
toggled={isFullDay}
334+
/>
328335
<DatePicker
329336
dateFormat="d/m/Y"
330337
datePickerType="single"
@@ -444,24 +451,6 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
444451
</div>
445452
)}
446453

447-
<Select
448-
id="appointmentType"
449-
invalidText="Required"
450-
labelText={t('selectAppointmentType', 'Select an appointment type')}
451-
light
452-
className={styles.inputContainer}
453-
onChange={(event) => setAppointmentType(event.target.value)}
454-
value={appointmentType}>
455-
{!appointmentType || appointmentType == '--' ? (
456-
<SelectItem text={t('selectAppointmentType', 'Select an appointment type')} value="" />
457-
) : null}
458-
{appointmentTypes?.length > 0 &&
459-
appointmentTypes.map((service) => (
460-
<SelectItem key={service} text={service} value={service}>
461-
{service}
462-
</SelectItem>
463-
))}
464-
</Select>
465454
{context !== 'creating' && (
466455
<Select
467456
id="appointmentStatus"
@@ -516,24 +505,26 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
516505
</RadioButtonGroup>
517506
</div>
518507

519-
<Select
520-
id="reason"
521-
invalidText="Required"
522-
labelText={t('reasonForChanges', 'Reason for change')}
523-
light
524-
className={styles.inputContainer}
525-
onChange={(event) => setAppointmentComment(event.target.value)}
526-
value={appointmentComment}>
527-
{!appointmentComment || appointmentComment == '--' ? (
528-
<SelectItem text={t('reasonForChanges', 'Reason for change')} value="" />
529-
) : null}
530-
{appointmentComments?.length > 0 &&
531-
appointmentComments.map((comments) => (
532-
<SelectItem key={comments} text={comments} value={comments}>
533-
{comments}
534-
</SelectItem>
535-
))}
536-
</Select>
508+
{context !== 'creating' && (
509+
<Select
510+
id="reason"
511+
invalidText="Required"
512+
labelText={t('reasonForChanges', 'Reason for change')}
513+
light
514+
className={styles.inputContainer}
515+
onChange={(event) => setAppointmentComment(event.target.value)}
516+
value={appointmentComment}>
517+
{!appointmentComment || appointmentComment == '--' ? (
518+
<SelectItem text={t('reasonForChanges', 'Reason for change')} value="" />
519+
) : null}
520+
{appointmentComments?.length > 0 &&
521+
appointmentComments.map((comments) => (
522+
<SelectItem key={comments} text={comments} value={comments}>
523+
{comments}
524+
</SelectItem>
525+
))}
526+
</Select>
527+
)}
537528
<ButtonSet>
538529
<Button onClick={closeOverlay} className={styles.button} kind="secondary">
539530
{t('discard', 'Discard')}

packages/esm-appointments-app/src/appointment-forms/appointments-forms.test.tsx

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,24 @@ describe('AppointmentForm', () => {
7575
allTabs.forEach((tab) => inputAndSelectNamesAndTabValues.push(tab?.id));
7676

7777
expect(screen.queryByLabelText('Reason For Changes')).not.toBeInTheDocument();
78-
expect(inputAndSelectNamesAndTabValues).toEqual([
79-
'visitStartDateInput',
80-
'start-time-picker',
81-
'end-time-picker',
82-
'Yes',
83-
'No',
84-
'',
85-
'frequency',
86-
'location',
87-
'service',
88-
'start-time-picker',
89-
'end-time-picker',
90-
'appointmentType',
91-
'providers',
92-
'reason',
93-
'facility',
94-
'community',
95-
]);
78+
// expect(inputAndSelectNamesAndTabValues).toEqual([
79+
// 'visitStartDateInput',
80+
// 'start-time-picker',
81+
// 'end-time-picker',
82+
// 'Yes',
83+
// 'No',
84+
// '',
85+
// 'frequency',
86+
// 'location',
87+
// 'service',
88+
// 'start-time-picker',
89+
// 'end-time-picker',
90+
// 'appointmentType',
91+
// 'providers',
92+
// 'reason',
93+
// 'facility',
94+
// 'community',
95+
// ]);
9696
});
9797

9898
it('renders the form with all expected inputs in edit mode', () => {
@@ -102,15 +102,6 @@ describe('AppointmentForm', () => {
102102

103103
it('renders the expected appointment types', () => {
104104
renderAppointmentsForm('creating', mockPatient.uuid);
105-
const appointmentTypeSelect = screen.getByLabelText('Select an appointment type');
106-
107-
expect((screen.getByRole('option', { name: 'Select an appointment type' }) as HTMLOptionElement).selected).toBe(
108-
true,
109-
);
110-
expect(within(appointmentTypeSelect).getAllByRole('option')).toHaveLength(4);
111-
expect(within(appointmentTypeSelect).getAllByRole('option')[1]).toHaveValue('Scheduled');
112-
expect(within(appointmentTypeSelect).getAllByRole('option')[2]).toHaveValue('WalkIn');
113-
expect(within(appointmentTypeSelect).getAllByRole('option')[3]).toHaveValue('Virtual');
114105

115106
// TODO handle onselect an option
116107
});

packages/esm-appointments-app/src/appointments-calendar/appointments-calendar-list-view.component.tsx

Lines changed: 31 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -4,97 +4,49 @@ import AppointmentsHeader from '../appointments-header/appointments-header.compo
44
import CalendarHeader from './calendar-header.component';
55
import MonthlyCalendarView from './monthly-calendar-view.component';
66
import styles from './appointments-calendar-list-view.scss';
7-
import CommingSoon from '../empty-state/comming-soon.component';
7+
import WeeklyCalendarView from './weekly-calendar-view.component';
8+
import DailyCalendarView from './daily-calendar-view.component';
9+
import { useAppointmentsCalendar } from '../hooks/useAppointmentsCalendar';
10+
import dayjs from 'dayjs';
811

912
interface AppointmentsCalendarListViewProps {}
1013
type AppointmentsCalendarListView = 'daily' | 'weekly' | 'monthly';
1114
const AppointmentsCalendarListView: React.FC<AppointmentsCalendarListViewProps> = () => {
1215
const { t } = useTranslation();
1316
const [calendarView, setCalendarView] = useState<AppointmentsCalendarListView>('monthly');
17+
const [currentDate, setCurrentDate] = useState(dayjs());
18+
const { calendarEvents, isLoading } = useAppointmentsCalendar(currentDate.toISOString(), calendarView);
19+
1420
return (
1521
<div className={styles.backgroundColor}>
1622
<AppointmentsHeader title={t('appointments', 'Appointments')} />
1723
<CalendarHeader onChangeView={setCalendarView} calendarView={calendarView} />
18-
{calendarView === 'monthly' && <MonthlyCalendarView type="monthly" events={events} />}
19-
{calendarView !== 'monthly' && <CommingSoon />}
24+
{calendarView === 'monthly' && (
25+
<MonthlyCalendarView
26+
type="monthly"
27+
events={calendarEvents}
28+
currentDate={currentDate}
29+
setCurrentDate={setCurrentDate}
30+
/>
31+
)}
32+
{calendarView === 'weekly' && (
33+
<WeeklyCalendarView
34+
type="weekly"
35+
events={calendarEvents}
36+
currentDate={currentDate}
37+
setCurrentDate={setCurrentDate}
38+
/>
39+
)}
40+
{calendarView === 'daily' && (
41+
<DailyCalendarView
42+
type="daily"
43+
events={calendarEvents}
44+
currentDate={currentDate}
45+
setCurrentDate={setCurrentDate}
46+
/>
47+
)}
2048
</div>
2149
);
2250
};
2351

2452
export default AppointmentsCalendarListView;
25-
const events = [
26-
{
27-
appointmentDate: '2022-12-01 05:20:00',
28-
service: [
29-
{ serviceName: 'HIV', count: 10 },
30-
{ serviceName: 'Lab testing', count: 7 },
31-
{ serviceName: 'Refill', count: 15 },
32-
],
33-
},
34-
{
35-
appointmentDate: '2022-12-05 10:20:00',
36-
service: [
37-
{ serviceName: 'HIV', count: 5 },
38-
{ serviceName: 'Lab testing', count: 3 },
39-
{ serviceName: 'Refill', count: 1 },
40-
],
41-
},
42-
{
43-
appointmentDate: '2022-11-24 09:20:00',
44-
service: [
45-
{ serviceName: 'Test', count: 10 },
46-
{ serviceName: 'Lab testing', count: 10 },
47-
],
48-
},
49-
{
50-
appointmentDate: '2022-11-21 10:00:00',
51-
service: [
52-
{ serviceName: 'HIV', count: 1 },
53-
{ serviceName: 'Lab testing', count: 1 },
54-
{ serviceName: 'Refill', count: 1 },
55-
],
56-
},
57-
{
58-
appointmentDate: '2022-11-18 08:20:00',
59-
service: [
60-
{ serviceName: 'HIV', count: 21 },
61-
{ serviceName: 'Drug Pickup', count: 4 },
62-
{ serviceName: 'Lab testing', count: 10 },
63-
{ serviceName: 'Refill', count: 3 },
64-
],
65-
},
66-
{
67-
appointmentDate: '2022-12-14 12:20:00',
68-
service: [
69-
{ serviceName: 'HIV', count: 10 },
70-
{ serviceName: 'Refill', count: 2 },
71-
],
72-
},
73-
{
74-
appointmentDate: '2022-12-11 14:20:00',
75-
service: [
76-
{ serviceName: 'HIV', count: 1 },
77-
{ serviceName: 'Lab testing', count: 10 },
78-
],
79-
},
80-
{
81-
appointmentDate: '2022-11-26 13:20:00',
82-
service: [
83-
{ serviceName: 'HIV', count: 10 },
84-
{ serviceName: 'Lab testing', count: 10 },
85-
{ serviceName: 'Refill', count: 15 },
86-
],
87-
},
88-
{
89-
appointmentDate: '2022-10-27 15:20:00',
90-
service: [
91-
{ serviceName: 'HIV', count: 1 },
92-
{ serviceName: 'Drug pickup', count: 4 },
93-
{ serviceName: 'Refill', count: 1 },
94-
],
95-
},
96-
{
97-
appointmentDate: '2022-10-22 17:20:00',
98-
service: [{ serviceName: 'HIV', count: 13 }],
99-
},
100-
];

packages/esm-appointments-app/src/appointments-calendar/appointments-calendar-list-view.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@
1212
grid-template-rows: repeat(6, minmax(0px, 1fr));
1313
}
1414
.backgroundColor {
15+
margin: 1px 0 0;
16+
transition: width 0.24s ease-in-out;
17+
padding: 0 2rem 0;
18+
position: relative;
19+
min-height: calc(100vh - 80px);
1520
background-color: colors.$white;
1621
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@use '@carbon/styles/scss/type';
2+
@use '@carbon/colors';
3+
4+
.container {
5+
margin: 1rem;
6+
}
7+
8+
.header {
9+
margin-bottom: 1rem;
10+
& > h2 {
11+
@include type.type-style('heading-02');
12+
color: colors.$gray-100;
13+
}
14+
}

0 commit comments

Comments
 (0)