Skip to content

Commit

Permalink
Merge branch 'main' into test/O3-2428
Browse files Browse the repository at this point in the history
  • Loading branch information
Vijaykv5 committed May 8, 2024
2 parents efd2935 + ea6f319 commit c43df6f
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 778 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const AppointmentsActions: React.FC<AppointmentsActionsProps> = ({ appointment }
(visit) => visit?.patient?.uuid === patientUuid && visit?.startDatetime && !visit?.stopDatetime,
);
const isTodaysAppointment = visitDate.isToday();
const isCheckedIn = appointment.status === AppointmentStatus.CHECKEDIN;
const isCompleted = appointment.status === AppointmentStatus.COMPLETED;
const isCancelled = appointment.status === AppointmentStatus.CANCELLED;

Expand Down Expand Up @@ -61,7 +62,7 @@ const AppointmentsActions: React.FC<AppointmentsActionsProps> = ({ appointment }
{t('checkedOut', 'Checked out')}
</Button>
);
case checkOutButton.enabled && hasActiveVisitToday && isTodaysAppointment:
case checkOutButton.enabled && isCheckedIn:
return (
<Button onClick={handleCheckout} kind="danger--tertiary" size="sm">
{t('checkOut', 'Check out')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React from 'react';
import { Button } from '@carbon/react';
import { useTranslation } from 'react-i18next';
import { launchOverlay } from '../../hooks/useOverlay';
import VisitForm from '../../patient-queue/visit-form/visit-form.component';
import { type Appointment } from '../../types';
import dayjs from 'dayjs';
import isToday from 'dayjs/plugin/isToday';
import utc from 'dayjs/plugin/utc';
import { navigate, useConfig } from '@openmrs/esm-framework';
import { navigate, useConfig, launchWorkspace } from '@openmrs/esm-framework';
import { type ConfigObject } from '../../config-schema';
dayjs.extend(utc);
dayjs.extend(isToday);
Expand All @@ -33,10 +31,7 @@ const CheckInButton: React.FC<CheckInButtonProps> = ({ appointment, patientUuid
to: checkInButton.customUrl,
templateParams: { patientUuid: appointment.patient.uuid, appointmentUuid: appointment.uuid },
})
: launchOverlay(
t('patientSearch', 'Patient search'),
<VisitForm patientUuid={patientUuid} appointment={appointment} />,
)
: launchWorkspace('start-visit-workspace-form', { patientUuid: patientUuid })
}>
{t('checkIn', 'Check in')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
border-left: 1px solid colors.$gray-20;
border-bottom: 1px solid colors.$gray-20;
}

&-disabled:last-child {
border-right: 1px solid colors.$gray-20;
}
}

.identifiers {
@include type.type-style('body-compact-02');
color: $ui-04;
Expand All @@ -38,10 +40,12 @@
margin: 0rem 0.75rem;
}
}

.identifierTag {
display: flex;
align-items: center;
}

.weekly-cell {
position: relative;
border-right: 1px solid colors.$gray-20;
Expand Down Expand Up @@ -77,29 +81,32 @@
}

.currentData {
margin: 2px;
padding-top: 2px;
background-color: colors.$gray-10;
display: flex;
flex-direction: column;
align-items: start;
margin: 0.1rem 0.1rem 0.5rem 0.1rem;

& > span {
@include type.type-style('label-02');
}
}

.serviceArea {
padding: 0.0125rem;
width: 100%;
padding: 0.125rem;
margin-right: 0.5rem;
display: grid;
grid-template-columns: 4fr 1fr;
justify-content: flex-start;
text-align: left;
margin: 0.125rem;
@include type.type-style('label-01');
color: #020f1b;
cursor: pointer;
@include type.type-style('label-01');

& > span:first-child {
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}

& > span:nth-child(2) {
Expand All @@ -108,8 +115,31 @@
}

.serviceArea:hover {
opacity: 0.8;
border: 1px solid grey;
background-color: colors.$gray-10;
}

.totals {
padding: 0.125rem;
display: grid;
grid-template-columns: 4fr 1fr;
justify-content: flex-start;
background-color: colors.$gray-10;

& > div {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
cursor: pointer;
font-weight: lighter;
}

& > span:nth-child(2) {
color: #020f1b;
font-weight: bold;
text-align: right;
@include type.type-style('heading-compact-01');
}
}

.smallDesktop {
Expand Down Expand Up @@ -144,6 +174,15 @@
font-weight: bold;
}

.calendarDate {
.showMoreItems {
margin-top: 0.1rem;
padding: 0;
@include type.type-style('heading-compact-01');
text-decoration: underline;
color: colors.$blue-50;
background-color: colors.$white;
font-weight: lighter;
border: none;
outline: none;
cursor: pointer;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useEffect, useRef } from 'react';
import { Popover, PopoverContent } from '@carbon/react';
import styles from './monthly-view-workload.scss';
import MonthlyWorkloadView, { type MonthlyWorkloadViewProps } from './monthly-workload-view.component';
import { useTranslation } from 'react-i18next';

interface MonthlyWorkloadViewExpandedProps extends MonthlyWorkloadViewProps {
count: number;
}

const MonthlyWorkloadViewExpanded: React.FC<MonthlyWorkloadViewExpandedProps> = ({ count, events, dateTime }) => {
const { t } = useTranslation();
const [isOpen, setIsOpen] = React.useState(false);
const popoverRef = useRef(null);

const handleClickOutside = (event) => {
if (popoverRef.current && !popoverRef.current.contains(event.target)) {
setIsOpen(false);
}
};

useEffect(() => {
document.addEventListener('click', handleClickOutside);

return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);

return (
<Popover open={isOpen} align="top" ref={popoverRef}>
<button className={styles.showMoreItems} onClick={() => setIsOpen((prev) => !prev)}>
{t('countMore', '{{count}} more', { count })}
</button>
<PopoverContent>
<MonthlyWorkloadView events={events} dateTime={dateTime} showAllServices={true} />
</PopoverContent>
</Popover>
);
};

export default MonthlyWorkloadViewExpanded;
Original file line number Diff line number Diff line change
@@ -1,51 +1,80 @@
import React, { useContext } from 'react';
import React, { useContext, useMemo } from 'react';
import classNames from 'classnames';
import dayjs, { type Dayjs } from 'dayjs';
import { useTranslation } from 'react-i18next';
import { navigate, useLayoutType } from '@openmrs/esm-framework';
import { isSameMonth } from '../../helpers';
import { spaHomePage } from '../../constants';
import styles from './monthly-view-workload.scss';
import { type DailyAppointmentsCountByService } from '../../types';
import SelectedDateContext from '../../hooks/selectedDateContext';
import { User } from '@carbon/react/icons';
import MonthlyWorkloadViewExpanded from './monthly-workload-view-expanded.component';

interface MonthlyWorkloadViewProps {
export interface MonthlyWorkloadViewProps {
events: Array<DailyAppointmentsCountByService>;
dateTime: Dayjs;
showAllServices?: boolean;
}

const MonthlyWorkloadView: React.FC<MonthlyWorkloadViewProps> = ({ dateTime, events }) => {
const MonthlyWorkloadView: React.FC<MonthlyWorkloadViewProps> = ({ dateTime, events, showAllServices = false }) => {
const layout = useLayoutType();
const { t } = useTranslation();
const { selectedDate } = useContext(SelectedDateContext);

const currentData = events?.find(
(event) => dayjs(event.appointmentDate)?.format('YYYY-MM-DD') === dayjs(dateTime)?.format('YYYY-MM-DD'),
const currentData = useMemo(
() =>
events?.find(
(event) => dayjs(event.appointmentDate)?.format('YYYY-MM-DD') === dayjs(dateTime)?.format('YYYY-MM-DD'),
),
[events],
);

const onClick = (serviceUuid) => {
const visibleServices = useMemo(() => {
if (currentData?.services) {
if (showAllServices) return currentData.services;
return currentData.services.slice(0, layout === 'small-desktop' ? 2 : 4);
}
return [];
}, [currentData, showAllServices, layout, currentData]);

const hasHiddenServices = useMemo(() => {
if (currentData?.services) {
if (showAllServices) return false;
return layout === 'small-desktop' ? currentData.services.length > 2 : currentData.services.length > 4;
}
return false;
}, [layout, currentData, currentData]);

const onClick = (serviceUuid: string) => {
navigate({ to: `${spaHomePage}/appointments/${dayjs(dateTime).format('YYYY-MM-DD')}/${serviceUuid}` });
};

return (
<div
onClick={() => {
onClick('');
}}
className={classNames(
styles[isSameMonth(dateTime, dayjs(selectedDate)) ? 'monthly-cell' : 'monthly-cell-disabled'],
{
[styles.greyBackground]: currentData?.services,
[styles.smallDesktop]: layout === 'small-desktop',
[styles.largeDesktop]: layout !== 'small-desktop',
},
showAllServices
? {}
: {
[styles.smallDesktop]: layout === 'small-desktop',
[styles.largeDesktop]: layout !== 'small-desktop',
},
)}>
{isSameMonth(dateTime, dayjs(selectedDate)) && (
<p>
<b className={styles.calendarDate}>{dateTime.format('D')}</b>
<div className={classNames(styles.totals)}>
{currentData?.services ? (
<div role="button" tabIndex={0}>
<User size={16} />
<span>{currentData?.services.reduce((sum, { count = 0 }) => sum + count, 0)}</span>
</div>
) : (
<div />
)}
<b className={styles.calendarDate}>{dateTime.format('D')}</b>
</div>
{currentData?.services && (
<div className={styles.currentData}>
{currentData.services.map(({ serviceName, serviceUuid, count }, i) => (
{visibleServices.map(({ serviceName, serviceUuid, count }, i) => (
<div
key={`${serviceUuid}-${count}-${i}`}
role="button"
Expand All @@ -59,17 +88,15 @@ const MonthlyWorkloadView: React.FC<MonthlyWorkloadViewProps> = ({ dateTime, eve
<span>{count}</span>
</div>
))}
<div
role="button"
tabIndex={0}
onClick={(e) => {
e.stopPropagation();
onClick('');
}}
className={classNames(styles.serviceArea, styles.green)}>
<span>{t('total', 'Total')}</span>
<span>{currentData?.services.reduce((sum, { count = 0 }) => sum + count, 0)}</span>
</div>
{hasHiddenServices ? (
<MonthlyWorkloadViewExpanded
count={currentData.services.length - (layout === 'small-desktop' ? 2 : 4)}
events={events}
dateTime={dateTime}
/>
) : (
''
)}
</div>
)}
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,18 @@ const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps
.concat(futureAppointments)
.filter((appointment) => appointment.status !== 'CheckedIn');

// If there is only one appointment, select it by default
if (appointments?.length === 1) {
setUpcomingAppointment(appointments[0]);
const defaultAppointment = ((appointments) => {
// if there's only one appointment today, select it by default, otherwise no default
const appts = appointments?.filter((appointment) =>
dayjs(new Date(appointment.startDateTime).toISOString()).isToday(),
);
if (appts?.length === 1) {
return appts[0];
}
})(appointments);

if (defaultAppointment) {
setUpcomingAppointment(defaultAppointment);
}

if (isError) {
Expand All @@ -69,7 +78,7 @@ const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps
className={styles.checkbox}
key={i}
labelText=""
defaultChecked={dayjs(new Date(appointment.startDateTime).toISOString()).isToday()}
defaultChecked={appointment.uuid === defaultAppointment?.uuid}
id={appointment.uuid}
onChange={(e) => (e.target.checked ? setUpcomingAppointment(appointment) : '')}
/>
Expand Down Expand Up @@ -100,6 +109,7 @@ const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps
</div>
);
}

return (
<InlineNotification
kind={'info'}
Expand Down

0 comments on commit c43df6f

Please sign in to comment.