From fb099ce99395b53512623f43225470da566b5894 Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:44:32 -0400 Subject: [PATCH 1/8] add search by instructor --- app/src/constants/frontend.ts | 1 + app/src/constants/soc.ts | 4 +++- app/src/scripts/soc/soc.tsx | 12 +++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/constants/frontend.ts b/app/src/constants/frontend.ts index 0667c10..9269907 100644 --- a/app/src/constants/frontend.ts +++ b/app/src/constants/frontend.ts @@ -15,6 +15,7 @@ export function getSectionColor(sectionInd: number): string { const SearchByStringExampleMap = new Map([ ["course-code", "MAS3114"], ["course-title", "Linear Algebra"], + ["instructor", "Huang"] ]); export function getSearchByStringExample(searchByStr: string): string { diff --git a/app/src/constants/soc.ts b/app/src/constants/soc.ts index 3c3d3cf..e2c65da 100644 --- a/app/src/constants/soc.ts +++ b/app/src/constants/soc.ts @@ -64,13 +64,15 @@ export function getProgramString(program: Program): string { export enum SearchBy { COURSE_CODE = "Course Code", COURSE_TITLE = "Course Title", + INSTRUCTOR = "Instructor" } -export const SearchBys = [SearchBy.COURSE_CODE, SearchBy.COURSE_TITLE]; +export const SearchBys = [SearchBy.COURSE_CODE, SearchBy.COURSE_TITLE, SearchBy.INSTRUCTOR]; const SearchByStringMap = new Map([ ["course-code", SearchBy.COURSE_CODE], ["course-title", SearchBy.COURSE_TITLE], + ["instructor", SearchBy.INSTRUCTOR] ]); export function getSearchBy(searchByStr: string): SearchBy { diff --git a/app/src/scripts/soc/soc.tsx b/app/src/scripts/soc/soc.tsx index 7ed305d..2ab6c96 100644 --- a/app/src/scripts/soc/soc.tsx +++ b/app/src/scripts/soc/soc.tsx @@ -131,6 +131,9 @@ export abstract class SOC_Generic { return this.courses.filter((c) => c.name.toUpperCase().includes(upperPhrase), ); + } else if (searchBy === SearchBy.INSTRUCTOR) { + console.log(this.courses); + return this.courses.filter((c) => c.sections.some((s) => s.instructors.some((inst) => inst.toUpperCase().indexOf(upperPhrase) != -1))); } throw new Error("Unhandled SearchBy."); } @@ -161,9 +164,9 @@ export class SOC_API extends SOC_Generic { termStr: string | undefined; programStr: string | undefined; } = { - termStr: undefined, - programStr: undefined, - }, + termStr: undefined, + programStr: undefined, + }, ): Promise { if (!termStr || !programStr) throw new Error("Term or program string was not provided."); @@ -216,8 +219,7 @@ export class SOC_API extends SOC_Generic { return Promise.resolve(); } console.log( - `Fetching by ${searchBy} for "${phrase}"${ - lcn > 0 ? ` @ #${lcn}` : "" + `Fetching by ${searchBy} for "${phrase}"${lcn > 0 ? ` @ #${lcn}` : "" }`, ); From ff6ebb2ae4337f0ca959af8d39c8df6f86f1ec67 Mon Sep 17 00:00:00 2001 From: Robert Conde Date: Thu, 28 Sep 2023 22:15:10 -0400 Subject: [PATCH 2/8] Ran Prettier --- app/src/constants/frontend.ts | 2 +- app/src/constants/soc.ts | 10 +++++++--- app/src/scripts/soc/soc.tsx | 18 ++++++++++++------ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/src/constants/frontend.ts b/app/src/constants/frontend.ts index 9269907..14dcfbf 100644 --- a/app/src/constants/frontend.ts +++ b/app/src/constants/frontend.ts @@ -15,7 +15,7 @@ export function getSectionColor(sectionInd: number): string { const SearchByStringExampleMap = new Map([ ["course-code", "MAS3114"], ["course-title", "Linear Algebra"], - ["instructor", "Huang"] + ["instructor", "Huang"], ]); export function getSearchByStringExample(searchByStr: string): string { diff --git a/app/src/constants/soc.ts b/app/src/constants/soc.ts index e2c65da..e5227cf 100644 --- a/app/src/constants/soc.ts +++ b/app/src/constants/soc.ts @@ -64,15 +64,19 @@ export function getProgramString(program: Program): string { export enum SearchBy { COURSE_CODE = "Course Code", COURSE_TITLE = "Course Title", - INSTRUCTOR = "Instructor" + INSTRUCTOR = "Instructor", } -export const SearchBys = [SearchBy.COURSE_CODE, SearchBy.COURSE_TITLE, SearchBy.INSTRUCTOR]; +export const SearchBys = [ + SearchBy.COURSE_CODE, + SearchBy.COURSE_TITLE, + SearchBy.INSTRUCTOR, +]; const SearchByStringMap = new Map([ ["course-code", SearchBy.COURSE_CODE], ["course-title", SearchBy.COURSE_TITLE], - ["instructor", SearchBy.INSTRUCTOR] + ["instructor", SearchBy.INSTRUCTOR], ]); export function getSearchBy(searchByStr: string): SearchBy { diff --git a/app/src/scripts/soc/soc.tsx b/app/src/scripts/soc/soc.tsx index 2ab6c96..30084a7 100644 --- a/app/src/scripts/soc/soc.tsx +++ b/app/src/scripts/soc/soc.tsx @@ -132,8 +132,13 @@ export abstract class SOC_Generic { c.name.toUpperCase().includes(upperPhrase), ); } else if (searchBy === SearchBy.INSTRUCTOR) { - console.log(this.courses); - return this.courses.filter((c) => c.sections.some((s) => s.instructors.some((inst) => inst.toUpperCase().indexOf(upperPhrase) != -1))); + return this.courses.filter((c) => + c.sections.some((s) => + s.instructors.some((inst) => + inst.toUpperCase().includes(upperPhrase), + ), + ), + ); } throw new Error("Unhandled SearchBy."); } @@ -164,9 +169,9 @@ export class SOC_API extends SOC_Generic { termStr: string | undefined; programStr: string | undefined; } = { - termStr: undefined, - programStr: undefined, - }, + termStr: undefined, + programStr: undefined, + }, ): Promise { if (!termStr || !programStr) throw new Error("Term or program string was not provided."); @@ -219,7 +224,8 @@ export class SOC_API extends SOC_Generic { return Promise.resolve(); } console.log( - `Fetching by ${searchBy} for "${phrase}"${lcn > 0 ? ` @ #${lcn}` : "" + `Fetching by ${searchBy} for "${phrase}"${ + lcn > 0 ? ` @ #${lcn}` : "" }`, ); From a49aef95efbe8c4329ee22556b086e82da9354f9 Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:06:30 -0400 Subject: [PATCH 3/8] Update ScheduleDisplay.tsx --- app/src/components/ScheduleDisplay.tsx | 175 +++++++++++++------------ 1 file changed, 88 insertions(+), 87 deletions(-) diff --git a/app/src/components/ScheduleDisplay.tsx b/app/src/components/ScheduleDisplay.tsx index cd6ccc7..5b0ecd5 100644 --- a/app/src/components/ScheduleDisplay.tsx +++ b/app/src/components/ScheduleDisplay.tsx @@ -12,10 +12,9 @@ import { GrPersonalComputer } from "react-icons/gr"; interface Props { schedule: Schedule; + pin: (sch: Schedule) => void; } -interface States {} - // TODO: reconsider what to store type MeetTimeInfo = { meetTime: MeetTime; @@ -24,7 +23,7 @@ type MeetTimeInfo = { sectionIsOnline: boolean; }; -export default class ScheduleDisplay extends Component { +export default class ScheduleDisplay extends Component { // TODO: redo this (it is *disgusting*); maybe there is a library that does the work render() { const schedule = this.props.schedule, @@ -179,103 +178,105 @@ export default class ScheduleDisplay extends Component { const onlineSections: Section[] = schedule.filter((s) => s.isOnline); return ( -
-
-
- {schedule.map((sec: Section, s: number) => ( -
- ({s + 1}) Sec. {sec.number} [ - {sec.courseCode}] -
- ))} + <> +
+
+
+ {schedule.map((sec: Section, s: number) => ( +
+ ({s + 1}) Sec. {sec.number} [ + {sec.courseCode}] +
+ ))} +
-
-
-
-
- {[...Array(periodCounts.all).keys()] - .map((p) => p + 1) - .map((p) => ( -
- - {MeetTime.formatPeriod( - p, - schedule.term, - )} - -
- ))} +
+
+
+ {[...Array(periodCounts.all).keys()] + .map((p) => p + 1) + .map((p) => ( +
+ + {MeetTime.formatPeriod( + p, + schedule.term + )} + +
+ ))} - {onlineSections.length > 0 && ( -
+ {onlineSections.length > 0 && (
- ️ +
+ ️ +
-
- )} + )} +
-
-
-
- {divs} - {onlineSections.length > 0 && ( -
-
-
- {onlineSections.map( - (sec: Section, ind: number) => ( -
- {sec.displayName} - - {1 + ind} - -
- ), - )} +
+
+ {divs} + {onlineSections.length > 0 && ( +
+
+
+ {onlineSections.map( + (sec: Section, ind: number) => ( +
+ {sec.displayName} + + {1 + ind} + +
+ ) + )} +
-
- )} + )} +
-
+ + ); } } From 92a2d7356c4033928ae896e8680cfba102656064 Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:07:55 -0400 Subject: [PATCH 4/8] Update MultipleScheduleDisplay.tsx --- app/src/components/MultipleScheduleDisplay.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/components/MultipleScheduleDisplay.tsx b/app/src/components/MultipleScheduleDisplay.tsx index 13472c4..7ea4d82 100644 --- a/app/src/components/MultipleScheduleDisplay.tsx +++ b/app/src/components/MultipleScheduleDisplay.tsx @@ -7,6 +7,7 @@ const NUM_PER_PAGE = 25; interface Props { schedules: Schedule[]; numPerPage?: number; + pin: (sch: Schedule) => void; } export default function MultipleScheduleDisplay(props: Props) { @@ -26,7 +27,7 @@ export default function MultipleScheduleDisplay(props: Props) { {schedulesToShow.map((schedule: Schedule, s) => (
Schedule #{s + 1} - +
))} From d359ca1f9339efd9e02c7e1aa87b5807b483880b Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:08:32 -0400 Subject: [PATCH 5/8] Update MultipleSelectionDisplay.tsx --- app/src/components/MultipleSelectionDisplay.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/components/MultipleSelectionDisplay.tsx b/app/src/components/MultipleSelectionDisplay.tsx index f0037f9..7f781d4 100644 --- a/app/src/components/MultipleSelectionDisplay.tsx +++ b/app/src/components/MultipleSelectionDisplay.tsx @@ -8,6 +8,7 @@ interface Props { newSelection: () => void; handleRemove: (sectionToRemove: Section) => void; handleDeleteSelection: (ind: number) => void; + } export default function MultipleSelectionDisplay(props: Props) { From 9bd87326dcd5119c56b301def2d2628e966f4baa Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:09:19 -0400 Subject: [PATCH 6/8] Update ScheduleBuilder.tsx --- app/src/components/ScheduleBuilder.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/components/ScheduleBuilder.tsx b/app/src/components/ScheduleBuilder.tsx index c3f97d5..8dd9cc2 100644 --- a/app/src/components/ScheduleBuilder.tsx +++ b/app/src/components/ScheduleBuilder.tsx @@ -26,6 +26,7 @@ interface States { selections: Selection[]; schedules: Schedule[]; showAddCourse: boolean; + pinnedSchedules: Schedule[]; } const defaultState: States = { @@ -36,6 +37,7 @@ const defaultState: States = { selections: getDefaultSelections(), schedules: [], showAddCourse: false, + pinnedSchedules: [] }; export default class ScheduleBuilder extends Component { @@ -139,6 +141,14 @@ export default class ScheduleBuilder extends Component { } // TODO: make separate functions + togglePin(sch: Schedule) { + const pinned = this.state.pinnedSchedules; + if (pinned.some(s => arrayEquals(s, sch))) { + this.setState({pinnedSchedules: pinned.filter(s => !arrayEquals(s, sch))}); + } else { + this.setState({pinnedSchedules: [...pinned, sch]}); + } + } newSelection(ind: number = -1, sectionsToAdd: Section[] = []) { if (ind == -1) { this.setState({ @@ -248,6 +258,7 @@ export default class ScheduleBuilder extends Component { handleDrop={this.handleDrop.bind(this)} newSelection={this.newSelection.bind(this)} handleRemove={this.handleRemove.bind(this)} + pinnedSchedules={this.togglePin.bind(this)} handleDeleteSelection={this.handleDeleteSelection.bind( this, )} @@ -259,6 +270,7 @@ export default class ScheduleBuilder extends Component {
@@ -267,3 +279,4 @@ export default class ScheduleBuilder extends Component { ); } } + From 2aa17b57e61b47913ae9fafe842428b6380d4fde Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:24:03 -0500 Subject: [PATCH 7/8] Update ScheduleBuilder.tsx --- app/src/components/ScheduleBuilder.tsx | 453 +++++++++++-------------- 1 file changed, 191 insertions(+), 262 deletions(-) diff --git a/app/src/components/ScheduleBuilder.tsx b/app/src/components/ScheduleBuilder.tsx index 8dd9cc2..e366cfa 100644 --- a/app/src/components/ScheduleBuilder.tsx +++ b/app/src/components/ScheduleBuilder.tsx @@ -1,9 +1,15 @@ -import { Component } from "react"; -import { Course, Section, SOC_API, SOC_Generic } from "@scripts/soc"; +//Importing React, necessary components, other class files, and any dependencies - used ChatGPT for proper syntax with the 'from ""'. +import React, { useState, useEffect } from "react"; import { - Schedule, - ScheduleGenerator, - Selection, + Course, + Section, + SOC_API, + SOC_Generic, +} from "@scripts/soc"; +import { + Schedule, + ScheduleGenerator, + Selection, } from "@scripts/scheduleGenerator"; import SectionPicker from "@components/SectionPicker"; import MultipleSelectionDisplay from "@components/MultipleSelectionDisplay"; @@ -13,270 +19,193 @@ import { API_Filters } from "@scripts/apiTypes"; import { arrayEquals, notEmpty, take } from "@scripts/utils"; import { LIMIT_VALUES, LIMITS } from "@constants/scheduleGenerator"; +//getDefaultSelections: returns an array of schedules selected +//defaultProgram: default program value (this was already specified in the original code file) const getDefaultSelections = () => [new Selection()]; const defaultProgram = "CWSP"; -interface Props {} - -interface States { - filters: API_Filters | null; - soc: SOC_Generic | null; - generator: ScheduleGenerator | null; - limit: number; - selections: Selection[]; - schedules: Schedule[]; - showAddCourse: boolean; - pinnedSchedules: Schedule[]; -} - -const defaultState: States = { - filters: null, - soc: null, - generator: null, - limit: LIMIT_VALUES[0], - selections: getDefaultSelections(), - schedules: [], - showAddCourse: false, - pinnedSchedules: [] -}; - -export default class ScheduleBuilder extends Component { - constructor(props: Props) { - super(props); - this.state = defaultState; +//function to build schedules and accomplish what the ScheduleBuilder class had to achieve before +const ScheduleBuilder = () => { + //filters: API Filters fetched from the UF_SOC_API and are set to null at this time + const [filters, setFilters] = useState(null); + //soc: Schedule of Courses and is set to null to start off with (since no schedules yet built) + const [soc, setSOCState] = useState(null); + //generator: generation of schedules through user usage of the website + const [generator, setGenerator] = useState(null); + //limit: maximum limit of schedules that can be generated; set initially to LIMIT_VALUES[0] + const [limit, setLimit] = useState(LIMIT_VALUES[0]); + //selections: user-selected course sections + const [selections, setSelections] = useState( + getDefaultSelections() + ); + //schedules: initial list of schedules with no schedules at the beginning + const [schedules, setSchedules] = useState([]); + //showAddCourse: if a course needs to be added to a schedule, the AddCourse button would be implemented + const [showAddCourse, setShowAddCourse] = useState(false); + //pinnedSchedules: if a course wants to be pinned by the user, it will be added to the Schedule array + const [pinnedSchedules, setPinnedSchedules] = useState([]); + + useEffect(() => { + //fetch filters from UF_SOC_API and set the SOCState with the default program + UF_SOC_API.fetchFilters().then(async (fetchedFilters) => { + setFilters(fetchedFilters); + await setSOCState(fetchedFilters.terms[0].CODE, defaultProgram); + }); + }, []); + //allows for loading selected courses into the schedule generator + useEffect(() => { + if (generator) { + generator.loadSelections( + selections.filter((sel: Selection) => sel.length > 0) + ); + + const newSchedules: Schedule[] = take( + limit, + generator.yieldSchedules() + ); + setSchedules(newSchedules); + //output whether the schedule was changed or not changed + if (schedules !== newSchedules) { + console.log("New schedules", newSchedules); + } else { + console.log("Same schedules"); + } } - - reset() { - console.log("Resetting Schedule Builder"); - this.setState({ - selections: getDefaultSelections(), - schedules: [], - }); - } - - componentDidMount() { - // TODO: implement retry upon fetch error - UF_SOC_API.fetchFilters().then(async (filters) => { - this.setState({ filters }); - await this.setSOC(filters.terms[0].CODE, defaultProgram); - }); - } - - componentDidUpdate( - _prevProps: Readonly, - prevState: Readonly, - ) { - // If limit was changed or a section was added/removed from a section, generate new schedules - if ( - this.state.limit != prevState.limit || - !arrayEquals( - this.state.selections.filter(notEmpty), - prevState.selections.filter(notEmpty), - ) - ) { - if (this.state.generator) { - // Make sure generator is not null - this.state.generator.loadSelections( - // Generate schedules from non-empty selections - this.state.selections.filter( - (sel: Selection) => sel.length > 0, - ), - ); - - const newSchedules: Schedule[] = [ - ...take( - this.state.limit, - this.state.generator.yieldSchedules(), - ), - ]; - this.setState({ schedules: newSchedules }); - console.log( - "Selections were changed, so schedules have been regenerated", - newSchedules, - ); - - // If schedules changed, log schedules - if (prevState.schedules != newSchedules) - console.log("New schedules", newSchedules); - else console.log("Same schedules"); - } - } - } - - async setSOC(termStr: string, programStr: string) { - console.log(`Setting SOC to "${termStr}" for "${programStr}"`); - await SOC_API.initialize({ termStr, programStr }).then((soc) => - this.setState({ - soc: soc, - generator: new ScheduleGenerator(soc), - }), + }, [limit, selections, generator, schedules]); + //reset the schedule building system + const reset = () => { + console.log("Resetting Schedule Builder"); + setSelections(getDefaultSelections()); + setSchedules([]); + }; + //initialize soc variable + const setSOC = async (termStr: string, programStr: string) => { + console.log(`Setting SOC to "${termStr}" for "${programStr}"`); + const socInstance = await SOC_API.initialize({ termStr, programStr }); + setSOCState(socInstance); + }; + //manages dropping (removing of) a course or schedule + const handleDrop = (ind: number, uid: string) => { + if (soc) { + const item: Section | Course | null = soc.get(uid); + if (item) { + let sectionsToTryAdd: Section[]; + if (item instanceof Course) sectionsToTryAdd = item.sections; + else sectionsToTryAdd = [item]; + + const sectionsToAdd: Section[] = sectionsToTryAdd.filter( + (section) => + !selections.some((sel) => sel.includes(section)) ); - this.reset(); // Make sure to only show info from the current SOC - } - - async handleDrop(ind: number, uid: string) { - if (this.state.soc) { - // Make sure SOC exists - const item: Section | Course | null = this.state.soc.get(uid); - console.log("Handling drop; will try to add", item); - - if (item) { - // Make sure a match was found (not null) - // Get the section(s) to try to add to selection - let sectionsToTryAdd: Section[]; - if (item instanceof Course) sectionsToTryAdd = item.sections; - else sectionsToTryAdd = [item]; - - // Get the sections that have not been added to a selection - const sectionsToAdd: Section[] = sectionsToTryAdd.filter( - (section) => - !this.state.selections.some( - // TODO: extract to a Selections class - (sel) => sel.includes(section), - ), - ); - this.newSelection(ind, sectionsToAdd); // Add the section that have not been added - } - } + newSelection(ind, sectionsToAdd); + } } - - // TODO: make separate functions - togglePin(sch: Schedule) { - const pinned = this.state.pinnedSchedules; - if (pinned.some(s => arrayEquals(s, sch))) { - this.setState({pinnedSchedules: pinned.filter(s => !arrayEquals(s, sch))}); - } else { - this.setState({pinnedSchedules: [...pinned, sch]}); - } + }; + //manages the pin status of a schedule + const togglePin = (sch: Schedule) => { + const pinned = pinnedSchedules; + if (pinned.some((s) => arrayEquals(s, sch))) { + setPinnedSchedules(pinned.filter((s) => !arrayEquals(s, sch))); + } else { + setPinnedSchedules([...pinned, sch]); } - newSelection(ind: number = -1, sectionsToAdd: Section[] = []) { - if (ind == -1) { - this.setState({ - selections: [...this.state.selections, new Selection()], - }); - return; - } - - const newSelections = this.state.selections.map((sel, i) => { - if (i == ind) return [...sel, ...sectionsToAdd]; - return sel; - }); - this.setState({ selections: newSelections }); + }; + //handles adding of new courses or schedules + const newSelection = (ind: number = -1, sectionsToAdd: Section[] = []) => { + if (ind === -1) { + setSelections([...selections, new Selection()]); + return; } - - handleDeleteSelection(ind: number) { - let newSelections = this.state.selections.filter((_sel, i) => i != ind); - if (newSelections.length == 0) newSelections = getDefaultSelections(); - - this.setState({ selections: newSelections }); - } - - handleRemove(sectionToRemove: Section) { - const newSelections = this.state.selections.map((sel) => - sel.filter((sec) => sec != sectionToRemove), - ); - this.setState({ selections: newSelections }); - } - - render() { - // Show loading screen if filters/terms haven't been fetched yet - if (this.state.filters === null) - return ( -
-

Fetching latest semester information...

-
- ); - if (this.state.soc === null) - // Make sure SOC is set + const newSelections = selections.map((sel, i) => { + if (i === ind) return [...sel, ...sectionsToAdd]; + return sel; + }); + setSelections(newSelections); + }; + //manages deletion of a course selection + const handleDeleteSelection = (ind: number) => { + let newSelections = selections.filter((_sel, i) => i !== ind); + if (newSelections.length === 0) newSelections = getDefaultSelections(); + setSelections(newSelections); + }; + //manages removal of a course selection + const handleRemove = (sectionToRemove: Section) => { + const newSelections = selections.map((sel) => + sel.filter((sec) => sec !== sectionToRemove) + ); + setSelections(newSelections); + }; + //sample loading messages - used ChatGPT for assistance with this part + return ( +
+
+

+ 🐊 Swamp Scheduler 📆 +

+ +
+ + - this.setSOC(e.target.value, defaultProgram) - } - disabled={false} - > - {this.state.filters?.terms.map((t) => { - const { term, year } = SOC_Generic.decodeTermString( - t.CODE, - ); - return ( - - ); - })} - - - -
- -
- - {/* Main of Builder */} -
- {/* Picker */} -
- -
- - {/* Selected */} -
- -
- - {/* Generated Schedules */} -
- -
-
-
- ); - } -} - + })} + + + +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +}; +//export the function in other parts - the key purpose behind this task +export default ScheduleBuilder; From 5ae1fd98a72644ef401b2498bc102ef882e4ad85 Mon Sep 17 00:00:00 2001 From: Harshil Pahuja <71945852+harshil162@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:01:35 -0500 Subject: [PATCH 8/8] Update ScheduleBuilder.tsx --- app/src/components/ScheduleBuilder.tsx | 96 ++++++++++++++------------ 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/app/src/components/ScheduleBuilder.tsx b/app/src/components/ScheduleBuilder.tsx index e366cfa..db33df0 100644 --- a/app/src/components/ScheduleBuilder.tsx +++ b/app/src/components/ScheduleBuilder.tsx @@ -1,23 +1,25 @@ //Importing React, necessary components, other class files, and any dependencies - used ChatGPT for proper syntax with the 'from ""'. import React, { useState, useEffect } from "react"; import { - Course, - Section, SOC_API, SOC_Generic, + Course, + Section } from "@scripts/soc"; import { + Selection, Schedule, ScheduleGenerator, - Selection, -} from "@scripts/scheduleGenerator"; -import SectionPicker from "@components/SectionPicker"; -import MultipleSelectionDisplay from "@components/MultipleSelectionDisplay"; -import MultipleScheduleDisplay from "@components/MultipleScheduleDisplay"; +} +from "@scripts/scheduleGenerator"; import { UF_SOC_API } from "@scripts/api"; import { API_Filters } from "@scripts/apiTypes"; import { arrayEquals, notEmpty, take } from "@scripts/utils"; import { LIMIT_VALUES, LIMITS } from "@constants/scheduleGenerator"; +import SectionPicker from "@components/SectionPicker"; +import MultipleSelectionDisplay from "@components/MultipleSelectionDisplay"; +import MultipleScheduleDisplay from "@components/MultipleScheduleDisplay"; + //getDefaultSelections: returns an array of schedules selected //defaultProgram: default program value (this was already specified in the original code file) @@ -28,23 +30,23 @@ const defaultProgram = "CWSP"; const ScheduleBuilder = () => { //filters: API Filters fetched from the UF_SOC_API and are set to null at this time const [filters, setFilters] = useState(null); - //soc: Schedule of Courses and is set to null to start off with (since no schedules yet built) - const [soc, setSOCState] = useState(null); //generator: generation of schedules through user usage of the website const [generator, setGenerator] = useState(null); + //soc: Schedule of Courses and is set to null to start off with (since no schedules yet built) + const [soc, setSOCState] = useState(null); //limit: maximum limit of schedules that can be generated; set initially to LIMIT_VALUES[0] const [limit, setLimit] = useState(LIMIT_VALUES[0]); - //selections: user-selected course sections - const [selections, setSelections] = useState( - getDefaultSelections() - ); //schedules: initial list of schedules with no schedules at the beginning const [schedules, setSchedules] = useState([]); - //showAddCourse: if a course needs to be added to a schedule, the AddCourse button would be implemented - const [showAddCourse, setShowAddCourse] = useState(false); //pinnedSchedules: if a course wants to be pinned by the user, it will be added to the Schedule array const [pinnedSchedules, setPinnedSchedules] = useState([]); - + //showAddCourse: if a course needs to be added to a schedule, the AddCourse button would be implemented + const [showAddCourse, setShowAddCourse] = useState(false); + //selections: user-selected course sections + const [selections, setSelections] = useState( + getDefaultSelections() + ); + useEffect(() => { //fetch filters from UF_SOC_API and set the SOCState with the default program UF_SOC_API.fetchFilters().then(async (fetchedFilters) => { @@ -65,18 +67,18 @@ const ScheduleBuilder = () => { ); setSchedules(newSchedules); //output whether the schedule was changed or not changed - if (schedules !== newSchedules) { - console.log("New schedules", newSchedules); - } else { + if (schedules === newSchedules) { console.log("Same schedules"); + } else { + console.log("New schedules", newSchedules); } } }, [limit, selections, generator, schedules]); //reset the schedule building system const reset = () => { - console.log("Resetting Schedule Builder"); setSelections(getDefaultSelections()); setSchedules([]); + console.log("Reset Schedule Builder"); }; //initialize soc variable const setSOC = async (termStr: string, programStr: string) => { @@ -101,31 +103,19 @@ const ScheduleBuilder = () => { } } }; - //manages the pin status of a schedule - const togglePin = (sch: Schedule) => { - const pinned = pinnedSchedules; - if (pinned.some((s) => arrayEquals(s, sch))) { - setPinnedSchedules(pinned.filter((s) => !arrayEquals(s, sch))); - } else { - setPinnedSchedules([...pinned, sch]); - } - }; + //handles adding of new courses or schedules const newSelection = (ind: number = -1, sectionsToAdd: Section[] = []) => { - if (ind === -1) { - setSelections([...selections, new Selection()]); - return; + if (ind !== -1) { + const newSelections = selections.map((sel, i) => { + if (i === ind) return [...sel, ...sectionsToAdd]; + return sel; + }); + } + else{ + setSelections([...selections, new Selection()]); + return; } - const newSelections = selections.map((sel, i) => { - if (i === ind) return [...sel, ...sectionsToAdd]; - return sel; - }); - setSelections(newSelections); - }; - //manages deletion of a course selection - const handleDeleteSelection = (ind: number) => { - let newSelections = selections.filter((_sel, i) => i !== ind); - if (newSelections.length === 0) newSelections = getDefaultSelections(); setSelections(newSelections); }; //manages removal of a course selection @@ -135,7 +125,23 @@ const ScheduleBuilder = () => { ); setSelections(newSelections); }; - //sample loading messages - used ChatGPT for assistance with this part + //manages deletion of a course selection + const handleDeleteSelection = (ind: number) => { + let newSelections = selections.filter((_sel, i) => i !== ind); + if (newSelections.length === 0) + newSelections = getDefaultSelections(); + setSelections(newSelections); + }; + //manages the pin status of a schedule + const togglePin = (sch: Schedule) => { + const pinned = pinnedSchedules; + if (pinned.some((s) => arrayEquals(s, sch))) { + setPinnedSchedules(pinned.filter((s) => !arrayEquals(s, sch))); + } else { + setPinnedSchedules([...pinned, sch]); + } + }; + //sample loading messages - used ChatGPT for assistance with this section return (
@@ -187,11 +193,11 @@ const ScheduleBuilder = () => {