Repository: icssc/AntAlmanac (ts)

Issue:
Load schedules faster
For users with lots of old schedules across different terms, loading is hella slow because we fetch _all_ the class info before finishing the load. I think we can speed this up by lazy loading the course info for schedules that aren't the default one, and maybe make requests to PPAPI concurrently.

EDIT: actually lazy-loading is pointless when we're doing everything concurrently since all requests seem to take roughly the same amount of time so all we really need is parallelization (correct me if I'm wrong here pls).
![image](https://github.com/icssc/AntAlmanac/assets/48658337/8f9c8ae5-5708-48b6-878f-7af54d773a9d)


Pull request description:
Parallelize Schedule Load Websoc Requests
## Summary
Saves a bunch of time on schedule loading by making PPAPI requests for different terms concurrently.

Before:
![image](https://github.com/icssc/AntAlmanac/assets/48658337/9af60850-75b5-4a0d-bcdf-6af4dd2fe35d)

After:
![image](https://github.com/icssc/AntAlmanac/assets/48658337/e89f1788-23f4-428d-abe0-8d713d4a4dcb)

## Test Plan
Verify with network inspector that requests are being done concurrently, and also that nothing breaks.

## Issues
Closes #712 

<!-- [Optional]
## Future Followup
-->


Patch:
diff --git a/.github/reviewer-lottery.yml b/.github/reviewer-lottery.yml
index 8afaf524..87f8309f 100644
--- a/.github/reviewer-lottery.yml
+++ b/.github/reviewer-lottery.yml
@@ -7,9 +7,7 @@ groups:
       - bevm0
       - MinhxNguyen7
       - stevenguyukai
-      - johnlorenzini
       - Douglas-Hong
       - teresa-liang
-      - mina03333
       - JacE070
-      
\ No newline at end of file
+      
diff --git a/apps/antalmanac/src/components/RightPane/AddedCourses/AddedCoursePane.tsx b/apps/antalmanac/src/components/RightPane/AddedCourses/AddedCoursePane.tsx
index facdb8b1..0981b0d8 100644
--- a/apps/antalmanac/src/components/RightPane/AddedCourses/AddedCoursePane.tsx
+++ b/apps/antalmanac/src/components/RightPane/AddedCourses/AddedCoursePane.tsx
@@ -54,7 +54,9 @@ function getCourses() {
     for (const course of currentCourses) {
         let formattedCourse = formattedCourses.find(
             (needleCourse) =>
-                needleCourse.courseNumber === course.courseNumber && needleCourse.deptCode === course.deptCode
+                needleCourse.courseNumber === course.courseNumber &&
+                needleCourse.deptCode === course.deptCode &&
+                needleCourse.courseTitle === course.courseTitle
         );
 
         if (formattedCourse) {
@@ -306,7 +308,7 @@ function AddedSectionsGrid() {
                 <Grid container spacing={2} padding={0}>
                     {courses.map((course) => {
                         return (
-                            <Grid item md={12} xs={12} key={course.deptCode + course.courseNumber}>
+                            <Grid item md={12} xs={12} key={course.deptCode + course.courseNumber + course.courseTitle}>
                                 <SectionTableLazyWrapper
                                     courseDetails={course}
                                     term={course.term}
diff --git a/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx b/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx
index 50f76183..8ee66fc0 100644
--- a/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx
+++ b/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useState, useEffect } from 'react';
+import { useCallback, useState, useEffect, useMemo } from 'react';
 import {
     Box,
     Button,
@@ -39,6 +39,10 @@ function RenameScheduleDialog(props: ScheduleNameDialogProps) {
 
     const [name, setName] = useState(scheduleNames[index]);
 
+    const disabled = useMemo(() => {
+        return name?.trim() === '';
+    }, [name]);
+
     const handleCancel = useCallback(() => {
         onClose?.({}, 'escapeKeyDown');
         setName(scheduleNames[index]);
@@ -93,10 +97,10 @@ function RenameScheduleDialog(props: ScheduleNameDialogProps) {
             </DialogContent>
 
             <DialogActions>
-                <Button onClick={handleCancel} color={isDarkMode() ? 'secondary' : 'primary'}>
+                <Button onClick={handleCancel} color={'inherit'}>
                     Cancel
                 </Button>
-                <Button onClick={submitName} variant="contained" color="primary" disabled={name.trim() === ''}>
+                <Button onClick={submitName} variant="contained" color="primary" disabled={disabled}>
                     Rename Schedule
                 </Button>
             </DialogActions>
diff --git a/apps/antalmanac/src/stores/Schedules.ts b/apps/antalmanac/src/stores/Schedules.ts
index 60fb6792..6443b9b0 100644
--- a/apps/antalmanac/src/stores/Schedules.ts
+++ b/apps/antalmanac/src/stores/Schedules.ts
@@ -461,17 +461,14 @@ export class Schedules {
 
             // Get the course info for each course
             const courseInfoDict = new Map<string, { [sectionCode: string]: CourseInfo }>();
-            for (const [term, courseSet] of Object.entries(courseDict)) {
-                const sectionCodes = Array.from(courseSet);
-                // Code from ImportStudyList
-                const courseInfo = getCourseInfo(
-                    await queryWebsoc({
-                        term: term,
-                        sectionCodes: sectionCodes.join(','),
-                    })
-                );
+
+            const websocRequests = Object.entries(courseDict).map(async ([term, courseSet]) => {
+                const sectionCodes = Array.from(courseSet).join(',');
+                const courseInfo = getCourseInfo(await queryWebsoc({ term, sectionCodes }));
                 courseInfoDict.set(term, courseInfo);
-            }
+            });
+
+            await Promise.all(websocRequests);
 
             // Map course info to courses and transform shortened schedule to normal schedule
             for (const shortCourseSchedule of saveState.schedules) {


Test patch:
diff --git a/apps/antalmanac/tests/schedule.test.ts b/apps/antalmanac/tests/schedule.test.ts
deleted file mode 100644
index 09894443..00000000
--- a/apps/antalmanac/tests/schedule.test.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { describe, test, expect } from 'vitest';
-import { Schedules } from '../src/stores/Schedules';
-
-describe('schedule logic', () => {
-    const scheduleStore = new Schedules();
-
-    test('no error when loading undefined schedule', () => {
-        expect(() => scheduleStore.getScheduleName(69)).not.toThrowError();
-    });
-});
diff --git a/apps/antalmanac/tests/schedule.test.tsx b/apps/antalmanac/tests/schedule.test.tsx
new file mode 100644
index 00000000..41e4d890
--- /dev/null
+++ b/apps/antalmanac/tests/schedule.test.tsx
@@ -0,0 +1,16 @@
+import { describe, test, expect } from 'vitest';
+import { render } from '@testing-library/react';
+import { Schedules } from '$stores/Schedules';
+import RenameScheduleDialog from '$components/dialogs/RenameSchedule';
+
+describe('schedule logic', () => {
+    const scheduleStore = new Schedules();
+
+    test('no error when loading undefined schedule', () => {
+        expect(() => scheduleStore.getScheduleName(100)).not.toThrowError();
+    });
+
+    test('does not error if schedule name is undefined', () => {
+        expect(() => render(<RenameScheduleDialog index={100} open />)).not.toThrowError();
+    });
+});