Skip to content

Commit 4cc9863

Browse files
authored
Merge pull request #3983 from Northeastern-Electric-Racing/calendar-week-view
calendar week view
2 parents 16563e6 + 7211a8e commit 4cc9863

6 files changed

Lines changed: 1164 additions & 100 deletions

File tree

src/frontend/src/pages/CalendarPage/CalendarPage.tsx

Lines changed: 125 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ import {
3434
convertIntToDay,
3535
eventsToEventInstances,
3636
eventsToNextEventInstance,
37-
getOverlapTime
37+
getOverlapTime,
38+
getSundayOfWeek
3839
} from '../../utils/calendar.utils';
3940
import { filterEventTransformer } from '../../apis/transformers/calendar.transformer';
4041
import WarningIcon from '@mui/icons-material/Warning';
@@ -43,6 +44,7 @@ import UpcomingMeetingsCard from './UpcomingMeetingsCard';
4344
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
4445
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
4546
import { EventInstance } from 'shared';
47+
import CalendarWeekView from './CalendarWeekView';
4648

4749
// localStorage key for calendar filters
4850
const CALENDAR_FILTERS_KEY = 'calendar-filters';
@@ -85,15 +87,25 @@ interface NewCalendarPageProps {
8587
yourEvents: EventInstance[];
8688
reviewEvents: Event[];
8789
allCalendars: Calendar[];
88-
onCreateEventClick: (date: Date) => void;
90+
onCreateEventClick: (date: Date, startTime?: Date, endTime?: Date) => void;
91+
viewMode: 'month' | 'week';
92+
displayMonthYear: Date;
93+
setDisplayMonthYear: (date: Date) => void;
94+
displayWeek: Date;
95+
setDisplayWeek: (date: Date) => void;
8996
}
9097

9198
const NewCalendarPage: React.FC<NewCalendarPageProps> = ({
9299
allEventTypes,
93100
yourEvents,
94101
reviewEvents,
95102
allCalendars,
96-
onCreateEventClick
103+
onCreateEventClick,
104+
viewMode,
105+
displayMonthYear,
106+
setDisplayMonthYear,
107+
displayWeek,
108+
setDisplayWeek
97109
}) => {
98110
const theme = useTheme();
99111
const history = useHistory();
@@ -111,7 +123,6 @@ const NewCalendarPage: React.FC<NewCalendarPageProps> = ({
111123

112124
const [memberIds, setMemberIds] = useState<string[]>(savedFilters.memberIds ?? []);
113125
const [teamIds, setTeamIds] = useState<string[]>(savedFilters.teamIds ?? []);
114-
const [displayMonthYear, setDisplayMonthYear] = useState<Date>(new Date());
115126
const [showInvitedEvents, setShowInvitedEvents] = useState<boolean>(savedFilters.showInvitedEvents ?? true);
116127
const [showTeamEvents, setShowTeamEvents] = useState<boolean>(savedFilters.showTeamEvents ?? true);
117128
const [openFilterModal, setOpenFilterModal] = useState(false);
@@ -155,8 +166,14 @@ const NewCalendarPage: React.FC<NewCalendarPageProps> = ({
155166
}
156167
}, [allTeams, teamList, additionalTeamIds.length, showTeamEvents, allEventsMode]);
157168

158-
const startPeriod = new Date(displayMonthYear.getFullYear(), displayMonthYear.getMonth() - 1, 15);
159-
const endPeriod = new Date(displayMonthYear.getFullYear(), displayMonthYear.getMonth() + 1, 15);
169+
const startPeriod =
170+
viewMode === 'week'
171+
? new Date(displayWeek.getFullYear(), displayWeek.getMonth(), displayWeek.getDate())
172+
: new Date(displayMonthYear.getFullYear(), displayMonthYear.getMonth() - 1, 15);
173+
const endPeriod =
174+
viewMode === 'week'
175+
? new Date(displayWeek.getFullYear(), displayWeek.getMonth(), displayWeek.getDate() + 7, 23, 59, 59)
176+
: new Date(displayMonthYear.getFullYear(), displayMonthYear.getMonth() + 1, 15);
160177

161178
// When allEventsMode is true, we don't filter by members/teams, but still filter by date and calendars
162179
const filterArgs = allEventsMode
@@ -533,80 +550,99 @@ const NewCalendarPage: React.FC<NewCalendarPageProps> = ({
533550
}}
534551
>
535552
<Box sx={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
536-
<Grid container sx={{ flexShrink: 0 }}>
537-
{enumToArray(DAY_NAMES).map((day, index) => (
538-
<Grid item xs={12 / 7} key={index}>
539-
<Typography align={'center'} sx={{ fontWeight: 'bold', fontSize: 18 }}>
540-
{
541-
// Day of the week display based on current breakpoint
542-
isLargerView ? day : isExtraSmallView ? day.charAt(0) : day.substring(0, 3)
543-
}
544-
</Typography>
553+
{viewMode === 'week' ? (
554+
<CalendarWeekView
555+
allEventTypes={allEventTypes ?? []}
556+
allCalendars={allCalendars ?? []}
557+
eventInstances={eventInstances}
558+
displayWeek={displayWeek}
559+
onNavigateWeek={(offset) => {
560+
const newWeek = new Date(displayWeek);
561+
newWeek.setDate(newWeek.getDate() + offset * 7);
562+
setDisplayWeek(newWeek);
563+
}}
564+
onCreateEventClick={onCreateEventClick}
565+
/>
566+
) : (
567+
<>
568+
<Grid container sx={{ flexShrink: 0 }}>
569+
{enumToArray(DAY_NAMES).map((day, index) => (
570+
<Grid item xs={12 / 7} key={index}>
571+
<Typography align={'center'} sx={{ fontWeight: 'bold', fontSize: 18 }}>
572+
{
573+
// Day of the week display based on current breakpoint
574+
isLargerView ? day : isExtraSmallView ? day.charAt(0) : day.substring(0, 3)
575+
}
576+
</Typography>
577+
</Grid>
578+
))}
545579
</Grid>
546-
))}
547-
</Grid>
548-
<Box
549-
sx={{
550-
border: '2px solid white',
551-
borderRadius: 2,
552-
bgcolor: '#1a1a1a',
553-
p: 1,
554-
flex: 1,
555-
display: 'flex',
556-
flexDirection: 'column',
557-
overflow: 'hidden'
558-
}}
559-
>
560-
{startOfEachWeek
561-
.filter((week) => daysThisMonth.slice(week, week + 7).length > 0)
562-
.map((week, weekIndex) => (
563-
<Box
564-
key={weekIndex}
565-
sx={{
566-
display: 'flex',
567-
flex: 1,
568-
minHeight: 0
569-
}}
570-
>
571-
{daysThisMonth.slice(week, week + 7).map((day, dayIndex) => {
572-
const cardDate = new Date(
573-
displayMonthYear.getFullYear(),
574-
displayMonthYear.getMonth() + (isDayInDifferentMonth(day, week) ? (day > 15 ? -1 : 1) : 0),
575-
day
576-
);
577-
return (
578-
<Box
579-
key={dayIndex}
580-
sx={{
581-
flex: 1,
582-
minWidth: 0,
583-
display: 'flex',
584-
justifyContent: 'center',
585-
alignItems: 'stretch',
586-
p: 0.5
587-
}}
588-
>
589-
<CalendarDayCard
590-
cardDate={cardDate}
591-
displayMonth={displayMonthYear}
592-
events={
593-
eventDict.get(datePipe(new Date(cardDate.getTime() + cardDate.getTimezoneOffset() * 60000))) ??
594-
[]
595-
}
596-
eventTypes={allEventTypes ?? []}
597-
calendars={allCalendars ?? []}
598-
dayOfWeek={
599-
dayDict.get(datePipe(new Date(cardDate.getTime() + cardDate.getTimezoneOffset() * 60000))) ??
600-
DayOfWeek.SUNDAY
601-
}
602-
onCreateEventClick={onCreateEventClick}
603-
/>
604-
</Box>
605-
);
606-
})}
607-
</Box>
608-
))}
609-
</Box>
580+
<Box
581+
sx={{
582+
border: '2px solid white',
583+
borderRadius: 2,
584+
bgcolor: '#1a1a1a',
585+
p: 1,
586+
flex: 1,
587+
display: 'flex',
588+
flexDirection: 'column',
589+
overflow: 'hidden'
590+
}}
591+
>
592+
{startOfEachWeek
593+
.filter((week) => daysThisMonth.slice(week, week + 7).length > 0)
594+
.map((week, weekIndex) => (
595+
<Box
596+
key={weekIndex}
597+
sx={{
598+
display: 'flex',
599+
flex: 1,
600+
minHeight: 0
601+
}}
602+
>
603+
{daysThisMonth.slice(week, week + 7).map((day, dayIndex) => {
604+
const cardDate = new Date(
605+
displayMonthYear.getFullYear(),
606+
displayMonthYear.getMonth() + (isDayInDifferentMonth(day, week) ? (day > 15 ? -1 : 1) : 0),
607+
day
608+
);
609+
return (
610+
<Box
611+
key={dayIndex}
612+
sx={{
613+
flex: 1,
614+
minWidth: 0,
615+
display: 'flex',
616+
justifyContent: 'center',
617+
alignItems: 'stretch',
618+
p: 0.5
619+
}}
620+
>
621+
<CalendarDayCard
622+
cardDate={cardDate}
623+
displayMonth={displayMonthYear}
624+
events={
625+
eventDict.get(
626+
datePipe(new Date(cardDate.getTime() + cardDate.getTimezoneOffset() * 60000))
627+
) ?? []
628+
}
629+
eventTypes={allEventTypes ?? []}
630+
calendars={allCalendars ?? []}
631+
dayOfWeek={
632+
dayDict.get(
633+
datePipe(new Date(cardDate.getTime() + cardDate.getTimezoneOffset() * 60000))
634+
) ?? DayOfWeek.SUNDAY
635+
}
636+
onCreateEventClick={onCreateEventClick}
637+
/>
638+
</Box>
639+
);
640+
})}
641+
</Box>
642+
))}
643+
</Box>
644+
</>
645+
)}
610646
</Box>
611647
<Box
612648
sx={{
@@ -619,10 +655,17 @@ const NewCalendarPage: React.FC<NewCalendarPageProps> = ({
619655
>
620656
<Box sx={{ flexShrink: 0 }}>
621657
<DateCalendar
622-
value={displayMonthYear}
623-
onMonthChange={(newDate) => setDisplayMonthYear(newDate)}
658+
value={viewMode === 'week' ? displayWeek : displayMonthYear}
659+
onMonthChange={(newDate) => {
660+
if (viewMode !== 'week') setDisplayMonthYear(newDate);
661+
}}
624662
onChange={(newDate) => {
625-
if (newDate) setDisplayMonthYear(newDate);
663+
if (!newDate) return;
664+
if (viewMode === 'week') {
665+
setDisplayWeek(getSundayOfWeek(newDate));
666+
} else {
667+
setDisplayMonthYear(newDate);
668+
}
626669
}}
627670
slotProps={{
628671
day: {

0 commit comments

Comments
 (0)