diff --git a/src/components/EventCalendar/EventCalendar.module.css b/src/components/EventCalendar/EventCalendar.module.css index 921af48bae..607d750f85 100644 --- a/src/components/EventCalendar/EventCalendar.module.css +++ b/src/components/EventCalendar/EventCalendar.module.css @@ -271,14 +271,6 @@ .expand_event_list { display: block; } - -.list_container { - padding: 5px; - width: fit-content; - display: flex; - flex-direction: row; -} - .event_list_hour { display: flex; flex-direction: row; @@ -316,7 +308,8 @@ flex-grow: 1; } -@media only screen and (max-width: 700px) { +@media only screen and (max-width: var(--mobile-breakpoint)) { + /** @breakpoint --mobile-breakpoint: 768px */ .event_list { display: none; } @@ -331,7 +324,7 @@ } } -@media only screen and (max-width: 500px) { +@media only screen and (max-width: var(--small-mobile-breakpoint)) { .btn__more { font-size: 12px; } @@ -344,7 +337,22 @@ gap: 10px; margin-top: 35px; } +.base_card { + flex: 1; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); +} + +.holidays_card { + composes: base_card; + background-color: var(--holiday-card-bg); +} +.events_card { + composes: base_card; + background-color: #ffffff; +} .card__holidays { background-color: rgba(246, 242, 229, 1); display: flex; @@ -415,9 +423,150 @@ border-radius: 10px; } -.userEvents__color { - height: 15px; - width: 40px; - background: rgba(146, 200, 141, 0.5); +.baseIndicator { + border-radius: 5px; + width: 20px; + height: 12px; + display: inline-block; +} + +.holidayText { + font-size: 14px; + color: #555555; +} +.eventsLegend { + display: flex; + align-items: center; + gap: 8px; +} + +.list_container { + padding: 5px; + width: fit-content; + display: flex; + align-items: center; + gap: var(--indicator-spacing); +} + +.holidayIndicator { + composes: baseIndicator; + background-color: rgba(0, 0, 0, 0.15); +} + +:root { + /* Color scheme for holiday-related elements */ + --color-user-event: rgba(139, 195, 74, 1); + /* Holiday colors */ + --color-holiday-indicator: rgba(0, 0, 0, 0.15); + --color-holiday-date: rgba(255, 152, 0, 1); + /* Breakpoints for responsive design */ + --mobile-breakpoint: 700px; + --small-mobile-breakpoint: 480px; + --text-color-primary: rgba(51, 51, 51, 1); + --text-color-secondary: rgba(85, 85, 85, 1); + /* Card styles */ + --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + --holiday-card-bg: #f6f2e5; + --holiday-date-color: #d35400; + --indicator-spacing: 8px; + /* Interactive states */ + --hover-bg-color: rgba(0, 0, 0, 0.05); +} +.organizationIndicator { + composes: baseIndicator; + background-color: rgba(82, 172, 255, 0.5); +} + +.legendText { + font-size: 14px; + color: #555555; +} +@media only screen and (max-width: var(--mobile-breakpoint)) { + .list_container, + .eventsLegend { + gap: 4px; + } + + .holidayIndicator, + .organizationIndicator { + width: 16px; + height: 10px; + } + + .holidayText, + .legendText { + font-size: 12px; + } +} +.card_title { + font-size: 16px; + font-weight: 600; + color: var(--text-color-primary); + margin-bottom: 15px; +} + +.card_list { + list-style: none; + padding: 0; + margin: 0; +} + +.card_list_item { + display: flex; + align-items: center; + margin-bottom: 10px; + font-size: 14px; + color: var(--text-color-secondary); +} + +.holiday_date { + font-weight: 500; + margin-right: 10px; + color: var(--holiday-date-color); +} + +.calendar_infocards { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + gap: 20px; + padding: 20px; + background-color: var(--grey-bg-color); +} +.holidays_card, +.events_card { + flex: 1; + padding: 20px; border-radius: 10px; + box-shadow: var(--card-shadow); +} + +.holidays_card { + background-color: var(--holiday-card-bg); +} + +.events_card { + background-color: white; +} + +.legend { + display: flex; + flex-direction: column; + gap: 12px; +} + +.userEvents__color { + composes: baseIndicator; + display: inline-block; + background-color: rgba(139, 195, 74, 1); +} + +.card_list_item:hover { + background-color: var(--hover-bg-color); + transition: background-color 0.2s ease; +} +.card_list_item:focus-visible { + background-color: var(--hover-bg-color); + transition: background-color 0.2s ease; } diff --git a/src/components/EventCalendar/EventCalendar.tsx b/src/components/EventCalendar/EventCalendar.tsx index 575bda391e..ebcf8be942 100644 --- a/src/components/EventCalendar/EventCalendar.tsx +++ b/src/components/EventCalendar/EventCalendar.tsx @@ -1,16 +1,14 @@ import EventListCard from 'components/EventListCard/EventListCard'; import dayjs from 'dayjs'; +import React, { useState, useEffect, useMemo } from 'react'; import Button from 'react-bootstrap/Button'; -import React, { useState, useEffect } from 'react'; import styles from './EventCalendar.module.css'; import { ChevronLeft, ChevronRight } from '@mui/icons-material'; -import CurrentHourIndicator from 'components/CurrentHourIndicator/CurrentHourIndicator'; import { ViewType } from 'screens/OrganizationEvents/OrganizationEvents'; import HolidayCard from '../HolidayCards/HolidayCard'; -import { holidays, hours, months, weekdays } from './constants'; +import { holidays, months, weekdays } from './constants'; import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; import YearlyEventCalender from './YearlyEventCalender'; - interface InterfaceEventListCardProps { userRole?: string; key?: string; @@ -75,7 +73,6 @@ const Calendar: React.FC = ({ ); const [expanded, setExpanded] = useState(-1); const [windowWidth, setWindowWidth] = useState(window.screen.width); - useEffect(() => { function handleResize(): void { setWindowWidth(window.screen.width); @@ -138,9 +135,21 @@ const Calendar: React.FC = ({ } }; - /** - * Moves the calendar view to the next month. - */ + const filteredHolidays = useMemo(() => { + return Array.isArray(holidays) + ? holidays.filter((holiday) => { + if (!holiday.date) { + if (process.env.NODE_ENV !== 'test') { + console.warn(`Holiday "${holiday.name}" has no date specified.`); + } + return false; + } + const holidayMonth = dayjs(holiday.date, 'MM-DD', true).month(); + return holidayMonth === currentMonth; + }) + : []; + }, [holidays, currentMonth]); + const handleNextMonth = (): void => { if (currentMonth === 11) { setCurrentMonth(0); @@ -149,10 +158,6 @@ const Calendar: React.FC = ({ setCurrentMonth(currentMonth + 1); } }; - - /** - * Moves the calendar view to the previous date. - */ const handlePrevDate = (): void => { if (currentDate > 1) { setCurrentDate(currentDate - 1); @@ -193,9 +198,6 @@ const Calendar: React.FC = ({ } }; - /** - * Moves the calendar view to today's date. - */ const handleTodayButton = (): void => { setCurrentYear(today.getFullYear()); setCurrentMonth(today.getMonth()); @@ -264,6 +266,17 @@ const Calendar: React.FC = ({ ); }) || []; + const shouldShowViewMore = useMemo(() => { + return ( + allDayEventsList.length > 2 || + (windowWidth <= 700 && allDayEventsList.length > 0) + ); + }, [allDayEventsList.length, windowWidth]); + + const handleExpandClick: () => void = () => { + toggleExpand(-100); + }; + return ( <>
@@ -284,7 +297,6 @@ const Calendar: React.FC = ({ ? styles.expand_list_container : styles.list_container } - style={{ width: 'fit-content' }} >
= ({ : styles.event_list_hour } > - {expanded === -100 - ? allDayEventsList - : allDayEventsList?.slice(0, 1)} + {Array.isArray(allDayEventsList) && + allDayEventsList.length > 0 ? ( + expanded === -100 ? ( + allDayEventsList + ) : ( + allDayEventsList.slice(0, 1) + ) + ) : ( +

+ No events available +

+ )}
- {(allDayEventsList?.length > 2 || - (windowWidth <= 700 && allDayEventsList?.length > 0)) && ( + {Array.isArray(allDayEventsList) && ( )}
- {hours.map((hour, index) => { - const timeEventsList: JSX.Element[] = - events - ?.filter((datas) => { - const currDate = new Date( - currentYear, - currentMonth, - currentDate, - ); - - if ( - parseInt(datas.startTime?.slice(0, 2) as string).toString() == - (index % 24).toString() && - datas.startDate == dayjs(currDate).format('YYYY-MM-DD') - ) { - return datas; - } - }) - .map((datas: InterfaceEventListCardProps) => { - const attendees: { _id: string }[] = []; - datas.attendees?.forEach((attendee: { _id: string }) => { - const r = { - _id: attendee._id, - }; - - attendees.push(r); - }); - - return ( - - ); - }) || []; - return ( -
-
-

{`${hour}`}

+
+
+

Holidays

+
    + {filteredHolidays.map((holiday, index) => ( +
  • + + {months[parseInt(holiday.date.slice(0, 2), 10) - 1]}{' '} + {holiday.date.slice(3)} + + {holiday.name} +
  • + ))} +
+
+ +
+

Events

+
+
+ + Holidays
-
-
0 - ? styles.event_list_parent_current - : styles.event_list_parent - } - > - {index % 24 == new Date().getHours() && - new Date().getDate() == currentDate && ( - - )} -
-
- {} - {expanded === index - ? timeEventsList - : timeEventsList?.slice(0, 1)} -
- {(timeEventsList?.length > 1 || - (windowWidth <= 700 && timeEventsList?.length > 0)) && ( - - )} -
+
+ + + Events Created by Organization + +
+
+ + + Events Created by User +
- ); - })} +
+
); }; @@ -448,10 +407,10 @@ const Calendar: React.FC = ({ return days.map((date, index) => { const className = [ date.getDay() === 0 || date.getDay() === 6 ? styles.day_weekends : '', - date.toLocaleDateString() === today.toLocaleDateString() //Styling for today day cell + date.toLocaleDateString() === today.toLocaleDateString() ? styles.day__today : '', - date.getMonth() !== currentMonth ? styles.day__outside : '', //Styling for days outside the current month + date.getMonth() !== currentMonth ? styles.day__outside : '', selectedDate?.getTime() === date.getTime() ? styles.day__selected : '', styles.day, ].join(' '); @@ -504,13 +463,12 @@ const Calendar: React.FC = ({ ); }) || []; - const holidayList: JSX.Element[] = holidays - .filter((holiday) => { - if (holiday.date == dayjs(date).format('MM-DD')) return holiday; - }) + const holidayList: JSX.Element[] = filteredHolidays + .filter((holiday) => holiday.date === dayjs(date).format('MM-DD')) .map((holiday) => { return ; }); + return (
= ({ )}
{viewType == ViewType.MONTH ? ( -
+ <>
{weekdays.map((weekday, index) => (
@@ -611,18 +569,14 @@ const Calendar: React.FC = ({ ))}
{renderDays()}
-
+ + ) : viewType == ViewType.YEAR ? ( + ) : ( - // -
- {viewType == ViewType.YEAR ? ( - - ) : ( -
{renderHours()}
- )} -
+
{renderHours()}
)}
+
{viewType == ViewType.YEAR ? ( diff --git a/src/screens/UserPortal/Posts/Posts.test.tsx b/src/screens/UserPortal/Posts/Posts.test.tsx index aa5f03fdcf..433e36f94a 100644 --- a/src/screens/UserPortal/Posts/Posts.test.tsx +++ b/src/screens/UserPortal/Posts/Posts.test.tsx @@ -1,7 +1,7 @@ import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; import type { RenderResult } from '@testing-library/react'; -import { render, screen, waitFor, within } from '@testing-library/react'; +import { render, screen, within } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import userEvent from '@testing-library/user-event'; import { @@ -395,5 +395,8 @@ describe('HomeScreen with invalid orgId', () => { ); const homeEl = await screen.findByTestId('homeEl'); expect(homeEl).toBeInTheDocument(); + + const postCardContainers = screen.queryAllByTestId('postCardContainer'); + expect(postCardContainers).toHaveLength(0); }); }); diff --git a/src/setupTests.ts b/src/setupTests.ts index f0b48b39d0..d204b3ddc9 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -32,4 +32,4 @@ jestPreviewConfigure({ autoPreview: true, }); -jest.setTimeout(17000); +jest.setTimeout(18000);