@@ -17,6 +17,7 @@ function CommunityCalendar() {
1717 const [ showEventModal , setShowEventModal ] = useState ( false ) ;
1818 const [ overflowDate , setOverflowDate ] = useState ( null ) ;
1919 const popupRef = useRef ( null ) ;
20+ const [ calendarView , setCalendarView ] = useState ( 'month' ) ;
2021
2122 const currentDate = new Date ( ) ;
2223 const currentMonth = currentDate . getMonth ( ) ;
@@ -170,6 +171,96 @@ function CommunityCalendar() {
170171 'Full Event' : 'statusFull' ,
171172 } ;
172173
174+ function WeeklyTimeGrid ( { events, selectedDate, onEventClick, darkMode } ) {
175+ const hours = Array . from ( { length : 24 } , ( _ , i ) => i ) ;
176+
177+ // Find the Sunday of the currently selected week
178+ const startOfWeek = useMemo ( ( ) => {
179+ const d = new Date ( selectedDate ) ;
180+ const day = d . getDay ( ) ; // 0 (Sun) to 6 (Sat)
181+ d . setDate ( d . getDate ( ) - day ) ;
182+ return d ;
183+ } , [ selectedDate ] ) ;
184+
185+ // Create an array of 7 Date objects for the header
186+ const weekDays = useMemo ( ( ) => {
187+ return Array . from ( { length : 7 } , ( _ , i ) => {
188+ const day = new Date ( startOfWeek ) ;
189+ day . setDate ( startOfWeek . getDate ( ) + i ) ;
190+ return day ;
191+ } ) ;
192+ } , [ startOfWeek ] ) ;
193+
194+ return (
195+ < div className = { `${ styles . weekGridContainer } ${ darkMode ? styles . weekGridDark : '' } ` } >
196+ { /* HEADER: Day Names and Numbers */ }
197+ < div className = { styles . weekGridHeader } >
198+ < div className = { styles . timeGutter } > </ div >
199+ { weekDays . map ( date => (
200+ < div key = { date . toString ( ) } className = { styles . dayColumnHeader } >
201+ < div className = { styles . dayLabel } >
202+ { date . toLocaleDateString ( 'en-US' , { weekday : 'short' } ) }
203+ </ div >
204+ < div className = { styles . dateLabel } > { date . getDate ( ) } </ div >
205+ </ div >
206+ ) ) }
207+ </ div >
208+
209+ { /* BODY: Time Rows */ }
210+ < div className = { styles . weekGridBody } >
211+ { hours . map ( hour => (
212+ < div key = { hour } className = { styles . hourRow } >
213+ < div className = { styles . timeLabel } >
214+ { hour === 0
215+ ? '12 AM'
216+ : hour > 12
217+ ? `${ hour - 12 } PM`
218+ : hour === 12
219+ ? '12 PM'
220+ : `${ hour } AM` }
221+ </ div >
222+ { weekDays . map ( date => {
223+ // Filter events that happen on THIS day at THIS hour
224+ const cellEvents = events . filter ( e => {
225+ const eventDate = new Date ( e . date ) ;
226+ // Check if date matches and if the hour in "10:00 AM" matches our current row
227+ const eventHour = parseInt ( e . time . split ( ':' ) [ 0 ] ) ;
228+ const isPM = e . time . toLowerCase ( ) . includes ( 'pm' ) ;
229+ const normalizedEventHour =
230+ isPM && eventHour !== 12
231+ ? eventHour + 12
232+ : ! isPM && eventHour === 12
233+ ? 0
234+ : eventHour ;
235+
236+ return (
237+ eventDate . toDateString ( ) === date . toDateString ( ) && normalizedEventHour === hour
238+ ) ;
239+ } ) ;
240+
241+ return (
242+ < div key = { date . toString ( ) } className = { styles . gridCell } >
243+ { cellEvents . map ( event => (
244+ < button
245+ key = { event . id }
246+ type = "button"
247+ className = { styles . gridEvent }
248+ onClick = { ( ) => onEventClick ( event ) }
249+ >
250+ < div className = { styles . gridEventTime } > { event . time } </ div >
251+ < div className = { styles . gridEventTitle } > { event . title } </ div >
252+ </ button >
253+ ) ) }
254+ </ div >
255+ ) ;
256+ } ) }
257+ </ div >
258+ ) ) }
259+ </ div >
260+ </ div >
261+ ) ;
262+ }
263+
173264 // Render event tiles
174265 const tileContent = useCallback (
175266 ( { date, view } ) => {
@@ -189,20 +280,24 @@ function CommunityCalendar() {
189280 key = { e . id }
190281 type = "button"
191282 className = { `${ styles . eventItem } ${ styles [ statusKey ] || '' } ` }
192- onClick = { ( ) => handleEventClick ( e ) }
283+ onClick = { e_obj => {
284+ e_obj . stopPropagation ( ) ;
285+ handleEventClick ( e ) ;
286+ } }
193287 title = { e . title }
194288 >
195289 { e . title }
196290 </ button >
197291 ) ;
198292 } ) }
199-
200293 { hiddenCount > 0 && (
201294 < button
202295 type = "button"
203296 className = { styles . moreEvents }
204- onClick = { ( ) => setOverflowDate ( date ) }
205- title = "View all events"
297+ onClick = { e_obj => {
298+ e_obj . stopPropagation ( ) ;
299+ setOverflowDate ( date ) ;
300+ } }
206301 >
207302 +{ hiddenCount } more
208303 </ button >
@@ -317,6 +412,16 @@ function CommunityCalendar() {
317412 < header className = { calendarClasses . header } >
318413 < h1 > Community Calendar</ h1 >
319414 < div className = { calendarClasses . filters } >
415+ < select
416+ value = { calendarView }
417+ onChange = { e => setCalendarView ( e . target . value ) }
418+ className = { styles . viewSelector }
419+ >
420+ < option value = "month" > Day View (Month)</ option >
421+ < option value = "week" > Week View (Time Grid)</ option >
422+ < option value = "year" > Month View (Year)</ option >
423+ < option value = "decade" > Year View (Decade)</ option >
424+ </ select >
320425 < select value = { filter . type } onChange = { handleFilterChange ( 'type' ) } >
321426 < option value = "all" > All Types</ option >
322427 { uniqueFilterValues . types . map ( t => (
@@ -346,13 +451,25 @@ function CommunityCalendar() {
346451 < CalendarActivitySection />
347452 </ div >
348453 < div className = { calendarClasses . calendarSection } >
349- < ReactCalendar
350- className = { calendarClasses . reactCalendar }
351- tileContent = { tileContent }
352- tileClassName = { tileClassName }
353- onClickDay = { handleDateSelect }
354- value = { selectedDate }
355- />
454+ { calendarView === 'week' ? (
455+ < WeeklyTimeGrid
456+ events = { filteredEvents }
457+ selectedDate = { selectedDate }
458+ onEventClick = { handleEventClick }
459+ darkMode = { darkMode }
460+ />
461+ ) : (
462+ < ReactCalendar
463+ className = { calendarClasses . reactCalendar }
464+ tileContent = { tileContent }
465+ tileClassName = { tileClassName }
466+ onClickDay = { handleDateSelect }
467+ value = { selectedDate }
468+ view = { calendarView }
469+ onViewChange = { ( { view } ) => setCalendarView ( view ) }
470+ />
471+ ) }
472+
356473 < section
357474 className = { `${ styles . selectedDatePanel } ${
358475 darkMode ? styles . selectedDatePanelDarkMode : ''
0 commit comments