Skip to content

Commit

Permalink
(feat) O3-3014: Add expand appointments calendar view (#1123)
Browse files Browse the repository at this point in the history
* feat: add expand appointments calendar view

* fix: fix with service area row

* chore: add translation
  • Loading branch information
usamaidrsk authored May 8, 2024
1 parent b06a2a8 commit 110aa7b
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 40 deletions.
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
3 changes: 2 additions & 1 deletion packages/esm-appointments-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
"chooseProvider": "Choose a provider",
"chooseService": "Select service",
"completed": "Completed",
"countMore_one": "{{count}} more",
"countMore_other": "{{count}} more",
"createAppointmentService": "Create appointment services",
"createNewAppointment": "Create new appointment",
"date": "Date",
Expand Down Expand Up @@ -153,7 +155,6 @@
"time": "Time",
"today": "Today",
"todays": "Today's",
"total": "Total",
"unscheduled": "Unscheduled",
"unscheduledAppointments": "Unscheduled appointments",
"unscheduledAppointments_lower": "unscheduled appointments",
Expand Down

0 comments on commit 110aa7b

Please sign in to comment.