Skip to content
102 changes: 68 additions & 34 deletions src/components/Profile/components/SchedulePanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
TableBody,
DialogActions,
Box,
Button,
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import GordonLoader from 'components/Loader';
Expand All @@ -26,7 +27,6 @@
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,
Expand All @@ -39,6 +39,7 @@
};

const scheduleOpenKey = 'profile.schedule.isOpen';

const GordonSchedulePanel = ({ profile, myProf }: Props) => {
const [loading, setLoading] = useState(true);
const [allSchedules, setAllSchedules] = useState<Schedule[]>([]);
Expand All @@ -47,34 +48,59 @@
const [isScheduleOpen, setIsScheduleOpen] = useState<boolean>(
localStorage.getItem(scheduleOpenKey) !== 'false',
);

const [finalExamOpen, setFinalExamOpen] = useState(false);
const [finalExams, setFinalExams] = useState<FinalExamEvent[]>([]);
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();

Check warning on line 70 in src/components/Profile/components/SchedulePanel/index.tsx

View workflow job for this annotation

GitHub Actions / build

'now' is assigned a value but never used
const currentStart = new Date(currentTerm.BeginDate);

Check warning on line 71 in src/components/Profile/components/SchedulePanel/index.tsx

View workflow job for this annotation

GitHub Actions / build

'currentStart' is assigned a value but never used
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;
});
};

Expand All @@ -96,9 +122,9 @@
.finally(() => setFinalExamsLoading(false));
};

return loading ? (
<GordonLoader />
) : (
if (loading) return <GordonLoader />;

return (
<>
<Accordion
expanded={isScheduleOpen}
Expand All @@ -113,13 +139,14 @@
className={`gc360_header ${styles.accordionHeader}`}
>
<Grid container className={styles.header}>
<CardHeader title={'Course Schedule'} />
<CardHeader title="Course Schedule" />
</Grid>
</AccordionSummary>
) : (
<div></div>
<div />
)}
{allSchedules.length > 0 ? (

{allSchedules.length > 0 && (
<AccordionDetails>
<Grid container justifyContent="center" spacing={4}>
<Grid item xs={12} lg={3}>
Expand All @@ -141,6 +168,7 @@
))}
</TextField>
</Grid>

<Grid item style={{ minWidth: 180 }}>
{selectedSchedule && (
<Button
Expand All @@ -153,37 +181,43 @@
</Button>
)}
</Grid>
<Grid lg={7}></Grid>
{selectedSchedule && (

<Grid lg={7} />

{selectedSchedule ? (
<>
<Grid item className={styles.addCalendarInfoText}>
{myProf && (
<Typography className={styles.addCalendarInfoText}>
{myProf && (
<Grid item className={styles.addCalendarInfoText}>
<Typography color="secondary">
Click on Course to add Schedule to Personal Calendar
</Typography>
)}
</Grid>
</Grid>
)}
<Grid item xs={12} lg={10}>
<GordonScheduleCalendar
schedule={selectedSchedule}
onSelectEvent={setSelectedCourse}
/>
</Grid>
</>
) : (
<Grid item xs={12}>
<Typography color="error">No schedule available to display.</Typography>
</Grid>
)}
</Grid>
</AccordionDetails>
) : (
<div></div>
)}
</Accordion>

{myProf && selectedCourse && selectedSchedule && (
<ScheduleDialog
onClose={() => setSelectedCourse(null)}
course={selectedCourse}
term={selectedSchedule?.term}
term={selectedSchedule.term}
/>
)}

<Dialog open={finalExamOpen} onClose={() => setFinalExamOpen(false)} maxWidth="md" fullWidth>
<Box sx={{ bgcolor: 'primary.main', color: 'primary.contrastText', px: 3, py: 2 }}>
<Typography variant="h6">Final Exam Schedule</Typography>
Expand Down Expand Up @@ -234,4 +268,4 @@
);
};

export default GordonSchedulePanel;
export default GordonSchedulePanel;
13 changes: 6 additions & 7 deletions src/components/Profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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) => {
Expand All @@ -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 });
},
[],
);
Expand Down Expand Up @@ -88,8 +88,7 @@ const Profile = ({ profile: propsProfile, myProf }: Props) => {
<Grid item xs={12} lg={10}>
<Grid container spacing={2}>
<OfficeInfoList profile={profile} myProf={myProf} />

{viewerIsPolice ? <EmergencyInfoList username={profile.AD_Username} /> : null}
{viewerIsPolice && <EmergencyInfoList username={profile.AD_Username} />}
</Grid>
</Grid>
)}
Expand All @@ -106,7 +105,7 @@ const Profile = ({ profile: propsProfile, myProf }: Props) => {
isOnline={isOnline}
createSnackbar={createSnackbar}
/>
{viewerIsPolice ? <EmergencyInfoList username={profile.AD_Username} /> : null}
{viewerIsPolice && <EmergencyInfoList username={profile.AD_Username} />}
</Grid>
</Grid>

Expand All @@ -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}
/>
</Grid>
);
Expand Down
Loading