diff --git a/src/components/Profile/components/SchedulePanel/index.tsx b/src/components/Profile/components/SchedulePanel/index.tsx index 8ec122df80..36b3928b3b 100644 --- a/src/components/Profile/components/SchedulePanel/index.tsx +++ b/src/components/Profile/components/SchedulePanel/index.tsx @@ -17,6 +17,7 @@ import { TableBody, DialogActions, Box, + Button, } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import GordonLoader from 'components/Loader'; @@ -26,7 +27,6 @@ import styles from './ScheduleHeader.module.css'; import scheduleService, { CourseEvent, formatTermDescription, Schedule } from 'services/schedule'; import { Profile } from 'services/user'; import academicTermService from 'services/academicTerm'; -import { Button } from '@mui/material'; import { getFinalExamEventsForUserByTerm, formatFinalExamEvent, @@ -39,6 +39,7 @@ type Props = { }; const scheduleOpenKey = 'profile.schedule.isOpen'; + const GordonSchedulePanel = ({ profile, myProf }: Props) => { const [loading, setLoading] = useState(true); const [allSchedules, setAllSchedules] = useState([]); @@ -47,34 +48,59 @@ const GordonSchedulePanel = ({ profile, myProf }: Props) => { const [isScheduleOpen, setIsScheduleOpen] = useState( localStorage.getItem(scheduleOpenKey) !== 'false', ); + const [finalExamOpen, setFinalExamOpen] = useState(false); const [finalExams, setFinalExams] = useState([]); const [finalExamsLoading, setFinalExamsLoading] = useState(false); useEffect(() => { - setLoading(true); + const loadSchedules = async () => { + setLoading(true); + try { + const [allTermSchedules, currentTerm] = await Promise.all([ + scheduleService.getAllTermSchedules(profile.AD_Username), + academicTermService.getCurrentTerm(), + ]); + + const sortedSchedules = [...allTermSchedules].sort( + (a, b) => new Date(b.term.BeginDate).getTime() - new Date(a.term.BeginDate).getTime(), + ); + setAllSchedules(sortedSchedules); - Promise.all([ - scheduleService.getAllTermSchedules(profile.AD_Username), - academicTermService.getCurrentTerm(), - ]).then(([allTermSchedules, currentTerm]) => { - setAllSchedules(allTermSchedules); + const now = new Date(); + const currentStart = new Date(currentTerm.BeginDate); + const currentEnd = new Date(currentTerm.EndDate); - const defaultSchedule = - allTermSchedules.find( + const currentSchedule = sortedSchedules.find( (s) => - s.term.YearCode === currentTerm.YearCode && s.term.TermCode === currentTerm.TermCode, - ) ?? allTermSchedules[0]; + s.term.YearCode === currentTerm.YearCode && + s.term.TermCode === currentTerm.TermCode && + (s.courses?.length ?? 0) > 0, + ); - setSelectedSchedule(defaultSchedule); - setLoading(false); - }); + const futureWithCourses = sortedSchedules.find( + (s) => new Date(s.term.BeginDate) > currentEnd && (s.courses?.length ?? 0) > 0, + ); + + const anyWithCourses = sortedSchedules.find((s) => (s.courses?.length ?? 0) > 0); + + const defaultSchedule = currentSchedule || futureWithCourses || anyWithCourses || null; + setSelectedSchedule(defaultSchedule); + } catch (err) { + console.error('Failed to load schedule or current term:', err); + } finally { + setLoading(false); + } + }; + + loadSchedules(); }, [profile.AD_Username]); const toggleIsScheduleOpen = () => { - setIsScheduleOpen((wasOpen) => { - localStorage.setItem(scheduleOpenKey, String(!wasOpen)); - return !wasOpen; + setIsScheduleOpen((prev) => { + const next = !prev; + localStorage.setItem(scheduleOpenKey, String(next)); + return next; }); }; @@ -96,9 +122,9 @@ const GordonSchedulePanel = ({ profile, myProf }: Props) => { .finally(() => setFinalExamsLoading(false)); }; - return loading ? ( - - ) : ( + if (loading) return ; + + return ( <> { className={`gc360_header ${styles.accordionHeader}`} > - + ) : ( -
+
)} - {allSchedules.length > 0 ? ( + + {allSchedules.length > 0 && ( @@ -141,6 +168,7 @@ const GordonSchedulePanel = ({ profile, myProf }: Props) => { ))} + {selectedSchedule && ( )} - - {selectedSchedule && ( + + + + {selectedSchedule ? ( <> - - {myProf && ( - + {myProf && ( + + Click on Course to add Schedule to Personal Calendar - )} - + + )} { /> + ) : ( + + No schedule available to display. + )} - ) : ( -
)} + {myProf && selectedCourse && selectedSchedule && ( setSelectedCourse(null)} course={selectedCourse} - term={selectedSchedule?.term} + term={selectedSchedule.term} /> )} + setFinalExamOpen(false)} maxWidth="md" fullWidth> Final Exam Schedule @@ -234,4 +268,4 @@ const GordonSchedulePanel = ({ profile, myProf }: Props) => { ); }; -export default GordonSchedulePanel; +export default GordonSchedulePanel; \ No newline at end of file diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index 229a48f92d..95961fade2 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -3,7 +3,7 @@ import GordonSnackbar from 'components/Snackbar'; import { Profile as profileType, isFacStaff as checkIsFacStaff } from 'services/user'; import { useAuthGroups } from 'hooks'; import useNetworkStatus from 'hooks/useNetworkStatus'; -import { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useState, useEffect } from 'react'; import { AuthGroup } from 'services/auth'; import user from 'services/user'; import { @@ -27,7 +27,7 @@ type SnackbarState = { severity: string; open: boolean; link?: string; - linkText?: string; // Add the optional link property + linkText?: string; }; const Profile = ({ profile: propsProfile, myProf }: Props) => { @@ -45,7 +45,7 @@ const Profile = ({ profile: propsProfile, myProf }: Props) => { const createSnackbar = useCallback( (message: string, severity: AlertColor, link?: string, linkText?: string) => { - setSnackbar({ message, severity, open: true, link, linkText }); // Include the link property + setSnackbar({ message, severity, open: true, link, linkText }); }, [], ); @@ -88,8 +88,7 @@ const Profile = ({ profile: propsProfile, myProf }: Props) => { - - {viewerIsPolice ? : null} + {viewerIsPolice && } )} @@ -106,7 +105,7 @@ const Profile = ({ profile: propsProfile, myProf }: Props) => { isOnline={isOnline} createSnackbar={createSnackbar} /> - {viewerIsPolice ? : null} + {viewerIsPolice && } @@ -125,7 +124,7 @@ const Profile = ({ profile: propsProfile, myProf }: Props) => { severity={snackbar.severity as AlertColor} onClose={() => setSnackbar((s) => ({ ...s, open: false }))} link={snackbar.link} - linkText={snackbar.linkText} // Pass the link property to the snackbar + linkText={snackbar.linkText} /> );