@@ -34,7 +34,8 @@ import {
3434 convertIntToDay ,
3535 eventsToEventInstances ,
3636 eventsToNextEventInstance ,
37- getOverlapTime
37+ getOverlapTime ,
38+ getSundayOfWeek
3839} from '../../utils/calendar.utils' ;
3940import { filterEventTransformer } from '../../apis/transformers/calendar.transformer' ;
4041import WarningIcon from '@mui/icons-material/Warning' ;
@@ -43,6 +44,7 @@ import UpcomingMeetingsCard from './UpcomingMeetingsCard';
4344import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline' ;
4445import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked' ;
4546import { EventInstance } from 'shared' ;
47+ import CalendarWeekView from './CalendarWeekView' ;
4648
4749// localStorage key for calendar filters
4850const 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
9198const 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