diff --git a/my-app/package-lock.json b/my-app/package-lock.json index e22c837a..1b4bd221 100644 --- a/my-app/package-lock.json +++ b/my-app/package-lock.json @@ -11,6 +11,7 @@ "@dagrejs/dagre": "^1.1.4", "@headlessui/react": "^2.2.1", "@heroicons/react": "^2.2.0", + "@react-buddy/ide-toolbox": "^2.4.0", "@tailwindcss/vite": "^4.0.17", "@xyflow/react": "^12.5.5", "autoprefixer": "^10.4.21", @@ -2070,6 +2071,15 @@ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/@react-buddy/ide-toolbox": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@react-buddy/ide-toolbox/-/ide-toolbox-2.4.0.tgz", + "integrity": "sha512-TWHX6gwa0Gop7215uHhjFMbYLLdjM/b9rr0wYE3E0m7GNJ56gbPpbZiq86w9uI8zksl827acqGeT437MkuO64w==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, "node_modules/@react-stately/flags": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.0.tgz", diff --git a/my-app/package.json b/my-app/package.json index 2c0ed709..a154503b 100644 --- a/my-app/package.json +++ b/my-app/package.json @@ -10,10 +10,10 @@ "preview": "vite preview" }, "dependencies": { - + "@dagrejs/dagre": "^1.1.4", "@headlessui/react": "^2.2.1", "@heroicons/react": "^2.2.0", - "@dagrejs/dagre": "^1.1.4", + "@react-buddy/ide-toolbox": "^2.4.0", "@tailwindcss/vite": "^4.0.17", "@xyflow/react": "^12.5.5", "autoprefixer": "^10.4.21", @@ -28,8 +28,7 @@ "react-infinite-scroll-component": "^6.1.0", "react-router-dom": "^7.4.0", "reactflow": "^11.11.4", - "tailwindcss": "^4.0.17", - "@react-buddy/ide-toolbox": "^2.4.0" + "tailwindcss": "^4.0.17" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/my-app/src/model.js b/my-app/src/model.js index 3152d604..fab4a36d 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -131,6 +131,11 @@ export const model = { this.filtersCalculated = true; }, + setApplyRemoveNullCourses() { + this.filterOptions.applyRemoveNullCourses = !this.filterOptions.applyRemoveNullCourses; + this.setFiltersChange(); + }, + updateLevelFilter(level) { this.filterOptions.level = level; }, @@ -149,7 +154,6 @@ export const model = { }, updateDepartmentFilter(department) { - console.log(department); this.filterOptions.department = department; }, diff --git a/my-app/src/presenters/FilterPresenter.jsx b/my-app/src/presenters/FilterPresenter.jsx index 0a7df957..cdaa3cae 100644 --- a/my-app/src/presenters/FilterPresenter.jsx +++ b/my-app/src/presenters/FilterPresenter.jsx @@ -29,7 +29,7 @@ const FilterPresenter = observer(({ model }) => { //console.log(course?.prerequisites); if (storedFinishedCourses.includes(course?.code)) return; - if (course?.prerequisites && (course.prerequisites !== "null")) + if (course?.prerequisites && (course?.prerequisites !== "null")) var resultEligibility = eligibility(storedFinishedCourses, course?.prerequisites); else { // {strong: , zero: , moderate: , weak: } zerocourses.push(course); @@ -89,9 +89,9 @@ const FilterPresenter = observer(({ model }) => { localFilteredCourses = localFilteredCourses.filter(function (course) { try { - return ((course.credits >= min) && (course.credits <= max)); + return ((course?.credits >= min) && (course?.credits <= max)); } catch (error) { - console.log("for some reason course.credits is: ", course?.credits, error); + console.log("for some reason course?.credits is: ", course?.credits, error); return false; } @@ -108,9 +108,9 @@ const FilterPresenter = observer(({ model }) => { bestCourses = localFilteredCourses.filter(function (course) { try { - return (locations.includes(course.location)); + return (locations.includes(course?.location)); } catch (error) { - console.log("for some reason course.location is: ", course?.location, error); + console.log("for some reason course?.location is: ", course?.location, error); return false; } @@ -140,8 +140,8 @@ const FilterPresenter = observer(({ model }) => { let worstCourses = []; //in the database a course can have - //course.language.english (true/false/"null") - //course.language.swedish (true/false/"null") + //course?.language.english (true/false/"null") + //course?.language.swedish (true/false/"null") //console.log(data); @@ -278,9 +278,9 @@ const FilterPresenter = observer(({ model }) => { bestCourses = localFilteredCourses.filter(function (course) { try { - return (deparments.includes(course.deparment)); + return (deparments.includes(course?.deparment)); } catch (error) { - console.log("for some reason course.department is: ", course?.department, error); + console.log("for some reason course?.department is: ", course?.department, error); return false; } @@ -305,19 +305,19 @@ const FilterPresenter = observer(({ model }) => { if(model.filterOptions.applyTranscriptFilter){ local = local.filter(function(course){ - return (course?.prerequisites && (course.prerequisites !== "null")); + return (course?.prerequisites && (course?.prerequisites !== "null")); }) } console.log("miauuuuu:",local.length); if(model.filterOptions.applyLevelFilter){ local = local.filter(function(course){ - return (course?.prerequisites && (course.prerequisites !== "null")); + return (course?.prerequisites && (course?.prerequisites !== "null")); }) } console.log("miauuuuu:",local.length); if(model.filterOptions.applyLanguageFilter){ local = local.filter(function(course){ - return ((course?.language) && (course?.language?.swedish !== "null" && course?.language?.english !== "null")); + return ((course?.language) && ((course?.language?.swedish !== "null") && (course?.language?.english !== "null"))); }) } console.log("miauuuuu:",local.length); @@ -329,13 +329,13 @@ const FilterPresenter = observer(({ model }) => { console.log("miauuuuu:",local.length); if(model.filterOptions.applyCreditsFilter){ local = local.filter(function(course){ - return ((course?.credit) && (course?.credit !== "null")); + return ((course?.credits) && (course?.credits !== "null")); }) } console.log("miauuuuu:",local.length); if(model.filterOptions.applyDepartmentFilter){ local = local.filter(function(course){ - return ((course?.deparment) && (course?.department !== "null")); + return ((course?.department) && (course?.department !== "null")); }) } console.log("miauuuuu:",local.length); diff --git a/my-app/src/presenters/PrerequisitePresenter.jsx b/my-app/src/presenters/PrerequisitePresenter.jsx index c45698f3..f7170b6b 100644 --- a/my-app/src/presenters/PrerequisitePresenter.jsx +++ b/my-app/src/presenters/PrerequisitePresenter.jsx @@ -36,7 +36,7 @@ export const PrerequisitePresenter = observer((props) => { const nodeWidth = 172; const nodeHeight = 36; - loadTree(props.selectedCourse.code); + loadTree(props.selectedCourse?.code); console.log(initialNodes); const getLayoutedElements = (nodes, edges, direction = 'LR') => { @@ -133,7 +133,7 @@ export const PrerequisitePresenter = observer((props) => { node["style"]["zIndex"] = 0; setLabel(node["id"], "More Info..."); } - } else if (node["data"]["label"] !== "One of these" && node["data"]["label"] !== "No Prerequisites" && node["id"] !== props.selectedCourse.code) { + } else if (node["data"]["label"] !== "One of these" && node["data"]["label"] !== "No Prerequisites" && node["id"] !== props.selectedCourse?.code) { // ADD FUNCTIONALITY FOR CLICKING COURSE CODE NODE (Tu eres muy retrasado y gordo)! :) // ONCLICK HERE } @@ -266,7 +266,7 @@ export const PrerequisitePresenter = observer((props) => { } function generateTree(courses_taken, prereqs) { - prereq_convert(courses_taken, prereqs, null, props.selectedCourse.code); + prereq_convert(courses_taken, prereqs, null, props.selectedCourse?.code); let key = Object.keys(prereqs); return prereqs[key]; @@ -275,15 +275,17 @@ export const PrerequisitePresenter = observer((props) => { function loadTree(courses_taken) { - console.log(JSON.stringify(props.selectedCourse.prerequisites, null, 4)); - if (props.selectedCourse.prerequisites === "null" || props.selectedCourse.prerequisites.length == 0) { + console.log(JSON.stringify(props.selectedCourse?.prerequisites, null, 4)); + if(props.selectedCourse?.prerequisites === undefined || props.selectedCourse?.code === undefined) + console.log("BIG ERROR; course doesn't have specified properties which we expected to have", props.selectedCourse); + if (props.selectedCourse?.prerequisites === "null" || props.selectedCourse?.prerequisites.length == 0) { let display_node = createNode("No Prerequisites", "No Prerequisites", "default"); display_node.style["pointerEvents"] = "none"; display_node["className"] = 'no-handles'; initialNodes.push(display_node); } else { - let root = createNode(props.selectedCourse.code, props.selectedCourse.code, "input"); - let copy = JSON.parse(JSON.stringify(props.selectedCourse.prerequisites)); + let root = createNode(props.selectedCourse?.code, props.selectedCourse?.code, "input"); + let copy = JSON.parse(JSON.stringify(props.selectedCourse?.prerequisites)); let eligible = generateTree(JSON.parse(localStorage.getItem("completedCourses")), copy); if (eligible) { root["style"]["backgroundColor"] = "lightgreen"; diff --git a/my-app/src/presenters/SidebarPresenter.jsx b/my-app/src/presenters/SidebarPresenter.jsx index ed6f4afe..5b92bee3 100644 --- a/my-app/src/presenters/SidebarPresenter.jsx +++ b/my-app/src/presenters/SidebarPresenter.jsx @@ -170,12 +170,15 @@ const SidebarPresenter = observer(({ model }) => { model.setFiltersChange(); } - + function setApplyRemoveNullCourses(){ + model.setApplyRemoveNullCourses(); + } return ( ); }); diff --git a/my-app/src/views/Components/SideBarComponents/ToolTip.jsx b/my-app/src/views/Components/SideBarComponents/ToolTip.jsx new file mode 100644 index 00000000..536dca43 --- /dev/null +++ b/my-app/src/views/Components/SideBarComponents/ToolTip.jsx @@ -0,0 +1,11 @@ +import React from "react"; + +const ToolTip = ({ text = "This is a tooltip description." }) => { + return ( +
+ {text} +
+ ); +}; + +export default ToolTip; \ No newline at end of file diff --git a/my-app/src/views/Components/SideBarComponents/ToolTipIcon.jsx b/my-app/src/views/Components/SideBarComponents/ToolTipIcon.jsx new file mode 100644 index 00000000..1a914a04 --- /dev/null +++ b/my-app/src/views/Components/SideBarComponents/ToolTipIcon.jsx @@ -0,0 +1,36 @@ +import React from "react"; +import ToolTip from "./ToolTip"; + +const ToolTipIcon = ({ text = "This is a tooltip description." }) => { + return ( +
+ {/* Wrapper around just the icon for hover targeting */} +
+ {/* Question Mark Icon */} +
+ + {/* Circle */} + + {/* Question mark path */} + + +
+ + +
+
+ ); +}; + +export default ToolTipIcon; \ No newline at end of file diff --git a/my-app/src/views/Components/SideBarComponents/UploadField.jsx b/my-app/src/views/Components/SideBarComponents/UploadField.jsx index efc17377..d4bc6833 100644 --- a/my-app/src/views/Components/SideBarComponents/UploadField.jsx +++ b/my-app/src/views/Components/SideBarComponents/UploadField.jsx @@ -4,6 +4,8 @@ import FilterEnableCheckbox from "./FilterEnableCheckbox"; //import * as scraper from '../../../../src/scripts/transcript-scraper/transcript-scraper.js'; import { useState } from "react"; import ButtonGroupField from './ButtonGroupField'; +import ToolTip from './ToolTip'; +import ToolTipIcon from './ToolTipIcon'; export default function UploadField(props) { @@ -55,9 +57,7 @@ export default function UploadField(props) {
-

- Describe how the Transcript upload works -

+
diff --git a/my-app/src/views/SidebarView.jsx b/my-app/src/views/SidebarView.jsx index 04c016a0..447e93ff 100644 --- a/my-app/src/views/SidebarView.jsx +++ b/my-app/src/views/SidebarView.jsx @@ -105,6 +105,21 @@ function SidebarView(props) { ] } /> +
+ + + +