!H#TVO>am^U+{P7;
zyD{Eo{M7O1Cm2r1nQ(NX#zfx4{i%f1q|_a$UwBcxYF=L&H?1nIm(Ss^;lB|03swob
zg+9U+!e{9|=_}H^GJG;tW^`xzWtL_3h&ZAO(W|V`tPNT3v!k-NW%uVKKf(;Atg`$ORi$*S5
zyXaeqpyWcSb7@)Wm&N?W7k(Y_Yx%GJOVXFLEp=bIei?C@c-f8Re#^J7&{|Qr;_=GS
zE9+M=SCy=KyL#g4^JT7O8`ewX)joo#S?1-W9m3vCgq>({8=prF+00*`DWnQ}^E37rw7~KWl&8
z0jmR52N?%T>XG_s^}P+54IPcijqQiR4mCGklvm=#9b&oDRMmaYBSpV_D
z<9#P2Cwfk1oP69ovH9+)F{iGz#I&@X4nKYFOz@dgXW3_upYu6)yg*nZzSBfb#vU!
zj$49TUAJ>?zq(U!=kwh;_Xzh&?rYvJdtmgS`VYH5c6YdU9DNx0u=P>gqq~p!k6%2=
zd-A1o{!`l1vS+5xYPwvyj&uiiUw%IJdFKnsi_bm9e`@_%_0sm`fxrC!YV94<+xbfR
zs{i%kHwJIEy>)%t+!x*V;9c&!&+kh<7<}0Nk@fNHr=(BMK2P~V`cnSY?rYPx@Nf6}
zbNl-xJSk7{D}cdd6k+#@Q?9e_Ic{~pr=
z|88yquxAV0enEYWaR5Zq0EqVl=*W?SZD6ma*jLJp2=@USi1(U77rUF6*;oe<)2_EZ7vL(l#+;c9n^`746
zTDHjHaQ9|BNKlFf*VVYfND?QotoV%a2p+)2g92^A96Wonfd6|?fr|v2{|@>J*XF-P
zoO-v;UQC4!bFfW_K63?PCg7~`fbK%=I+NJjxhnXG#!O9zo}ZnFUBu%~Eh=`|wX+dX
zK?GL;a`#ut
zQi`_`>|ITdSSUT1n7_fh)@)qIMx@=q-I*9y`x_LNn09spfwMq@E^McAQxN*|
z^(G6jX}8^LteF+Mh-eeZWKUeht_nqgi)!?k5&|MDp6|1?PF&TR?NYQBl
zHihuL=dR=7vRI_(yo-=rlYuMnYPh>v=GTe&ebnGPkfQMZ5+!bq;6LD@B8D4o3fvU9
zDR5KZrocoM7}F`tledkOw&WibN{pw9)ztNdYY0e@l8WnUR2Vt$1B!SAIX+j{^*wHf
z!B7HfwDT9pk&KB0f>TKT!xpb63ysRRAb)C|uSEV@*?|h23^Xdu!E1?T%FCKkaI{EK
zSpk|F7|T3sWUZrtMkP}auK56i2-)WlQ4nqiYA^&!1gXh*-}uJ`?yGBsaRnyTec#~=
z0(=0=zJYw!zlU?5!y(7|ColyS*cBA<0c0%3Ja;5}*?`fpLWa+vZ=o!32c{rn!~$bK
zfP1jZ17?j1i~@zI1?VGQ4*v}pQ#6Ec1#_n03+PibdsJXhB#7qoL@AsOT0y^Htc5kX
z3dvsCa}YctimP}9e07klae_P`ENgTXlD+o=6S^kLdSx1RF>7`0tFwr%uWf;1f^GK!
zbyUd3+HFF1dYxT^?@_=CoGMuR6X+tM@@dlL$z(nONAAmBY$CqE$7!={9fC38+>oIm
zn}{E6O(zaPm}suZ(3nj`Ej3?Q0`Pk=ci6s()Tk9HW+nBF3tOX2dy?NfNsCQedlbmD
zh)20rGmRq`W9~9!r`5u&H=Vku+QCeLW4)4$u$L3g2S_5
zTZ&22K-&Z?m!gu;r=-D(0`fgKVQn%jXkOA_bq67MSV-V^fLtn+)Hnq!K+#DGuyEUv
zukfdZi_oY2XYN3L1Gx*OZ(*M#b6s1avA^r)5?oM3eh+W7Yrwx;Q?uWoaJL6<0?HcX
z&`5#*g0FBB3KP2GJw{a#!{Sh);}duU`9GxgAn*UjPt+S0=&hFPd;kCd07*qoM6N<$
Ef+;!RM*si-
literal 0
HcmV?d00001
diff --git a/frontend/src/app/account/Account.module.css b/frontend/src/app/account/Account.module.css
new file mode 100644
index 0000000..e7cf6b9
--- /dev/null
+++ b/frontend/src/app/account/Account.module.css
@@ -0,0 +1,35 @@
+
+.Row {
+ display: flex;
+ flex-direction: row;
+}
+
+.Column {
+ display: flex;
+ flex-direction: column;
+}
+
+.AccountPage {
+ position: absolute;
+ top: 75px;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ width: 100%;
+ padding-top: 50px;
+ padding-bottom: 200px;
+}
+
+.AccountContent {
+ width: 600px; /* Adjust the width as needed */
+ padding: 20px;
+ background-color: white; /* Optional, just to make the box visible */
+ border-radius: 10px; /* Optional, for rounded corners */
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Optional, for a subtle shadow */
+
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start; /* Ensures text and elements inside are left-aligned */
+}
diff --git a/frontend/src/app/account/meta-inputs/MetaInputs.module.css b/frontend/src/app/account/meta-inputs/MetaInputs.module.css
new file mode 100644
index 0000000..dc3d033
--- /dev/null
+++ b/frontend/src/app/account/meta-inputs/MetaInputs.module.css
@@ -0,0 +1,90 @@
+
+
+.Row {
+ display: flex;
+ flex-direction: row;
+}
+
+.Column {
+ display: flex;
+ flex-direction: column;
+}
+
+.InputContainer {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-end;
+}
+
+.Label {
+ font-weight: bold;
+ margin-right: 4px;
+ margin-bottom: 3px;
+}
+
+.InputBox {
+ height: 10px;
+ padding: 4px;
+ border: 2px solid #ccc;
+ border-radius: 5px;
+ font-size: 14px;
+ transition: border-color 0.3s ease-in-out;
+}
+
+.InputBox:focus {
+ border-color: #82beff; /* Blue border on focus */
+ outline: none;
+}
+
+.LanguageLevelBox {
+ height: 24px; /* Matches InputBox height */
+ padding: 5px 7px; /* Matches InputBox padding */
+ border: 2px solid #ccc; /* Matches InputBox border */
+ border-radius: 5px; /* Matches InputBox border-radius */
+ font-size: 14px; /* Matches InputBox font-size */
+ background-color: white;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ box-sizing: border-box;
+ color: black;
+ position: relative;
+ transition: border-color 0.3s ease-in-out;
+}
+
+.LanguageLevel:hover {
+ border-color: #aaa;
+}
+
+.LanguageLevelOptions {
+ position: absolute;
+ background-color: #fff;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ top: 100%;
+ left: 0;
+ margin-top: 5px;
+ z-index: 9999;
+ /* width: 90px; */
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
+ max-height: 200px;
+ overflow-y: auto;
+ font-size: 12px;
+ box-sizing: border-box;
+}
+
+.LanguageLevelOptions div {
+ padding: 8px;
+ cursor: pointer;
+ color: black;
+ background-color: white;
+}
+
+.LanguageLevelOptions div:hover {
+ background-color: #f0f0f0;
+}
+
+.SelectedTerm {
+ background-color: #93c7ff !important; /* Light blue background for the selected term */
+ color: black; /* Optional: change text color for selected term */
+}
\ No newline at end of file
diff --git a/frontend/src/app/account/meta-inputs/MetaInputs.tsx b/frontend/src/app/account/meta-inputs/MetaInputs.tsx
new file mode 100644
index 0000000..c442537
--- /dev/null
+++ b/frontend/src/app/account/meta-inputs/MetaInputs.tsx
@@ -0,0 +1,103 @@
+
+"use client";
+import { useState, useEffect, useRef } from "react";
+import Style from "./MetaInputs.module.css";
+
+const languageList: string[] = ["Spanish", "French", "German", "Chinese", "Japanese", "Italian", "Latin", "Greek"];
+const levelList: string[] = ["L1", "L2", "L3", "L4", "L5"];
+
+function LanguagePlacement(){
+ const [languageDropdownVisible, setLanguageDropdownVisible] = useState(false);
+ const [levelDropdownVisible, setLevelDropdownVisible] = useState(false);
+ const [selectedLanguage, setSelectedLanguage] = useState("");
+ const [selectedLevel, setSelectedLevel] = useState("");
+
+ const languageDropdownRef = useRef(null);
+ const levelDropdownRef = useRef(null);
+
+ // Click outside handler
+ const handleClickOutside = (event: MouseEvent) => {
+ if (languageDropdownRef.current && !languageDropdownRef.current.contains(event.target as Node)) {
+ setLanguageDropdownVisible(false);
+ }
+ if (levelDropdownRef.current && !levelDropdownRef.current.contains(event.target as Node)) {
+ setLevelDropdownVisible(false);
+ }
+ };
+
+ // Attach event listener when dropdowns are open
+ useEffect(() => {
+ if (languageDropdownVisible || levelDropdownVisible) {
+ document.addEventListener("mousedown", handleClickOutside);
+ } else {
+ document.removeEventListener("mousedown", handleClickOutside);
+ }
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, [languageDropdownVisible, levelDropdownVisible]);
+
+ return (
+
+
+
Language Placement:
+
setLanguageDropdownVisible(!languageDropdownVisible)}>
+ {selectedLanguage}
+ {languageDropdownVisible && (
+
+ {languageList.map((lang, index) => (
+
{ setSelectedLanguage(lang); setLanguageDropdownVisible(false); }} className={lang === selectedLanguage ? Style.SelectedLanguageLevel : ""}>
+ {lang}
+
+ ))}
+
+ )}
+
+
setLevelDropdownVisible(!levelDropdownVisible)}>
+ {selectedLevel}
+ {levelDropdownVisible && (
+
+ {levelList.map((level, index) => (
+
{ setSelectedLevel(level); setLevelDropdownVisible(false); }} className={level === selectedLevel ? Style.SelectedLanguageLevel : ""}>
+ {level}
+
+ ))}
+
+ )}
+
+
+
+ );
+}
+
+
+
+function FirstShelf() {
+ const [formData, setFormData] = useState({
+ name: "",
+ gradYear: "",
+ languagePlacement: "",
+ });
+
+ const handleChange = (e: any) => {
+ setFormData({ ...formData, [e.target.name]: e.target.value });
+ };
+
+ return (
+
+ );
+}
+
+export default FirstShelf;
\ No newline at end of file
diff --git a/frontend/src/app/account/page.tsx b/frontend/src/app/account/page.tsx
new file mode 100644
index 0000000..99924e5
--- /dev/null
+++ b/frontend/src/app/account/page.tsx
@@ -0,0 +1,26 @@
+
+import Style from "./Account.module.css";
+import NavBar from "@/components/navbar/NavBar";
+
+import FirstShelf from "./meta-inputs/MetaInputs";
+
+function Account(){
+ return(
+
+
+
+
+
+ Profile
+
+
+ Configure basic degree data.
+
+
+
+
+
+ )
+}
+
+export default Account;
\ No newline at end of file
diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx
index 6c893e5..4eb3ab4 100644
--- a/frontend/src/app/login/page.tsx
+++ b/frontend/src/app/login/page.tsx
@@ -4,6 +4,7 @@ import { useRouter } from "next/navigation";
import Style from "./Login.module.css";
import { useAuth } from "../providers";
+import NavBar from "@/components/navbar/NavBar";
function Login()
{
@@ -22,7 +23,12 @@ function Login()
setAuth({ loggedIn: true });
setUser(data);
- router.push("/graduation");
+ if(!data.onboard){
+ router.push("/account");
+ }else{
+ router.push("/graduation");
+ }
+
} catch (error) {
console.error("❌ Login error:", error);
}
@@ -31,6 +37,7 @@ function Login()
return (
+
Plan Your Major @ Yale
diff --git a/frontend/src/app/onboard/Onboard.module.css b/frontend/src/app/onboard/Onboard.module.css
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/src/app/onboard/page.tsx b/frontend/src/app/onboard/page.tsx
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/src/components/navbar/NavBar.module.css b/frontend/src/components/navbar/NavBar.module.css
index a0dc20d..95ce719 100644
--- a/frontend/src/components/navbar/NavBar.module.css
+++ b/frontend/src/components/navbar/NavBar.module.css
@@ -42,8 +42,23 @@
}
.Logo {
- /* width: 150px;
- height: auto; */
margin-right: 10px;
margin-left: 20px;
+}
+
+.Circle {
+ width: 35px;
+ height: 35px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: white;
+ border-radius: 50%;
+ border: 2px solid transparent; /* Default border is invisible */
+
+ transition: background-color 0.3s ease-in-out, border-color 0.3s ease-in-out;
+}
+
+.Circle:hover {
+ border-color: #cce5ff; /* Blue border appears on hover */
}
\ No newline at end of file
diff --git a/frontend/src/components/navbar/NavBar.tsx b/frontend/src/components/navbar/NavBar.tsx
index 2fdadc2..c0806ad 100644
--- a/frontend/src/components/navbar/NavBar.tsx
+++ b/frontend/src/components/navbar/NavBar.tsx
@@ -1,17 +1,50 @@
"use client";
-import Image from "next/image";
import Style from "./NavBar.module.css";
-import PageLinks from "./PageLinks";
-function NavBar({utility}: {utility?: React.ReactNode}) {
+import { usePathname } from "next/navigation";
+import Image from "next/image";
+import Link from "next/link";
+
+function AccountButton() {
+ return(
+
+
+
+ );
+}
+
+function PageLinks()
+{
+ const pathname = usePathname();
+
+ return(
+
+
+ Graduation
+
+
+ Courses
+
+
+ Majors
+
+
+
+
+
+ );
+}
+
+
+function NavBar({utility, loggedIn = true }: { utility?: React.ReactNode; loggedIn?: boolean }) {
return(
{utility}
-
+ {loggedIn &&
}
);
}
diff --git a/frontend/src/components/navbar/PageLinks.tsx b/frontend/src/components/navbar/PageLinks.tsx
deleted file mode 100644
index 13a9d62..0000000
--- a/frontend/src/components/navbar/PageLinks.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-
-"use client";
-import { usePathname } from "next/navigation";
-import Link from "next/link";
-import Style from "./NavBar.module.css";
-
-function PageLinks()
-{
- const pathname = usePathname();
-
- return(
-
-
- Graduation
-
-
- Courses
-
-
- Majors
-
-
- );
-}
-
-export default PageLinks;
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index 32dfeb7..bbf09d1 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -4,7 +4,7 @@ import { User } from "./../types/type-user";
export const Ryan: User = {
name: "Ryan",
netID: "rgg32",
- onboard: true,
+ onboard: false,
FYP: {
studentCourses: [
{ term: 202403, status: "DA", course: { codes: ["CPSC 201"], title: "Intro To Computer Science", credit: 1, dist: ["QR"], seasons: [] } },
From 9084ba9c53db3f56f39b2a0b8ed5ab98cd966f3e Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Sun, 23 Feb 2025 17:26:08 -0500
Subject: [PATCH 10/38] arrangement
---
.../app/account/meta-inputs/MetaInputs.tsx | 2 +-
frontend/src/app/courses/CoursesUtils.tsx | 78 +++++---------
frontend/src/app/courses/page.tsx | 6 +-
frontend/src/app/courses/years/YearBox.tsx | 2 +-
.../courses/years/semester/SemesterBox.tsx | 2 +-
.../add-course/AddCourseButton.module.css | 28 ++++-
.../semester/add-course/AddCourseButton.tsx | 100 ++++++++++--------
frontend/src/app/providers.tsx | 11 +-
frontend/src/database/data-catalog.ts | 10 ++
frontend/src/database/data-cpsc.ts | 86 +++++++++++++++
frontend/src/database/data-user.ts | 44 +++++---
frontend/src/types/type-program.ts | 40 +++++--
frontend/src/types/type-user.ts | 18 +++-
13 files changed, 287 insertions(+), 140 deletions(-)
create mode 100644 frontend/src/database/data-cpsc.ts
diff --git a/frontend/src/app/account/meta-inputs/MetaInputs.tsx b/frontend/src/app/account/meta-inputs/MetaInputs.tsx
index c442537..00f103a 100644
--- a/frontend/src/app/account/meta-inputs/MetaInputs.tsx
+++ b/frontend/src/app/account/meta-inputs/MetaInputs.tsx
@@ -82,7 +82,7 @@ function FirstShelf() {
};
return (
-
+
Name
diff --git a/frontend/src/app/courses/CoursesUtils.tsx b/frontend/src/app/courses/CoursesUtils.tsx
index 2747480..0a341f4 100644
--- a/frontend/src/app/courses/CoursesUtils.tsx
+++ b/frontend/src/app/courses/CoursesUtils.tsx
@@ -1,57 +1,27 @@
-
-import { StudentCourse, StudentSemester, StudentYear } from "@/types/type-user";
-import { IsTermActive } from "@/utils/CourseDisplay";
-
-export function BuildStudentYears(studentCourses: StudentCourse[]): StudentYear[] {
- const grades = ["First-Year", "Sophomore", "Junior", "Senior"];
- const studentYears: StudentYear[] = grades.map(grade => ({
- grade,
- studentSemesters: [],
- active: true, // Default to true, will update later
- }));
-
- studentCourses.sort((a, b) => a.term - b.term);
- const semesterMap: Map = new Map();
-
- for (const course of studentCourses) {
- if (!semesterMap.has(course.term)) {
- semesterMap.set(course.term, {
- term: course.term,
- studentCourses: [],
- active: IsTermActive(course.term)
- });
- }
- semesterMap.get(course.term)!.studentCourses.push(course);
- }
-
- const studentSemesters = Array.from(semesterMap.values()).sort((a, b) => a.term - b.term);
-
- let yearIndex = 0;
- let termsInYear = 0;
-
- for (const semester of studentSemesters) {
- const isSummer = semester.term % 100 === 2;
-
- if (!isSummer) {
- if (termsInYear >= 2 && yearIndex < 3) {
- yearIndex++;
- termsInYear = 0;
- }
- termsInYear++;
- }
-
- studentYears[yearIndex].studentSemesters.push(semester);
- }
-
- // Determine `active` status for each StudentYear
- for (let i = 0; i < studentYears.length - 1; i++) {
- const nextYear = studentYears[i + 1]; // Look ahead to the next year
-
- if (nextYear.studentSemesters.some(sem => !sem.active)) {
- studentYears[i].active = false;
- }
- }
+import { User, StudentSemester, StudentYear } from "@/types/type-user";
+
+export function BuildStudentYears(user: User): StudentYear[]
+{
+ const { studentTermArrangement, studentCourses } = user.FYP;
+
+ const firstYearTerms = studentTermArrangement.first_year;
+ const sophomoreTerms = studentTermArrangement.sophomore;
+ const juniorTerms = studentTermArrangement.junior;
+ const seniorTerms = studentTermArrangement.senior;
+
+ const buildSemesters = (terms: number[]): StudentSemester[] => {
+ return terms.map(term => ({
+ term,
+ studentCourses: studentCourses.filter(course => course.term === term),
+ }));
+ };
+
+ const studentYears: StudentYear[] = [
+ { grade: "First-Year", studentSemesters: buildSemesters(firstYearTerms) },
+ { grade: "Sophomore", studentSemesters: buildSemesters(sophomoreTerms) },
+ { grade: "Junior", studentSemesters: buildSemesters(juniorTerms) },
+ { grade: "Senior", studentSemesters: buildSemesters(seniorTerms) },
+ ];
return studentYears;
}
-
diff --git a/frontend/src/app/courses/page.tsx b/frontend/src/app/courses/page.tsx
index 07e44a5..c237f74 100644
--- a/frontend/src/app/courses/page.tsx
+++ b/frontend/src/app/courses/page.tsx
@@ -19,12 +19,12 @@ function Courses(){
const [columns, setColumns] = useState(true);
const toggleColumns = () => { setColumns(!columns); }
- const [studentYears, setStudentYears] = useState(() => BuildStudentYears(user.FYP.studentCourses));
+ const [studentYears, setStudentYears] = useState(() => BuildStudentYears(user));
const [renderedYears, setRenderedYears] = useState([]);
useEffect(() => {
- setStudentYears(BuildStudentYears(user.FYP.studentCourses));
- }, [user.FYP.studentCourses]);
+ setStudentYears(BuildStudentYears(user));
+ }, [user]);
useEffect(() => {
const newRenderedYears = studentYears.map((studentYear: StudentYear, index: number) => (
diff --git a/frontend/src/app/courses/years/YearBox.tsx b/frontend/src/app/courses/years/YearBox.tsx
index 96e1372..6a0d9a9 100644
--- a/frontend/src/app/courses/years/YearBox.tsx
+++ b/frontend/src/app/courses/years/YearBox.tsx
@@ -36,7 +36,7 @@ function YearBox(props: { edit: boolean, columns: boolean, studentYear: StudentY
{renderedSemesters}
- {(props.edit && props.studentYear.active) &&
}
+ {(props.edit && (props.studentYear.studentSemesters.length < 3)) && }
);
diff --git a/frontend/src/app/courses/years/semester/SemesterBox.tsx b/frontend/src/app/courses/years/semester/SemesterBox.tsx
index e0af037..b8be76a 100644
--- a/frontend/src/app/courses/years/semester/SemesterBox.tsx
+++ b/frontend/src/app/courses/years/semester/SemesterBox.tsx
@@ -38,7 +38,7 @@ function SemesterBox(props: { edit: boolean, studentSemester: StudentSemester, u
{renderedCourses}
- {(props.edit && IsTermActive(props.studentSemester.term)) &&
}
+ {props.edit && }
);
diff --git a/frontend/src/app/courses/years/semester/add-course/AddCourseButton.module.css b/frontend/src/app/courses/years/semester/add-course/AddCourseButton.module.css
index 46a67f9..86542a7 100644
--- a/frontend/src/app/courses/years/semester/add-course/AddCourseButton.module.css
+++ b/frontend/src/app/courses/years/semester/add-course/AddCourseButton.module.css
@@ -59,9 +59,29 @@
border-color: #aaa;
}
+.ResultBox {
+ border: 1px solid #ccc;
+ padding: 0 8px;
+ background-color: white;
+ cursor: pointer;
+ border-radius: 4px;
+ font-size: 12px;
+ height: 22px;
+ width: 60px;
+ display: flex;
+ align-items: center;
+ box-sizing: border-box;
+ color: black;
+ position: relative;
+ transition: border-color 0.3s ease;
+}
+.ResultBox:hover {
+ border-color: #aaa;
+}
+
/* */
-.TermOptions {
+.DropdownOptions {
position: absolute;
background-color: #fff;
border: 1px solid #ccc;
@@ -78,18 +98,18 @@
box-sizing: border-box;
}
-.TermOptions div {
+.DropdownOptions div {
padding: 8px;
cursor: pointer;
color: black;
background-color: white;
}
-.TermOptions div:hover {
+.DropdownOptions div:hover {
background-color: #f0f0f0;
}
-.SelectedTerm {
+.SelectedDropdownOption {
background-color: #93c7ff !important; /* Light blue background for the selected term */
color: black; /* Optional: change text color for selected term */
}
diff --git a/frontend/src/app/courses/years/semester/add-course/AddCourseButton.tsx b/frontend/src/app/courses/years/semester/add-course/AddCourseButton.tsx
index 567ab5c..bffdeaf 100644
--- a/frontend/src/app/courses/years/semester/add-course/AddCourseButton.tsx
+++ b/frontend/src/app/courses/years/semester/add-course/AddCourseButton.tsx
@@ -3,19 +3,19 @@ import { useRef, useState, useEffect } from "react";
import Style from "./AddCourseButton.module.css";
import { User, StudentCourse } from "@/types/type-user";
-import { getCatalogCourse } from "@/database/data-catalog";
+import { getCatalogCourse, getCatalogTerms } from "@/database/data-catalog";
interface AddCourseDisplay {
active: boolean;
- dropVis: boolean;
+ termDropVis: boolean;
+ resultDropVis: boolean;
}
-const terms = [202203, 202301];
-
function executeAddCourse(
props: { term: number; user: User; setUser: Function },
inputRef: React.RefObject,
selectedTerm: number,
+ selectedResult: string,
setAddDisplay: Function
){
if(inputRef.current){
@@ -24,16 +24,11 @@ function executeAddCourse(
if(targetCourse){
const status = selectedTerm === props.term ? "DA" : "MA";
- const newCourse: StudentCourse = { course: targetCourse, status, term: props.term };
+ const newCourse: StudentCourse = { course: targetCourse, status, term: props.term, result: selectedResult };
- const updatedSemesters = props.user.FYP.studentSemesters.map((semester) => {
- if (semester.season === selectedTerm) {
- return { ...semester, studentCourses: [...semester.studentCourses, newCourse] };
- }
- return semester;
- });
+ const updatedCourses = [...props.user.FYP.studentCourses, newCourse];
- props.setUser({ ...props.user, FYP: { ...props.user.FYP, studentSemesters: updatedSemesters } });
+ props.setUser({ ...props.user, FYP: { ...props.user.FYP, studentCourses: updatedCourses } });
setAddDisplay((prevState: AddCourseDisplay) => ({ ...prevState, active: false }));
}
}
@@ -44,8 +39,12 @@ function AddCourseButton(props: { term: number; user: User; setUser: Function })
const inputRef = useRef(null);
const addRef = useRef(null);
- const [addDisplay, setAddDisplay] = useState({ active: false, dropVis: false });
- const [selectedTerm, setSelectedTerm] = useState(props.term);
+ const [addDisplay, setAddDisplay] = useState({ active: false, termDropVis: false, resultDropVis: false });
+ const [selectedTerm, setSelectedTerm] = useState(props.term);
+ const [selectedResult, setSelectedResult] = useState("");
+ const resultOptions = ["GRADE", "CR", "D/F"];
+
+ const catalogTerms = getCatalogTerms()
useEffect(() => {
if(addDisplay.active){
@@ -54,30 +53,30 @@ function AddCourseButton(props: { term: number; user: User; setUser: Function })
}
return () => {
- if(addDisplay.active){
- document.removeEventListener("mousedown", handleClickOutside);
- }
+ if(addDisplay.active){
+ document.removeEventListener("mousedown", handleClickOutside);
+ }
};
}, [addDisplay]);
- const handleClickOutside = (event: MouseEvent) => {
+ const handleClickOutside = (event: MouseEvent) => {
if(addRef.current && !addRef.current.contains(event.target as Node)){
- if(addDisplay.dropVis){
- setAddDisplay((prevState) => ({...prevState, dropVis: false}));
- setTimeout(() => {
- if(inputRef.current){
- inputRef.current.focus();
- }
- }, 0);
+ if(addDisplay.termDropVis || addDisplay.resultDropVis){
+ setAddDisplay((prevState) => ({...prevState, termDropVis: false, resultDropVis: false}));
+ setTimeout(() => {
+ if(inputRef.current){
+ inputRef.current.focus();
+ }
+ }, 0);
}else{
- setAddDisplay((prevState) => ({...prevState, active: false}));
+ setAddDisplay((prevState) => ({...prevState, active: false}));
}
}
};
const handleKeyPress = (event: React.KeyboardEvent) => {
if(event.key === "Enter"){
- executeAddCourse(props, inputRef, selectedTerm, setAddDisplay);
+ executeAddCourse(props, inputRef, selectedTerm, selectedResult, setAddDisplay);
}
};
@@ -91,26 +90,35 @@ function AddCourseButton(props: { term: number; user: User; setUser: Function })
setAddDisplay((prevState) => ({...prevState, active: false}))}>
-
-
-
setAddDisplay((prevState) => ({...prevState, dropVis: !addDisplay.dropVis}))}>
+
+
setAddDisplay((prevState) => ({...prevState, termDropVis: !prevState.termDropVis}))}>
{selectedTerm}
- {addDisplay.dropVis && (
-
- {terms.map((term, index) => (
-
setSelectedTerm(term)} className={term === selectedTerm ? Style.SelectedTerm : ""}>
- {term}
-
- ))}
-
- )}
-
-
-
-
-
executeAddCourse(props, inputRef, selectedTerm, setAddDisplay)}>
-
-
+ {addDisplay.termDropVis && (
+
+ {catalogTerms.map((term, index) => (
+
setSelectedTerm(term)} className={term === selectedTerm ? Style.SelectedDropdownOption : ""}>
+ {term}
+
+ ))}
+
+ )}
+
+
+
+
setAddDisplay((prevState) => ({...prevState, resultDropVis: !prevState.resultDropVis}))}>
+ {selectedResult || ""}
+ {addDisplay.resultDropVis && (
+
+ {resultOptions.map((result, index) => (
+
setSelectedResult(result)} className={result === selectedResult ? Style.SelectedDropdownOption : ""}>
+ {result}
+
+ ))}
+
+ )}
+
+
executeAddCourse(props, inputRef, selectedTerm, selectedResult, setAddDisplay)}>
+
)}
diff --git a/frontend/src/app/providers.tsx b/frontend/src/app/providers.tsx
index 9cd4599..020a3cb 100644
--- a/frontend/src/app/providers.tsx
+++ b/frontend/src/app/providers.tsx
@@ -1,15 +1,20 @@
"use client";
-import { createContext, useContext, useState } from "react";
+import { createContext, useContext, useState, useEffect } from "react";
import { User } from "@/types/type-user";
-import { NullUser } from "@/database/data-user";
+import { NullUser, Ryan } from "@/database/data-user";
const AuthContext = createContext
(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [auth, setAuth] = useState({ loggedIn: false });
- const [user, setUser] = useState(NullUser);
+ const [user, setUser] = useState(Ryan);
+
+ // uh this isnt right
+ useEffect(() => {
+ setUser(Ryan);
+ }, []);
return(
diff --git a/frontend/src/database/data-catalog.ts b/frontend/src/database/data-catalog.ts
index 212e244..336d1ba 100644
--- a/frontend/src/database/data-catalog.ts
+++ b/frontend/src/database/data-catalog.ts
@@ -9,6 +9,12 @@ interface Catalog {
export const Catalogs: Catalog[] = [
{ number: 202203, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
{ number: 202301, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202302, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202303, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202401, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202402, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202403, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202501, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
]
export const getCatalogCourse = (catalogNumber: number, courseCode: string): Course | null => {
@@ -19,3 +25,7 @@ export const getCatalogCourse = (catalogNumber: number, courseCode: string): Cou
const course = catalog.courses.find((course) => course.codes.includes(courseCode));
return course || null;
};
+
+export const getCatalogTerms = (): number[] => {
+ return Catalogs.map((catalog) => catalog.number).sort((a, b) => a - b);
+}
diff --git a/frontend/src/database/data-cpsc.ts b/frontend/src/database/data-cpsc.ts
new file mode 100644
index 0000000..06dadb4
--- /dev/null
+++ b/frontend/src/database/data-cpsc.ts
@@ -0,0 +1,86 @@
+
+
+import { DegreeConfiguration, TypeOneRequirement, TypeOneSubrequirement } from "@/types/type-program";
+
+
+const CPSC_201: TypeOneSubrequirement = {
+ requirement_name: "INTRODUCTION",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ course_options: [{ codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: [] }],
+ any: true,
+}
+
+const CPSC_202: TypeOneSubrequirement = {
+ requirement_name: "MATH",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ course_options: [
+ { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: [] },
+ { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: [] },
+ ],
+ any: true,
+}
+
+const CPSC_223: TypeOneSubrequirement = {
+ requirement_name: "SYSTEMS",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ course_options: [{ codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: [] }],
+}
+
+const CPSC_323: TypeOneSubrequirement = {
+ requirement_name: "SYSTEMS",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ course_options: [{ codes: ["CPSC 323"], title: "Systems", credit: 1, dist: ["QR"], seasons: [] }],
+}
+
+const CPSC_365: TypeOneSubrequirement = {
+ requirement_name: "ALGORITHMS",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ course_options: [
+ { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: [] },
+ { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: [] },
+ ],
+}
+
+const CPSC_CORE: TypeOneRequirement = {
+ requirement_name: "CORE",
+ requirement_description: "",
+ must_choose_n_subrequirements: 5,
+ subrequirements: [CPSC_201, CPSC_202, CPSC_223, CPSC_323, CPSC_365]
+}
+
+const CPSC_ELEC: TypeOneSubrequirement = {
+ requirement_name: "",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ elective_range: { department: "CPSC", min_code: 300, max_code: 999 }
+}
+
+const CPSC_ELECTIVE: TypeOneRequirement = {
+ requirement_name: "ELECTIVES",
+ requirement_description: "",
+ must_choose_n_subrequirements: 4,
+ subrequirements: [CPSC_ELEC, CPSC_ELEC, CPSC_ELEC, CPSC_ELEC]
+}
+
+const CPSC_SENIOR_CLASS: TypeOneSubrequirement = {
+ requirement_name: "",
+ requirement_description: "",
+ must_choose_n_courses: 1,
+ course_options: [{ codes: ["CPSC 323"], title: "Systems", credit: 1, dist: ["QR"], seasons: [] }],
+}
+
+const CPSC_SENIOR: TypeOneRequirement = {
+ requirement_name: "SENIOR",
+ requirement_description: "",
+ must_choose_n_subrequirements: 1,
+ subrequirements: [CPSC_SENIOR_CLASS]
+}
+
+export const CPSC_CONFIG: DegreeConfiguration = {
+ degreeRequirements: [CPSC_CORE, CPSC_ELECTIVE, CPSC_SENIOR]
+}
\ No newline at end of file
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index bbf09d1..0a02b75 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,5 +1,6 @@
import { User } from "./../types/type-user";
+import { CPSC_CONFIG } from "./data-cpsc";
export const Ryan: User = {
name: "Ryan",
@@ -7,21 +8,26 @@ export const Ryan: User = {
onboard: false,
FYP: {
studentCourses: [
- { term: 202403, status: "DA", course: { codes: ["CPSC 201"], title: "Intro To Computer Science", credit: 1, dist: ["QR"], seasons: [] } },
- { term: 202501, status: "DA", course: { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: [] } },
- { term: 202503, status: "MA", course: { codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: [] } },
+ { term: 202403, status: "DA", result: "GRADE_PASS", course: { codes: ["CPSC 201"], title: "Intro To Computer Science", credit: 1, dist: ["QR"], seasons: [] } },
+ { term: 202501, status: "DA", result: "GRADE_PASS", course: { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: [] } },
+ { term: 202503, status: "MA", result: "IP", course: { codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: [] } },
],
- languageRequirement: "",
+ studentTermArrangement: {
+ first_year: [0, 202403, 202501],
+ sophomore: [0, 202503, 202601],
+ junior: [0, 202603, 202701],
+ senior: [0, 202703, 202801],
+ },
+ languagePlacement: {
+ language: "Spanish",
+ level: 5,
+ },
degreeDeclarations: [],
degreeConfigurations: [
- [
- ],
- [
- ],
- [
- ],
- [
- ]
+ [CPSC_CONFIG],
+ [],
+ [],
+ []
],
}
}
@@ -32,7 +38,16 @@ export const NullUser: User = {
onboard: false,
FYP: {
studentCourses: [],
- languageRequirement: "",
+ studentTermArrangement: {
+ first_year: [],
+ sophomore: [],
+ junior: [],
+ senior: [],
+ },
+ languagePlacement: {
+ language: "",
+ level: 0,
+ },
degreeDeclarations: [],
degreeConfigurations: [
[
@@ -46,3 +61,6 @@ export const NullUser: User = {
],
}
}
+
+
+
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 4aae385..f07363d 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -1,5 +1,5 @@
-import { StudentCourse } from "./type-user";
+import { Course, StudentCourse } from "./type-user";
interface DUS {
name: string;
@@ -34,21 +34,39 @@ export interface DegreeMetadata {
// \BEGIN{MAJOR MAGIC}
-interface DegreeRequirementsSubsection {
- name?: string;
- description?: string;
- flexible: boolean;
- courses: StudentCourse[];
+export interface Range {
+ department: string;
+ min_code: number;
+ max_code: number;
}
-interface DegreeRequirement {
- name: string;
- description?: string;
- subsections: DegreeRequirementsSubsection[];
+export interface TypeOneSubrequirement {
+ requirement_name: string;
+ requirement_description: string;
+ must_choose_n_courses: number;
+ course_options?: Course[];
+ elective_range?: Range;
+ any?: boolean;
+}
+
+export interface TypeOneRequirement {
+ requirement_name: string;
+ requirement_description: string;
+ must_choose_n_subrequirements: number;
+ subrequirements: TypeOneSubrequirement[];
}
+export interface TypeTwoRequirement {
+ requirement_name: string;
+ requirement_description: string;
+ checkbox_boolean: boolean;
+}
+
+
+export type DegreeRequirement = TypeOneRequirement | TypeTwoRequirement;
+
export interface DegreeConfiguration {
- degreeRequirements: DegreeRequirement[];
+ degreeRequirements: DegreeRequirement[];
}
export interface Degree {
diff --git a/frontend/src/types/type-user.ts b/frontend/src/types/type-user.ts
index c558864..ce21d91 100644
--- a/frontend/src/types/type-user.ts
+++ b/frontend/src/types/type-user.ts
@@ -1,6 +1,11 @@
import { DegreeConfiguration, StudentDegree } from "./type-program";
+export interface LanguagePlacement {
+ language: string;
+ level: number;
+}
+
export interface Course {
codes: string[]; // ["FREN 403", "HUMS 409"]
title: string; // "Proust Interpretations: Reading Remembrance of Things Past "
@@ -13,23 +18,30 @@ export interface StudentCourse {
course: Course;
term: number; // 202401
status: string; // "DA" or "MA"
+ result: string; // "IP" or "GRADE_PASS" or "GRADE_FAIL" or "CR" or "W"
}
export interface StudentSemester {
term: number;
- active: boolean;
studentCourses: StudentCourse[];
}
export interface StudentYear {
grade: string; // "First-Year" | "Sophomore" | "Junior" | "Senior"
- active: boolean;
studentSemesters: StudentSemester[];
}
+export interface StudentTermArrangement {
+ first_year: number[];
+ sophomore: number[];
+ junior: number[];
+ senior: number[];
+}
+
export interface FYP {
- languageRequirement: string;
+ languagePlacement: LanguagePlacement;
studentCourses: StudentCourse[];
+ studentTermArrangement: StudentTermArrangement;
degreeConfigurations: DegreeConfiguration[][];
degreeDeclarations: StudentDegree[];
}
From e4d8e13b710411f75a8d059486f41aa0de650caf Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Sun, 23 Feb 2025 23:36:39 -0500
Subject: [PATCH 11/38] reqs r back kinda
---
frontend/src/app/courses/years/YearBox.tsx | 18 ++---
.../courses/years/semester/SemesterBox.tsx | 2 +-
frontend/src/app/majors/Majors.module.css | 6 +-
.../app/majors/metadata/Metadata.module.css | 5 ++
frontend/src/app/majors/metadata/Metadata.tsx | 2 +-
.../requirements/Requirements.module.css | 33 ++++++----
.../app/majors/requirements/Requirements.tsx | 53 ++++++++++++---
.../src/components/course-icon/CourseIcon.tsx | 66 +++++++++----------
frontend/src/database/data-cpsc.ts | 25 +++----
frontend/src/types/type-program.ts | 26 +++-----
frontend/src/utils/CourseDisplay.tsx | 6 +-
11 files changed, 144 insertions(+), 98 deletions(-)
diff --git a/frontend/src/app/courses/years/YearBox.tsx b/frontend/src/app/courses/years/YearBox.tsx
index 6a0d9a9..bc166bf 100644
--- a/frontend/src/app/courses/years/YearBox.tsx
+++ b/frontend/src/app/courses/years/YearBox.tsx
@@ -8,15 +8,17 @@ import AddSemesterButton from "./add-semester/AddSemesterButton"
function RenderSemesters(props: { edit: boolean; columns: boolean; studentYear: StudentYear, setStudentYears: Function, user: User, setUser: Function })
{
- const newRenderedSemesters = props.studentYear.studentSemesters.map((studentSemester: StudentSemester) => (
-
- ));
+ const newRenderedSemesters = props.studentYear.studentSemesters
+ .filter((studentSemester: StudentSemester) => studentSemester.term !== 0)
+ .map((studentSemester: StudentSemester) => (
+
+ ));
- return(
-
- {newRenderedSemesters}
-
- );
+ return(
+
+ {newRenderedSemesters}
+
+ );
}
function YearBox(props: { edit: boolean, columns: boolean, studentYear: StudentYear, setStudentYears: Function, user: User, setUser: Function })
diff --git a/frontend/src/app/courses/years/semester/SemesterBox.tsx b/frontend/src/app/courses/years/semester/SemesterBox.tsx
index b8be76a..5cc3625 100644
--- a/frontend/src/app/courses/years/semester/SemesterBox.tsx
+++ b/frontend/src/app/courses/years/semester/SemesterBox.tsx
@@ -32,7 +32,7 @@ function SemesterBox(props: { edit: boolean, studentSemester: StudentSemester, u
}, [props.edit, props.studentSemester, props.user]);
return(
-
+
{TransformTermNumber(props.studentSemester.term)}
diff --git a/frontend/src/app/majors/Majors.module.css b/frontend/src/app/majors/Majors.module.css
index df741d6..22f3d96 100644
--- a/frontend/src/app/majors/Majors.module.css
+++ b/frontend/src/app/majors/Majors.module.css
@@ -1,11 +1,13 @@
.MajorsPage {
position: absolute;
+ top: 75px;
display: flex;
flex-direction: row;
+
justify-content: center;
- padding: 20px calc(50% - 500px);
- margin-top: 100px;
+ width: 100%;
+ padding-top: 50px;
}
diff --git a/frontend/src/app/majors/metadata/Metadata.module.css b/frontend/src/app/majors/metadata/Metadata.module.css
index adf4b8b..263f80f 100644
--- a/frontend/src/app/majors/metadata/Metadata.module.css
+++ b/frontend/src/app/majors/metadata/Metadata.module.css
@@ -1,4 +1,9 @@
+
+.MetadataContainer{
+ width: 600px;
+}
+
.countBox {
display: inline-block; /* Display as inline block */
width: max-content; /* Set width to maximum content size */
diff --git a/frontend/src/app/majors/metadata/Metadata.tsx b/frontend/src/app/majors/metadata/Metadata.tsx
index e5d4fc4..5471e7f 100644
--- a/frontend/src/app/majors/metadata/Metadata.tsx
+++ b/frontend/src/app/majors/metadata/Metadata.tsx
@@ -152,7 +152,7 @@ function Metadata(props: {
peekProgram: Function
}) {
return (
-
+
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index 8d4817d..fe338cc 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -1,10 +1,25 @@
-.row{
+.Column {
+ display: flex;
+ flex-direction: column;
+}
+
+.Row{
display: flex;
flex-direction: row;
}
-.reqsList {
+.RequirementsContainer {
+ padding: 20px;
+ border-radius: 25px;
+ width: 500px;
+ height: 500px;
+ min-width: 390px;
+ background-color: white;
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
+}
+
+.ReqsList {
height: 430px;
scrollbar-color: rgb(131, 131, 131) transparent;
scrollbar-width: thin;
@@ -13,20 +28,16 @@
overflow-x: hidden;
}
-.subsectionHeader {
+.ReqHeader {
color: grey;
font-size: 18px;
font-weight: 501;
}
-.reqsContainer {
- padding: 20px;
- border-radius: 25px;
- width: 490px;
- height: 490px;
- min-width: 390px;
- background-color: white;
- box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
+.SubHeader {
+ color: grey;
+ font-size: 14px;
+ font-weight: 500;
}
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index a8aa215..e51e1ee 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -3,21 +3,54 @@ import { useState } from "react";
import Style from "./Requirements.module.css";
import { User } from "@/types/type-user";
-import { DegreeConfiguration } from "@/types/type-program";
+import { DegreeConfiguration, TypeOneRequirement, TypeOneSubrequirement } from "@/types/type-program";
+import { CourseIcon } from "@/components/course-icon/CourseIcon";
+
+
+
// import AddableCourse from "./icons/AddableCourse";
// import RemovableCourse from "./icons/RemovableCourse";
// import { addCourseToSubsection, removeCourseFromSubsection, resetDegree } from "./RequirementsUtils";
-function RequirementsContent(props: {
- edit: boolean,
- degreeConfiguration: DegreeConfiguration,
- user: User,
- setUser: Function
-}){
+function RenderSubrequirement(props: { subrequirement: TypeOneSubrequirement }){
+ return(
+
+
+ {props.subrequirement.requirement_name}
+
+
+ {props.subrequirement.courses.map((course, index) => (
+
+
+
+ ))}
+
+
+ )
+}
+
+function RenderRequirement(props: { requirement: TypeOneRequirement }){
+ return(
+
+
+ {props.requirement.requirement_name}
+
+
+ {props.requirement.subrequirements.map((subrequirement, index) => (
+
+ ))}
+
+
+ )
+}
+
+function RequirementsContent(props: { edit: boolean, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function }){
return(
-
-
+
+ {props.degreeConfiguration.degreeRequirements.map((requirement, index) => (
+
+ ))}
);
}
@@ -34,7 +67,7 @@ function Requirements(props: {
};
return(
-
+
Requirements
diff --git a/frontend/src/components/course-icon/CourseIcon.tsx b/frontend/src/components/course-icon/CourseIcon.tsx
index cdaf3f3..e08a68a 100644
--- a/frontend/src/components/course-icon/CourseIcon.tsx
+++ b/frontend/src/components/course-icon/CourseIcon.tsx
@@ -1,18 +1,21 @@
import React from "react";
import styles from "./CourseIcon.module.css";
-import "react-tooltip/dist/react-tooltip.css";
-import { StudentCourse } from "@/types/type-user";
-import fall from "./fall.svg";
+import { StudentCourse, Course } from "@/types/type-user";
+import { RenderMark, GetCourseColor } from "@/utils/CourseDisplay";
+
import DistributionCircle from "../distribution-circle/DistributionsCircle";
+
+
// import { useModal } from "../../../hooks/modalContext";
+// import "react-tooltip/dist/react-tooltip.css";
function CourseSeasonIcon(props: { seasons: Array
}) {
const seasonImageMap: { [key: string]: string } = {
- "Fall": fall,
- "Spring": fall,
+ "Fall": "./fall.svg",
+ "Spring": "./spring.svg",
};
return (
@@ -32,12 +35,17 @@ function CourseSeasonIcon(props: { seasons: Array }) {
);
}
-function DistCircDiv(props: { dist: Array }) {
- if (!Array.isArray(props.dist) || props.dist.length === 0) {
- return
;
+function DistCircDiv(props: { dist: string[] })
+{
+ if(!Array.isArray(props.dist) || props.dist.length === 0){
+ return(
+
+
+
+ );
}
- return (
+ return(
@@ -47,39 +55,29 @@ function DistCircDiv(props: { dist: Array }) {
export function StudentCourseIcon(props: { studentCourse: StudentCourse, utilityButton?: React.ReactNode }) {
- const mark = (status: string) => {
- let mark = "";
- switch (status) {
- case "DA_COMPLETE":
- case "DA_PROSPECT":
- mark = "✓";
- break;
- case "MA_HYPOTHETICAL":
- mark = "⚠";
- break;
- case "MA_VALID":
- mark = "☑";
- break;
- default:
- return
;
- }
- return {mark}
;
- };
-
const dist = props.studentCourse.course.dist || [];
return (
-
+
{props.utilityButton && props.utilityButton}
- {props.studentCourse.status === "NA"
+ {props.studentCourse.status === ""
?
- : mark(props.studentCourse.status)
+ :
}
{props.studentCourse.course.codes[0]}
);
}
+
+
+export function CourseIcon(props: { course: Course }){
+
+ return(
+
+
+ {props.course.codes[0]}
+
+
+ );
+}
diff --git a/frontend/src/database/data-cpsc.ts b/frontend/src/database/data-cpsc.ts
index 06dadb4..0abb444 100644
--- a/frontend/src/database/data-cpsc.ts
+++ b/frontend/src/database/data-cpsc.ts
@@ -4,10 +4,10 @@ import { DegreeConfiguration, TypeOneRequirement, TypeOneSubrequirement } from "
const CPSC_201: TypeOneSubrequirement = {
- requirement_name: "INTRODUCTION",
+ requirement_name: "INTRO",
requirement_description: "",
must_choose_n_courses: 1,
- course_options: [{ codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: [] }],
+ courses: [{ codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
any: true,
}
@@ -15,34 +15,34 @@ const CPSC_202: TypeOneSubrequirement = {
requirement_name: "MATH",
requirement_description: "",
must_choose_n_courses: 1,
- course_options: [
- { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: [] },
- { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: [] },
+ courses: [
+ { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
+ { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
],
any: true,
}
const CPSC_223: TypeOneSubrequirement = {
- requirement_name: "SYSTEMS",
+ requirement_name: "DATA STRUCTURES",
requirement_description: "",
must_choose_n_courses: 1,
- course_options: [{ codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: [] }],
+ courses: [{ codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
}
const CPSC_323: TypeOneSubrequirement = {
requirement_name: "SYSTEMS",
requirement_description: "",
must_choose_n_courses: 1,
- course_options: [{ codes: ["CPSC 323"], title: "Systems", credit: 1, dist: ["QR"], seasons: [] }],
+ courses: [{ codes: ["CPSC 323"], title: "Systems", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
}
const CPSC_365: TypeOneSubrequirement = {
requirement_name: "ALGORITHMS",
requirement_description: "",
must_choose_n_courses: 1,
- course_options: [
- { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: [] },
- { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: [] },
+ courses: [
+ { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
+ { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
],
}
@@ -57,6 +57,7 @@ const CPSC_ELEC: TypeOneSubrequirement = {
requirement_name: "",
requirement_description: "",
must_choose_n_courses: 1,
+ courses: [],
elective_range: { department: "CPSC", min_code: 300, max_code: 999 }
}
@@ -71,7 +72,7 @@ const CPSC_SENIOR_CLASS: TypeOneSubrequirement = {
requirement_name: "",
requirement_description: "",
must_choose_n_courses: 1,
- course_options: [{ codes: ["CPSC 323"], title: "Systems", credit: 1, dist: ["QR"], seasons: [] }],
+ courses: [{ codes: ["CPSC 490"], title: "Systems", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
}
const CPSC_SENIOR: TypeOneRequirement = {
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index f07363d..3ec84f0 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -1,5 +1,5 @@
-import { Course, StudentCourse } from "./type-user";
+import { Course } from "./type-user";
interface DUS {
name: string;
@@ -44,7 +44,7 @@ export interface TypeOneSubrequirement {
requirement_name: string;
requirement_description: string;
must_choose_n_courses: number;
- course_options?: Course[];
+ courses: Course[];
elective_range?: Range;
any?: boolean;
}
@@ -56,17 +56,17 @@ export interface TypeOneRequirement {
subrequirements: TypeOneSubrequirement[];
}
-export interface TypeTwoRequirement {
- requirement_name: string;
- requirement_description: string;
- checkbox_boolean: boolean;
-}
+// export interface TypeTwoRequirement {
+// requirement_name: string;
+// requirement_description: string;
+// checkbox_boolean: boolean;
+// }
-export type DegreeRequirement = TypeOneRequirement | TypeTwoRequirement;
+// export type DegreeRequirement = TypeOneRequirement | TypeTwoRequirement;
export interface DegreeConfiguration {
- degreeRequirements: DegreeRequirement[];
+ degreeRequirements: TypeOneRequirement[];
}
export interface Degree {
@@ -76,14 +76,8 @@ export interface Degree {
// \END{MAJOR MAGIC}
-
-
-
-
-
-
export interface StudentDegree {
- status: string; // DA | ADD | PIN
+ status: string; // DA | ADD | PIN
programIndex: number;
degreeIndex: number;
}
diff --git a/frontend/src/utils/CourseDisplay.tsx b/frontend/src/utils/CourseDisplay.tsx
index dcfaeed..b09f91d 100644
--- a/frontend/src/utils/CourseDisplay.tsx
+++ b/frontend/src/utils/CourseDisplay.tsx
@@ -53,16 +53,16 @@ export function GetCourseColor(term: number): string {
return IsTermActive(term) ? "#F5F5F5" : "#E1E9F8";
}
-export function RenderMark(props: { edit: boolean, studentCourse: StudentCourse, user: User, setUser: Function })
+export function RenderMark(props: { status: string })
{
- if(props.studentCourse.status === "DA"){
+ if(props.status === "DA"){
return(
✓
);
}else
- if(props.studentCourse.status === "MA"){
+ if(props.status === "MA"){
return(
⚠
From 2f8a8ecfea8cf4ecc317d3939101e541d7bffb21 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Sat, 8 Mar 2025 08:30:29 -0800
Subject: [PATCH 12/38] data stuff
---
.../app/majors/requirements/Requirements.tsx | 57 ++++---
.../src/components/course-icon/CourseIcon.tsx | 13 +-
frontend/src/database/data-catalog.ts | 28 +++-
frontend/src/database/data-cpsc.ts | 155 +++++++++++-------
frontend/src/types/type-program.ts | 71 ++++----
5 files changed, 195 insertions(+), 129 deletions(-)
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index e51e1ee..0982d21 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -2,64 +2,77 @@
import { useState } from "react";
import Style from "./Requirements.module.css";
-import { User } from "@/types/type-user";
-import { DegreeConfiguration, TypeOneRequirement, TypeOneSubrequirement } from "@/types/type-program";
+import { User, Course } from "@/types/type-user";
+import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
import { CourseIcon } from "@/components/course-icon/CourseIcon";
+function RenderSubrequirementCourse(props: { course: Course, subreq: DegreeSubrequirement; user: User }){
-// import AddableCourse from "./icons/AddableCourse";
-// import RemovableCourse from "./icons/RemovableCourse";
-// import { addCourseToSubsection, removeCourseFromSubsection, resetDegree } from "./RequirementsUtils";
-function RenderSubrequirement(props: { subrequirement: TypeOneSubrequirement }){
+ return(
+
+
+
+ )
+}
+
+function RenderSubrequirement(props: { subreq: DegreeSubrequirement, user: User })
+{
return(
-
- {props.subrequirement.requirement_name}
+
+
+
+ {props.subreq.subreq_name}
+
+
+ {props.subreq.user_courses_satisfying.length}/{props.subreq.courses_required}
+
+
- {props.subrequirement.courses.map((course, index) => (
+ {props.subreq.courses_options.map((course, index) => (
-
+
))}
+
)
}
-function RenderRequirement(props: { requirement: TypeOneRequirement }){
+function RenderRequirement(props: { req: DegreeRequirement, user: User })
+{
return(
- {props.requirement.requirement_name}
+ {props.req.req_name}
- {props.requirement.subrequirements.map((subrequirement, index) => (
-
+ {props.req.subreqs_list.map((subreq, index) => (
+
))}
)
}
-function RequirementsContent(props: { edit: boolean, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function }){
+function RequirementsContent(props: { edit: boolean, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function })
+{
return(
- {props.degreeConfiguration.degreeRequirements.map((requirement, index) => (
-
+ {props.degreeConfiguration.reqs_list.map((req, index) => (
+
))}
);
}
-function Requirements(props: {
- user: User,
- setUser: Function,
- degreeConfiguration: DegreeConfiguration
-}){
+function Requirements(props: { user: User, setUser: Function, degreeConfiguration: DegreeConfiguration })
+{
const [edit, setEdit] = useState(false);
const updateEdit = () => {
diff --git a/frontend/src/components/course-icon/CourseIcon.tsx b/frontend/src/components/course-icon/CourseIcon.tsx
index e08a68a..073a50b 100644
--- a/frontend/src/components/course-icon/CourseIcon.tsx
+++ b/frontend/src/components/course-icon/CourseIcon.tsx
@@ -8,10 +8,6 @@ import { RenderMark, GetCourseColor } from "@/utils/CourseDisplay";
import DistributionCircle from "../distribution-circle/DistributionsCircle";
-
-// import { useModal } from "../../../hooks/modalContext";
-// import "react-tooltip/dist/react-tooltip.css";
-
function CourseSeasonIcon(props: { seasons: Array
}) {
const seasonImageMap: { [key: string]: string } = {
"Fall": "./fall.svg",
@@ -35,6 +31,7 @@ function CourseSeasonIcon(props: { seasons: Array }) {
);
}
+
function DistCircDiv(props: { dist: string[] })
{
if(!Array.isArray(props.dist) || props.dist.length === 0){
@@ -71,8 +68,14 @@ export function StudentCourseIcon(props: { studentCourse: StudentCourse, utility
}
-export function CourseIcon(props: { course: Course }){
+export function CourseIcon(props: { course: Course, studentCourse?: StudentCourse }){
+ if(props.studentCourse){
+ return(
+
+ );
+ }
+
return(
diff --git a/frontend/src/database/data-catalog.ts b/frontend/src/database/data-catalog.ts
index 336d1ba..957bd25 100644
--- a/frontend/src/database/data-catalog.ts
+++ b/frontend/src/database/data-catalog.ts
@@ -6,15 +6,27 @@ interface Catalog {
courses: Course[];
}
+export const CPSC_201: Course = { codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_202: Course = { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_244: Course = { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_223: Course = { codes: ["CPSC 223"], title: "Data Structures And Programming Techniques", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_323: Course = { codes: ["CPSC 323"], title: "Introduction To Systems Programming", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_365: Course = { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_366: Course = { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_490: Course = { codes: ["CPSC 490"], title: "Senior Project", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+export const HSAR_401: Course = { codes: ["HSAR 401"], title: "Critical Approaches To Art History", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+
export const Catalogs: Catalog[] = [
- { number: 202203, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202301, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202302, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202303, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202401, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202402, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202403, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
- { number: 202501, courses: [{ codes: ["HSAR 401"], title: "Critical Approaches", credit: 1, dist: [], seasons: [] }] },
+ { number: 202203, courses: [HSAR_401] },
+ { number: 202301, courses: [HSAR_401] },
+ { number: 202302, courses: [HSAR_401] },
+ { number: 202303, courses: [HSAR_401] },
+ { number: 202401, courses: [HSAR_401] },
+ { number: 202402, courses: [HSAR_401] },
+ { number: 202403, courses: [HSAR_401] },
+ { number: 202501, courses: [HSAR_401] },
]
export const getCatalogCourse = (catalogNumber: number, courseCode: string): Course | null => {
diff --git a/frontend/src/database/data-cpsc.ts b/frontend/src/database/data-cpsc.ts
index 0abb444..13f53a6 100644
--- a/frontend/src/database/data-cpsc.ts
+++ b/frontend/src/database/data-cpsc.ts
@@ -1,87 +1,120 @@
-import { DegreeConfiguration, TypeOneRequirement, TypeOneSubrequirement } from "@/types/type-program";
+import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./data-catalog";
+const CPSC_INTRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [CPSC_201],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ user_courses_satisfying: [CPSC_201],
+}
-const CPSC_201: TypeOneSubrequirement = {
- requirement_name: "INTRO",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [{ codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
- any: true,
+const CPSC_MATH: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "DISCRETE MATH",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [CPSC_202, MATH_244],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ user_courses_satisfying: [],
}
-const CPSC_202: TypeOneSubrequirement = {
- requirement_name: "MATH",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [
- { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
- { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
- ],
- any: true,
+const CPSC_DATA: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "DATA STRUCTURES",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [CPSC_223],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ user_courses_satisfying: [CPSC_223],
}
-const CPSC_223: TypeOneSubrequirement = {
- requirement_name: "DATA STRUCTURES",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [{ codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
+const CPSC_SYSTEMS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "SYSTEMS",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [CPSC_323],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ user_courses_satisfying: [CPSC_323],
}
-const CPSC_323: TypeOneSubrequirement = {
- requirement_name: "SYSTEMS",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [{ codes: ["CPSC 323"], title: "Systems", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
+const CPSC_ALGOS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "ALGORITHMS",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [CPSC_365, CPSC_366],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ user_courses_satisfying: [],
}
-const CPSC_365: TypeOneSubrequirement = {
- requirement_name: "ALGORITHMS",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [
- { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
- { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] },
- ],
+const CPSC_CORE: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "CORE",
+ req_desc: "",
+ subreqs_required: 5,
+ subreqs_list: [CPSC_INTRO, CPSC_MATH, CPSC_DATA, CPSC_SYSTEMS, CPSC_ALGOS]
}
-const CPSC_CORE: TypeOneRequirement = {
- requirement_name: "CORE",
- requirement_description: "",
- must_choose_n_subrequirements: 5,
- subrequirements: [CPSC_201, CPSC_202, CPSC_223, CPSC_323, CPSC_365]
+const CPSC_RANGE_ELECS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [],
+ courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
+ courses_any_bool: false,
+ user_courses_satisfying: []
}
-const CPSC_ELEC: TypeOneSubrequirement = {
- requirement_name: "",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [],
- elective_range: { department: "CPSC", min_code: 300, max_code: 999 }
+const CPSC_SUB_ELEC: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "",
+ courses_required: 3,
+ courses_options: [],
+ courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
+ courses_any_bool: true,
+ user_courses_satisfying: []
}
-const CPSC_ELECTIVE: TypeOneRequirement = {
- requirement_name: "ELECTIVES",
- requirement_description: "",
- must_choose_n_subrequirements: 4,
- subrequirements: [CPSC_ELEC, CPSC_ELEC, CPSC_ELEC, CPSC_ELEC]
+const CPSC_ELECTIVES: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "ELECTIVE",
+ req_desc: "",
+ subreqs_required: 4,
+ subreqs_list: [CPSC_RANGE_ELECS, CPSC_SUB_ELEC]
}
-const CPSC_SENIOR_CLASS: TypeOneSubrequirement = {
- requirement_name: "",
- requirement_description: "",
- must_choose_n_courses: 1,
- courses: [{ codes: ["CPSC 490"], title: "Systems", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }],
+const CPSC_SENPROJ: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "SENIOR PROJECT",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [CPSC_490],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ user_courses_satisfying: []
}
-const CPSC_SENIOR: TypeOneRequirement = {
- requirement_name: "SENIOR",
- requirement_description: "",
- must_choose_n_subrequirements: 1,
- subrequirements: [CPSC_SENIOR_CLASS]
+const CPSC_SENIOR: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "SENIOR",
+ req_desc: "",
+ subreqs_required: 1,
+ subreqs_list: [CPSC_SENPROJ]
}
export const CPSC_CONFIG: DegreeConfiguration = {
- degreeRequirements: [CPSC_CORE, CPSC_ELECTIVE, CPSC_SENIOR]
+ reqs_list: [CPSC_CORE, CPSC_ELECTIVES, CPSC_SENIOR]
}
\ No newline at end of file
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 3ec84f0..95148d4 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -1,6 +1,12 @@
import { Course } from "./type-user";
+export interface StudentDegree {
+ status: string; // DA | ADD | PIN
+ programIndex: number;
+ degreeIndex: number;
+}
+
interface DUS {
name: string;
address: string;
@@ -26,47 +32,52 @@ export interface DegreeMetadata {
wesbiteLink: string;
}
-
-
-
-
-
-
// \BEGIN{MAJOR MAGIC}
-export interface Range {
- department: string;
+export interface ElectiveRange {
+ dept: string;
min_code: number;
max_code: number;
}
-export interface TypeOneSubrequirement {
- requirement_name: string;
- requirement_description: string;
- must_choose_n_courses: number;
- courses: Course[];
- elective_range?: Range;
- any?: boolean;
+export type SubreqElectiveRange = ElectiveRange| null;
+
+// subreq: 1 | set options
+export interface DegreeSubrequirement {
+ subreq_type_id: number;
+ subreq_name: string;
+ subreq_desc: string;
+
+ courses_required: number;
+ courses_options: Course[];
+ courses_elective_range: SubreqElectiveRange;
+ courses_any_bool: boolean;
+
+ user_courses_satisfying: Course[];
}
-export interface TypeOneRequirement {
- requirement_name: string;
- requirement_description: string;
- must_choose_n_subrequirements: number;
- subrequirements: TypeOneSubrequirement[];
+export interface DegreeRequirement {
+ req_type_id: number;
+ req_name: string;
+ req_desc: string;
+
+ subreqs_required: number;
+ subreqs_list: DegreeSubrequirement[];
}
-// export interface TypeTwoRequirement {
-// requirement_name: string;
-// requirement_description: string;
-// checkbox_boolean: boolean;
-// }
+// export interface DegreeRequirementTypeTwo {
+// req_type_id: number;
+// req_name: string;
+// req_desc: string;
+// checkbox_bool: boolean;
+// user_courses_satisfying: Course[];
+// }
-// export type DegreeRequirement = TypeOneRequirement | TypeTwoRequirement;
+// export type DegreeRequirement = DegreeRequirementTypeOne | DegreeRequirementTypeTwo;
export interface DegreeConfiguration {
- degreeRequirements: TypeOneRequirement[];
+ reqs_list: DegreeRequirement[];
}
export interface Degree {
@@ -75,9 +86,3 @@ export interface Degree {
}
// \END{MAJOR MAGIC}
-
-export interface StudentDegree {
- status: string; // DA | ADD | PIN
- programIndex: number;
- degreeIndex: number;
-}
From dd58660aebd37599cc6926e97fa2e49e0e06f1f3 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Sat, 8 Mar 2025 09:38:13 -0800
Subject: [PATCH 13/38] requirements liberated
---
frontend/src/app/majors/Majors.module.css | 19 +++++++++++--
.../app/majors/metadata/Metadata.module.css | 19 +++++++++++--
frontend/src/app/majors/page.tsx | 3 +-
.../requirements/Requirements.module.css | 25 +++++++++++------
.../app/majors/requirements/Requirements.tsx | 28 +++++++++----------
5 files changed, 66 insertions(+), 28 deletions(-)
diff --git a/frontend/src/app/majors/Majors.module.css b/frontend/src/app/majors/Majors.module.css
index 22f3d96..010a158 100644
--- a/frontend/src/app/majors/Majors.module.css
+++ b/frontend/src/app/majors/Majors.module.css
@@ -1,7 +1,9 @@
.MajorsPage {
+ /* border: 1px solid blue; */
+
position: absolute;
- top: 75px;
+ top: 75px;
display: flex;
flex-direction: row;
@@ -9,5 +11,18 @@
justify-content: center;
width: 100%;
- padding-top: 50px;
+ height: calc(100vh - 75px);
+
+ /* padding-top: 50px; */
+}
+
+.Divider {
+ border-right: 1px solid gray;
+
+ position: absolute;
+ top: 50px;
+ bottom: 50px;
+
+ width: 5px;
+ height: calc(100% - 100px);
}
diff --git a/frontend/src/app/majors/metadata/Metadata.module.css b/frontend/src/app/majors/metadata/Metadata.module.css
index 263f80f..7b9aea5 100644
--- a/frontend/src/app/majors/metadata/Metadata.module.css
+++ b/frontend/src/app/majors/metadata/Metadata.module.css
@@ -1,7 +1,22 @@
+.Column {
+ display: flex;
+ flex-direction: column;
+}
+
+.Row{
+ display: flex;
+ flex-direction: row;
+}
.MetadataContainer{
+ /* border: 1px solid red; */
+
+ margin-top: 50px;
+ margin-right: 25px;
+
width: 600px;
+ height: 600px;
}
.countBox {
@@ -58,12 +73,10 @@
}
.majorContainer {
- padding: 20px 20px 20px 0;
+
width: auto;
height: 400px;
background-color: white;
- margin-right: 10px;
- /* border: 1px solid black; */
}
.thumbtack {
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 4fb5166..1ebc057 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -20,7 +20,7 @@ function Majors()
const allProgramMetadatas: DegreeMetadata[][] = ALL_PROGRAM_METADATAS;
- const shiftProgramIndex = (dir: number) => {
+ const shiftProgramIndex: Function = (dir: number) => {
setProgramIndex((programIndex + dir + allProgramMetadatas.length) % allProgramMetadatas.length);
};
@@ -40,6 +40,7 @@ function Majors()
shiftProgramIndex={shiftProgramIndex}
peekProgram={peekProgram}
/>
+
-
-
-
- {props.subreq.subreq_name}
-
-
- {props.subreq.user_courses_satisfying.length}/{props.subreq.courses_required}
-
+
+
+ {props.subreq.user_courses_satisfying.length}|{props.subreq.courses_required} {props.subreq.subreq_name}
-
-
+
{props.subreq.courses_options.map((course, index) => (
@@ -47,10 +40,17 @@ function RenderRequirement(props: { req: DegreeRequirement, user: User })
{
return(
-
- {props.req.req_name}
+
+
+
+ {props.req.req_name}
+
+
+ 0|{props.req.subreqs_required}
+
-
+
+
{props.req.subreqs_list.map((subreq, index) => (
))}
From b9ac1f3220987f8f3376e4930c44def6f5c2dd7e Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Sat, 8 Mar 2025 11:26:48 -0800
Subject: [PATCH 14/38] course overflow
---
frontend/src/app/majors/Majors.module.css | 8 +--
.../app/majors/metadata/Metadata.module.css | 8 +--
frontend/src/app/majors/metadata/Metadata.tsx | 2 +-
.../requirements/Requirements.module.css | 38 ++++++++++++-
.../app/majors/requirements/Requirements.tsx | 56 ++++++++++++++++---
.../course-icon/CourseIcon.module.css | 2 -
.../src/components/course-icon/CourseIcon.tsx | 8 ++-
frontend/src/database/data-catalog.ts | 13 +----
frontend/src/database/data-courses.ts | 15 +++++
frontend/src/database/data-cpsc.ts | 46 +++++++++------
frontend/src/database/data-studentcourses.ts | 11 ++++
frontend/src/database/data-user.ts | 8 +--
frontend/src/types/type-program.ts | 10 ++--
13 files changed, 160 insertions(+), 65 deletions(-)
create mode 100644 frontend/src/database/data-courses.ts
create mode 100644 frontend/src/database/data-studentcourses.ts
diff --git a/frontend/src/app/majors/Majors.module.css b/frontend/src/app/majors/Majors.module.css
index 010a158..0243411 100644
--- a/frontend/src/app/majors/Majors.module.css
+++ b/frontend/src/app/majors/Majors.module.css
@@ -19,10 +19,10 @@
.Divider {
border-right: 1px solid gray;
- position: absolute;
- top: 50px;
- bottom: 50px;
+ margin-top: 50px;
+ margin-right: 25px;
+ margin-left: 25px;
- width: 5px;
+ width: 1px;
height: calc(100% - 100px);
}
diff --git a/frontend/src/app/majors/metadata/Metadata.module.css b/frontend/src/app/majors/metadata/Metadata.module.css
index 7b9aea5..eefa8bd 100644
--- a/frontend/src/app/majors/metadata/Metadata.module.css
+++ b/frontend/src/app/majors/metadata/Metadata.module.css
@@ -12,10 +12,9 @@
.MetadataContainer{
/* border: 1px solid red; */
- margin-top: 50px;
- margin-right: 25px;
+ margin-top: 75px;
- width: 600px;
+ width: 550px;
height: 600px;
}
@@ -72,7 +71,8 @@
margin-right: 10px;
}
-.majorContainer {
+.MajorContainer {
+ /* border: 1px solid gray; */
width: auto;
height: 400px;
diff --git a/frontend/src/app/majors/metadata/Metadata.tsx b/frontend/src/app/majors/metadata/Metadata.tsx
index 5471e7f..87316bc 100644
--- a/frontend/src/app/majors/metadata/Metadata.tsx
+++ b/frontend/src/app/majors/metadata/Metadata.tsx
@@ -86,7 +86,7 @@ function MetadataContent(props: {
programIndex: number,
}){
return (
-
+
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index aabdc39..4efc472 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -12,8 +12,7 @@
.RequirementsContainer {
/* border: 1px solid green; */
- margin-top: 25px;
- margin-left: 25px;
+ margin-top: 37px;
width: 600px;
height: 650px;
@@ -27,7 +26,7 @@
}
.ReqsList {
- /* border: 1px solid orange; */
+ border: 1px solid white;
/*
height: 430px;
scrollbar-color: rgb(131, 131, 131) transparent;
@@ -49,6 +48,39 @@
font-weight: 500;
}
+.SubDesc {
+ color: grey;
+ font-style: italic;
+ font-size: 12px;
+ font-weight: 500;
+}
+
+
+.EmptyCourse {
+ border-radius: 15px;
+ padding: 2px 2px;
+ background-color: #e7e7e7c3;
+ transition: filter 0.4s ease;
+ width: 15px; /* Adjust width to match CourseIcon */
+ height: 15px; /* Adjust height to match CourseIcon */
+ display: inline-block; /* Keeps it inline with other elements */
+}
+
+.EmptyCourse:hover {
+ cursor: pointer;
+ filter: brightness(95%);
+}
+
+.ToggleButton {
+ margin-top: 3px;
+
+ cursor: pointer;
+ background: none;
+ border: none;
+ color: #65a8f0;
+ font-size: 14px;
+}
+
.ButtonRow {
display: flex;
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 843b864..238d988 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -6,32 +6,68 @@ import { User, Course } from "@/types/type-user";
import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
import { CourseIcon } from "@/components/course-icon/CourseIcon";
-function RenderSubrequirementCourse(props: { course: Course, subreq: DegreeSubrequirement; user: User }){
+function RenderSubrequirementCourse(props: { course: Course | null, subreq: DegreeSubrequirement; user: User }){
+
+ // TODO
+
+ if(props.course === null){
+ return(
+
+ );
+ }
+
+ const matchingStudentCourse = props.subreq.student_courses_satisfying.find(
+ (studentCourse) => studentCourse.course === props.course
+ );
return(
-
-
+
+
)
}
function RenderSubrequirement(props: { subreq: DegreeSubrequirement, user: User })
{
+ const [showAll, setShowAll] = useState(false);
+
+ // Extract non-null courses
+ const nonNullCourses = props.subreq.courses_options.filter((course) => course !== null) as Course[];
+ const satisfiedCourses = props.subreq.student_courses_satisfying.map((studentCourse) => studentCourse.course);
+
+ // Determine which courses to show based on satisfaction condition
+ const isSatisfied = props.subreq.student_courses_satisfying.length === props.subreq.courses_required;
+ const displayedCourses = showAll
+ ? nonNullCourses
+ : isSatisfied
+ ? satisfiedCourses
+ : nonNullCourses.slice(0, 4);
+
+ const extraCoursesCount = showAll ? 0 : nonNullCourses.length - displayedCourses.length;
+
return(
- {props.subreq.user_courses_satisfying.length}|{props.subreq.courses_required} {props.subreq.subreq_name}
+ {props.subreq.student_courses_satisfying.length}|{props.subreq.courses_required} {props.subreq.subreq_name}
+
+
+ {props.subreq.subreq_desc}
-
- {props.subreq.courses_options.map((course, index) => (
+
+ {displayedCourses.map((course, index) => (
))}
+ {/* Show More / Show Less Button */}
+ {nonNullCourses.length > 4 && (
+
setShowAll(!showAll)}>
+ {showAll ? "<<" : ">>"}
+
)
+ }
-
)
}
@@ -46,7 +82,7 @@ function RenderRequirement(props: { req: DegreeRequirement, user: User })
{props.req.req_name}
- 0|{props.req.subreqs_required}
+ {props.req.courses_satisfied_count}|{props.req.courses_required_count}
@@ -91,7 +127,9 @@ function Requirements(props: { user: User, setUser: Function, degreeConfiguratio
-
+
+
+
);
}
diff --git a/frontend/src/components/course-icon/CourseIcon.module.css b/frontend/src/components/course-icon/CourseIcon.module.css
index 1c4e427..7efaaa5 100644
--- a/frontend/src/components/course-icon/CourseIcon.module.css
+++ b/frontend/src/components/course-icon/CourseIcon.module.css
@@ -15,8 +15,6 @@
background-color: #F5F5F5;
transition: filter 0.4s ease;
-
- margin-right: 2px;
}
.CourseIcon:hover {
diff --git a/frontend/src/components/course-icon/CourseIcon.tsx b/frontend/src/components/course-icon/CourseIcon.tsx
index 073a50b..31eb639 100644
--- a/frontend/src/components/course-icon/CourseIcon.tsx
+++ b/frontend/src/components/course-icon/CourseIcon.tsx
@@ -54,15 +54,17 @@ export function StudentCourseIcon(props: { studentCourse: StudentCourse, utility
const dist = props.studentCourse.course.dist || [];
+ // style={{ backgroundColor: GetCourseColor(props.studentCourse.term) }}
+
return (
-
+
{props.utilityButton && props.utilityButton}
{props.studentCourse.status === ""
?
- :
+ :
}
{props.studentCourse.course.codes[0]}
-
+ {/* */}
);
}
diff --git a/frontend/src/database/data-catalog.ts b/frontend/src/database/data-catalog.ts
index 957bd25..70a9827 100644
--- a/frontend/src/database/data-catalog.ts
+++ b/frontend/src/database/data-catalog.ts
@@ -1,23 +1,12 @@
import { Course } from "@/types/type-user";
+import { HSAR_401 } from "./data-courses";
interface Catalog {
number: number;
courses: Course[];
}
-export const CPSC_201: Course = { codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_202: Course = { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const MATH_244: Course = { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_223: Course = { codes: ["CPSC 223"], title: "Data Structures And Programming Techniques", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_323: Course = { codes: ["CPSC 323"], title: "Introduction To Systems Programming", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_365: Course = { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_366: Course = { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_490: Course = { codes: ["CPSC 490"], title: "Senior Project", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-export const HSAR_401: Course = { codes: ["HSAR 401"], title: "Critical Approaches To Art History", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-
export const Catalogs: Catalog[] = [
{ number: 202203, courses: [HSAR_401] },
{ number: 202301, courses: [HSAR_401] },
diff --git a/frontend/src/database/data-courses.ts b/frontend/src/database/data-courses.ts
new file mode 100644
index 0000000..c2c42f8
--- /dev/null
+++ b/frontend/src/database/data-courses.ts
@@ -0,0 +1,15 @@
+
+import { Course } from "@/types/type-user"
+
+// HSAR ONE
+export const HSAR_401: Course = { codes: ["HSAR 401"], title: "Critical Approaches To Art History", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+// CPSC PROGRAM
+export const CPSC_201: Course = { codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_202: Course = { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_244: Course = { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_223: Course = { codes: ["CPSC 223"], title: "Data Structures And Programming Techniques", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_323: Course = { codes: ["CPSC 323"], title: "Introduction To Systems Programming", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_365: Course = { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_366: Course = { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_490: Course = { codes: ["CPSC 490"], title: "Senior Project", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
diff --git a/frontend/src/database/data-cpsc.ts b/frontend/src/database/data-cpsc.ts
index 13f53a6..6ddd52e 100644
--- a/frontend/src/database/data-cpsc.ts
+++ b/frontend/src/database/data-cpsc.ts
@@ -1,7 +1,8 @@
-
import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./data-catalog";
+
+import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./data-courses";
+import { SC_CPSC_201, SC_CPSC_202, SC_CPSC_223, SC_CPSC_323 } from "./data-studentcourses";
const CPSC_INTRO: DegreeSubrequirement = {
subreq_type_id: 1,
@@ -11,7 +12,7 @@ const CPSC_INTRO: DegreeSubrequirement = {
courses_options: [CPSC_201],
courses_elective_range: null,
courses_any_bool: false,
- user_courses_satisfying: [CPSC_201],
+ student_courses_satisfying: [SC_CPSC_201],
}
const CPSC_MATH: DegreeSubrequirement = {
@@ -22,7 +23,7 @@ const CPSC_MATH: DegreeSubrequirement = {
courses_options: [CPSC_202, MATH_244],
courses_elective_range: null,
courses_any_bool: false,
- user_courses_satisfying: [],
+ student_courses_satisfying: [],
}
const CPSC_DATA: DegreeSubrequirement = {
@@ -33,7 +34,7 @@ const CPSC_DATA: DegreeSubrequirement = {
courses_options: [CPSC_223],
courses_elective_range: null,
courses_any_bool: false,
- user_courses_satisfying: [CPSC_223],
+ student_courses_satisfying: [SC_CPSC_223],
}
const CPSC_SYSTEMS: DegreeSubrequirement = {
@@ -44,7 +45,7 @@ const CPSC_SYSTEMS: DegreeSubrequirement = {
courses_options: [CPSC_323],
courses_elective_range: null,
courses_any_bool: false,
- user_courses_satisfying: [CPSC_323],
+ student_courses_satisfying: [SC_CPSC_323],
}
const CPSC_ALGOS: DegreeSubrequirement = {
@@ -55,45 +56,51 @@ const CPSC_ALGOS: DegreeSubrequirement = {
courses_options: [CPSC_365, CPSC_366],
courses_elective_range: null,
courses_any_bool: false,
- user_courses_satisfying: [],
+ student_courses_satisfying: [],
}
const CPSC_CORE: DegreeRequirement = {
req_type_id: 1,
req_name: "CORE",
req_desc: "",
- subreqs_required: 5,
+
+ courses_required_count: 5,
+ courses_satisfied_count: 3,
+
subreqs_list: [CPSC_INTRO, CPSC_MATH, CPSC_DATA, CPSC_SYSTEMS, CPSC_ALGOS]
}
const CPSC_RANGE_ELECS: DegreeSubrequirement = {
subreq_type_id: 1,
subreq_name: "",
- subreq_desc: "",
+ subreq_desc: "Standard elective or DUS approved extra-department substitution.",
courses_required: 1,
- courses_options: [],
+ courses_options: [null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: false,
- user_courses_satisfying: []
+ student_courses_satisfying: []
}
const CPSC_SUB_ELEC: DegreeSubrequirement = {
subreq_type_id: 1,
subreq_name: "",
- subreq_desc: "",
+ subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
courses_required: 3,
- courses_options: [],
+ courses_options: [null, null, null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: true,
- user_courses_satisfying: []
+ student_courses_satisfying: []
}
const CPSC_ELECTIVES: DegreeRequirement = {
req_type_id: 1,
req_name: "ELECTIVE",
req_desc: "",
- subreqs_required: 4,
- subreqs_list: [CPSC_RANGE_ELECS, CPSC_SUB_ELEC]
+
+ courses_required_count: 4,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [CPSC_SUB_ELEC, CPSC_RANGE_ELECS]
}
const CPSC_SENPROJ: DegreeSubrequirement = {
@@ -104,14 +111,17 @@ const CPSC_SENPROJ: DegreeSubrequirement = {
courses_options: [CPSC_490],
courses_elective_range: null,
courses_any_bool: false,
- user_courses_satisfying: []
+ student_courses_satisfying: []
}
const CPSC_SENIOR: DegreeRequirement = {
req_type_id: 1,
req_name: "SENIOR",
req_desc: "",
- subreqs_required: 1,
+
+ courses_required_count: 1,
+ courses_satisfied_count: 0,
+
subreqs_list: [CPSC_SENPROJ]
}
diff --git a/frontend/src/database/data-studentcourses.ts b/frontend/src/database/data-studentcourses.ts
new file mode 100644
index 0000000..1fedb89
--- /dev/null
+++ b/frontend/src/database/data-studentcourses.ts
@@ -0,0 +1,11 @@
+
+import { StudentCourse } from "@/types/type-user"
+import { CPSC_201, CPSC_202, CPSC_223, CPSC_323 } from "./data-courses"
+
+export const SC_CPSC_201: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_201 }
+export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
+export const SC_CPSC_223: StudentCourse = { term: 202501, status: "DA", result: "GRADE_PASS", course: CPSC_223 }
+export const SC_CPSC_323: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_323 }
+
+
+
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index 0a02b75..ea0c37b 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,5 +1,7 @@
import { User } from "./../types/type-user";
+
+import { SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "./data-studentcourses";
import { CPSC_CONFIG } from "./data-cpsc";
export const Ryan: User = {
@@ -7,11 +9,7 @@ export const Ryan: User = {
netID: "rgg32",
onboard: false,
FYP: {
- studentCourses: [
- { term: 202403, status: "DA", result: "GRADE_PASS", course: { codes: ["CPSC 201"], title: "Intro To Computer Science", credit: 1, dist: ["QR"], seasons: [] } },
- { term: 202501, status: "DA", result: "GRADE_PASS", course: { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: [] } },
- { term: 202503, status: "MA", result: "IP", course: { codes: ["CPSC 223"], title: "Data Structures", credit: 1, dist: ["QR"], seasons: [] } },
- ],
+ studentCourses: [SC_CPSC_201, SC_CPSC_223, SC_CPSC_323],
studentTermArrangement: {
first_year: [0, 202403, 202501],
sophomore: [0, 202503, 202601],
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 95148d4..2eda0b0 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -1,5 +1,5 @@
-import { Course } from "./type-user";
+import { Course, StudentCourse } from "./type-user";
export interface StudentDegree {
status: string; // DA | ADD | PIN
@@ -49,11 +49,11 @@ export interface DegreeSubrequirement {
subreq_desc: string;
courses_required: number;
- courses_options: Course[];
+ courses_options: (Course | null)[];
courses_elective_range: SubreqElectiveRange;
courses_any_bool: boolean;
- user_courses_satisfying: Course[];
+ student_courses_satisfying: StudentCourse[];
}
export interface DegreeRequirement {
@@ -61,7 +61,9 @@ export interface DegreeRequirement {
req_name: string;
req_desc: string;
- subreqs_required: number;
+ courses_required_count: number;
+ courses_satisfied_count: number;
+
subreqs_list: DegreeSubrequirement[];
}
From c3f90132f45e343acce4ad9ea578e9d35337068f Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Sun, 9 Mar 2025 11:35:07 -0700
Subject: [PATCH 15/38] more majors
---
frontend/src/app/majors/page.tsx | 1 +
.../requirements/Requirements.module.css | 33 ++-
.../app/majors/requirements/Requirements.tsx | 164 +++++++++-----
.../course-icon/CourseIcon.module.css | 31 +--
.../src/database/{ => configs}/data-cpsc.ts | 4 +-
frontend/src/database/configs/data-econ.ts | 162 ++++++++++++++
frontend/src/database/configs/data-hist.ts | 202 ++++++++++++++++++
frontend/src/database/configs/data-plsc.ts | 162 ++++++++++++++
frontend/src/database/data-courses.ts | 27 +++
frontend/src/database/data-degree.ts | 86 ++++----
frontend/src/database/data-studentcourses.ts | 5 +-
frontend/src/database/data-user.ts | 36 ++--
frontend/src/types/type-program.ts | 6 +-
13 files changed, 763 insertions(+), 156 deletions(-)
rename frontend/src/database/{ => configs}/data-cpsc.ts (97%)
create mode 100644 frontend/src/database/configs/data-econ.ts
create mode 100644 frontend/src/database/configs/data-hist.ts
create mode 100644 frontend/src/database/configs/data-plsc.ts
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 1ebc057..38552a1 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -44,6 +44,7 @@ function Majors()
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index 4efc472..ab5aa0b 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -58,11 +58,11 @@
.EmptyCourse {
border-radius: 15px;
- padding: 2px 2px;
- background-color: #e7e7e7c3;
+ /* padding: 2px 2px; e7e7e7c3 */
+ background-color: #F5F5F5;
transition: filter 0.4s ease;
- width: 15px; /* Adjust width to match CourseIcon */
- height: 15px; /* Adjust height to match CourseIcon */
+ width: 24px; /* Adjust width to match CourseIcon */
+ height: 24px; /* Adjust height to match CourseIcon */
display: inline-block; /* Keeps it inline with other elements */
}
@@ -110,3 +110,28 @@
.resetButton:active, .editButton:active {
color: #333; /* Darker color on click */
}
+
+
+
+
+.ButtonRow {
+ display: flex;
+ gap: 6px;
+ margin-bottom: 2px;
+}
+
+.SubreqButton {
+ font-size: 10px;
+ padding: 3px;
+
+ cursor: pointer;
+ border-radius: 6px;
+
+ background-color: rgb(211, 211, 211);
+ color: white;
+ transition: background-color 0.3s ease;
+}
+
+.SubreqButton.Selected {
+ background-color: rgb(100, 178, 238);
+}
\ No newline at end of file
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 238d988..da62ea5 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -2,12 +2,13 @@
import { useState } from "react";
import Style from "./Requirements.module.css";
+import { useAuth } from "@/app/providers";
+
import { User, Course } from "@/types/type-user";
import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
import { CourseIcon } from "@/components/course-icon/CourseIcon";
-
function RenderSubrequirementCourse(props: { course: Course | null, subreq: DegreeSubrequirement; user: User }){
// TODO
@@ -29,85 +30,142 @@ function RenderSubrequirementCourse(props: { course: Course | null, subreq: Degr
)
}
-function RenderSubrequirement(props: { subreq: DegreeSubrequirement, user: User })
-{
+function RenderSubrequirement(props: { subreq: DegreeSubrequirement; user: User }) {
const [showAll, setShowAll] = useState(false);
- // Extract non-null courses
+ // Separate null and non-null courses
+ const nullCourses = props.subreq.courses_options.filter((course) => course === null);
const nonNullCourses = props.subreq.courses_options.filter((course) => course !== null) as Course[];
const satisfiedCourses = props.subreq.student_courses_satisfying.map((studentCourse) => studentCourse.course);
- // Determine which courses to show based on satisfaction condition
+ // Determine which courses to show
const isSatisfied = props.subreq.student_courses_satisfying.length === props.subreq.courses_required;
- const displayedCourses = showAll
+ const displayedNonNullCourses = showAll
? nonNullCourses
: isSatisfied
? satisfiedCourses
: nonNullCourses.slice(0, 4);
- const extraCoursesCount = showAll ? 0 : nonNullCourses.length - displayedCourses.length;
+ // Ensure null courses are always displayed
+ const displayedCourses = [...nullCourses, ...displayedNonNullCourses];
- return(
-
-
- {props.subreq.student_courses_satisfying.length}|{props.subreq.courses_required} {props.subreq.subreq_name}
-
-
+ return (
+
+
+ {props.subreq.student_courses_satisfying.length}|{props.subreq.courses_required} {props.subreq.subreq_name}
+
+
{props.subreq.subreq_desc}
-
- {displayedCourses.map((course, index) => (
-
-
-
- ))}
- {/* Show More / Show Less Button */}
- {nonNullCourses.length > 4 && (
-
setShowAll(!showAll)}>
- {showAll ? "<<" : ">>"}
-
)
- }
-
-
- )
+
+ {displayedCourses.map((course, index) => (
+
+
+
+ ))}
+ {/* Toggle Button to Expand / Collapse */}
+ {nonNullCourses.length > 4 && (
+
setShowAll(!showAll)}>
+ {showAll ? "<<" : ">>"}
+
+ )}
+
+
+ );
}
-function RenderRequirement(props: { req: DegreeRequirement, user: User })
-{
- return(
-
-
-
-
- {props.req.req_name}
-
-
- {props.req.courses_satisfied_count}|{props.req.courses_required_count}
-
-
-
-
- {props.req.subreqs_list.map((subreq, index) => (
-
- ))}
-
-
- )
+function RenderRequirement(props: { programIndex: number, req: DegreeRequirement; user: User }){
+
+ const { user, setUser } = useAuth();
+ const { req, programIndex } = props;
+ const { subreqs_list, subreqs_required_count } = req;
+
+ // Get the correct degree configuration (assumes only one degree per program)
+ const degreeConfig = user.FYP.degreeConfigurations[programIndex][0];
+
+ // Find the corresponding requirement in `degreeConfig`
+ const requirement = degreeConfig.reqs_list.find((r: DegreeRequirement) => r.req_name === req.req_name);
+
+ if (!requirement) return null; // Fail-safe, shouldn't happen
+
+ // Move clicked subreq to the front if it's beyond the first `subreqs_required_count`
+ const handleSubreqClick = (subreq: DegreeSubrequirement) => {
+ if (!subreqs_required_count) return; // Ignore clicks if not applicable
+
+ setUser((prevUser: User) => {
+ const newUser = { ...prevUser };
+
+ // Get the degree and requirement again inside state update
+ const updatedDegree = newUser.FYP.degreeConfigurations[programIndex][0];
+ const updatedRequirement = updatedDegree.reqs_list.find((r) => r.req_name === req.req_name);
+
+ if (!updatedRequirement) return prevUser; // Failsafe
+
+ const updatedSubreqs = [...updatedRequirement.subreqs_list];
+ const index = updatedSubreqs.findIndex((s) => s.subreq_name === subreq.subreq_name);
+
+ if (index >= subreqs_required_count) {
+ // Move it to the front
+ updatedSubreqs.splice(index, 1);
+ updatedSubreqs.unshift(subreq);
+ }
+
+ // Update the requirement's subreqs_list in user state
+ updatedRequirement.subreqs_list = updatedSubreqs;
+
+ return newUser;
+ });
+ };
+
+
+ return (
+
+
+
{props.req.req_name}
+
+ {props.req.checkbox !== undefined ? props.req.courses_satisfied_count === props.req.courses_required_count ? "✅" : "❌" : `${props.req.courses_satisfied_count}|${props.req.courses_required_count}`}
+
+
+
+ {/* Subreq Toggle Buttons - Only show if subreqs_required_count exists and < total subreqs */}
+ {subreqs_required_count && subreqs_list.length > subreqs_required_count && (
+
+ {subreqs_list.map((subreq, index) => (
+
handleSubreqClick(subreq)}>
+ {subreq.subreq_name}
+
+ ))}
+
+ )}
+
+ {/* Display Selected Subreqs - Enforce subreqs_required_count if present */}
+
+ {subreqs_required_count
+ ? subreqs_list.slice(0, subreqs_required_count).map((subreq, index) => (
+
+ ))
+ : subreqs_list.map((subreq, index) => (
+
+ ))}
+
+
+ );
}
-function RequirementsContent(props: { edit: boolean, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function })
+
+function RequirementsContent(props: { edit: boolean, programIndex: number, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function })
{
return(
{props.degreeConfiguration.reqs_list.map((req, index) => (
-
+
))}
);
}
-function Requirements(props: { user: User, setUser: Function, degreeConfiguration: DegreeConfiguration })
+function Requirements(props: { user: User, setUser: Function, programIndex: number, degreeConfiguration: DegreeConfiguration })
{
const [edit, setEdit] = useState(false);
@@ -128,7 +186,7 @@ function Requirements(props: { user: User, setUser: Function, degreeConfiguratio
-
+
);
diff --git a/frontend/src/components/course-icon/CourseIcon.module.css b/frontend/src/components/course-icon/CourseIcon.module.css
index 7efaaa5..a4dac89 100644
--- a/frontend/src/components/course-icon/CourseIcon.module.css
+++ b/frontend/src/components/course-icon/CourseIcon.module.css
@@ -9,6 +9,7 @@
width: max-content;
padding: 2px 4px;
+ min-height: 18px;
font-size: 14px;
font-weight: bold;
@@ -21,33 +22,3 @@
cursor: pointer;
filter: brightness(95%);
}
-
-.Mark {
- padding-left: 1px;
- padding-right: 1px;
-}
-
-
-
-
-.OrIconContainer {
- display: flex;
- align-items: center;
- padding: 2px 4px;
- border-radius: 15px;
- background-color: #e3e3e3;
- transition: filter 0.4s ease;
- margin-right: 2px;
-}
-
-.OrIconContainer:hover {
- cursor: pointer;
- filter: brightness(95%);
-}
-
-.OrSeparator {
- margin-bottom: 3px;
- margin-right: 2px;
- font-size: 14px;
- font-weight: bold;
-}
\ No newline at end of file
diff --git a/frontend/src/database/data-cpsc.ts b/frontend/src/database/configs/data-cpsc.ts
similarity index 97%
rename from frontend/src/database/data-cpsc.ts
rename to frontend/src/database/configs/data-cpsc.ts
index 6ddd52e..afdbc40 100644
--- a/frontend/src/database/data-cpsc.ts
+++ b/frontend/src/database/configs/data-cpsc.ts
@@ -1,8 +1,8 @@
import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./data-courses";
-import { SC_CPSC_201, SC_CPSC_202, SC_CPSC_223, SC_CPSC_323 } from "./data-studentcourses";
+import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./../data-courses";
+import { SC_CPSC_201, SC_CPSC_202, SC_CPSC_223, SC_CPSC_323 } from "./../data-studentcourses";
const CPSC_INTRO: DegreeSubrequirement = {
subreq_type_id: 1,
diff --git a/frontend/src/database/configs/data-econ.ts b/frontend/src/database/configs/data-econ.ts
new file mode 100644
index 0000000..68adfb1
--- /dev/null
+++ b/frontend/src/database/configs/data-econ.ts
@@ -0,0 +1,162 @@
+
+import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+
+import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "../data-courses";
+import { SC_ECON_110 } from "../data-studentcourses";
+
+// INTRO
+
+const ECON_MATH: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "MATH",
+ subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
+ courses_required: 1,
+ courses_options: [null, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_INTRO_MICRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTRO MICRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_108, ECON_110, ECON_115],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [SC_ECON_110],
+}
+
+const ECON_INTRO_MACRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTRO MACRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_111, ECON_116],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_INTRO: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "INTRO",
+ req_desc: "",
+
+ courses_required_count: 3,
+ courses_satisfied_count: 1,
+
+ subreqs_list: [ECON_MATH, ECON_INTRO_MICRO, ECON_INTRO_MACRO]
+}
+
+// CORE
+
+const ECON_CORE_MICRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTERMEDIATE MICRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_121, ECON_125],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE_MACRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTERMEDIATE MACRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_122, ECON_126],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE_METRICS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "ECONOMETRICS",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_117, ECON_123, ECON_136],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "CORE",
+ req_desc: "",
+
+ courses_required_count: 3,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [ECON_CORE_MICRO, ECON_CORE_MACRO, ECON_CORE_METRICS]
+}
+
+// ELECTIVE
+
+const ECON_RANGE_ELECS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "Standard elective or DUS approved extra-department substitution.",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SUB_ELEC: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
+ courses_required: 3,
+ courses_options: [null, null, null],
+ courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
+ courses_any_bool: true,
+ student_courses_satisfying: []
+}
+
+const ECON_ELECTIVES: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "ELECTIVE",
+ req_desc: "",
+
+ courses_required_count: 4,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [ECON_SUB_ELEC, ECON_RANGE_ELECS]
+}
+
+// SENIOR
+
+const ECON_SEN_SUB: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "SENIOR REQUIREMENT",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SENIOR: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "SENIOR",
+ req_desc: "",
+
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [ECON_SEN_SUB]
+}
+
+// FINAL
+
+export const ECON_CONFIG: DegreeConfiguration = {
+ reqs_list: [ECON_INTRO, ECON_CORE, ECON_ELECTIVES, ECON_SENIOR]
+}
diff --git a/frontend/src/database/configs/data-hist.ts b/frontend/src/database/configs/data-hist.ts
new file mode 100644
index 0000000..f551242
--- /dev/null
+++ b/frontend/src/database/configs/data-hist.ts
@@ -0,0 +1,202 @@
+
+import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+
+// PRE
+
+const HIST_PRE: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "PRE 1800",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_PREINDUSTRIAL: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "PREINDUSTRIAL",
+ req_desc: "",
+
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+
+ checkbox: true,
+ subreqs_list: [HIST_PRE]
+}
+
+// GLOBAL
+
+const HIST_CORE_GLOB_AFRICA: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "AFRICA",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_CORE_GLOB_ASIA: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "ASIA",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_CORE_GLOB_EUROPE: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "EUROPE",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_CORE_GLOB_LA: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "LATIN AMERICA",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_CORE_GLOB_ME: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "MIDDLE EAST",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_CORE_GLOB_US: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "U.S.",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_GLOB_CORE: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "GLOBAL",
+ req_desc: "",
+
+ courses_required_count: 5,
+ courses_satisfied_count: 0,
+
+ subreqs_required_count: 5,
+ subreqs_satisfied_count: 0,
+
+ subreqs_list: [HIST_CORE_GLOB_AFRICA, HIST_CORE_GLOB_ASIA, HIST_CORE_GLOB_EUROPE, HIST_CORE_GLOB_LA, HIST_CORE_GLOB_ME, HIST_CORE_GLOB_US]
+}
+
+// SEMINAR
+
+const HIST_DEPT_SEMINAR: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "DEPARTMENTAL",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const HIST_SEMINAR: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "SEMINAR",
+ req_desc: "",
+
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+
+ checkbox: true,
+ subreqs_list: [HIST_DEPT_SEMINAR]
+}
+
+// ELECTIVE
+
+const HIST_ELEC_INDIV: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "",
+ courses_required: 5,
+ courses_options: [null, null, null, null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const HIST_ELECTIVE: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "ELECTIVE",
+ req_desc: "",
+
+ courses_required_count: 5,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [HIST_ELEC_INDIV]
+}
+
+// SENIOR
+
+const ECON_SEN_ONE: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "ONE TERM",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SEN_TWO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "TWO TERM",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SENIOR: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "SENIOR",
+ req_desc: "",
+
+ courses_required_count: 0,
+ courses_satisfied_count: 0,
+
+ subreqs_required_count: 1,
+ subreqs_satisfied_count: 0,
+
+ subreqs_list: [ECON_SEN_ONE, ECON_SEN_TWO]
+}
+
+// FINAL
+
+export const HIST_CONFIG: DegreeConfiguration = {
+ reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_GLOB_CORE, HIST_ELECTIVE, ECON_SENIOR]
+}
diff --git a/frontend/src/database/configs/data-plsc.ts b/frontend/src/database/configs/data-plsc.ts
new file mode 100644
index 0000000..55b7cc8
--- /dev/null
+++ b/frontend/src/database/configs/data-plsc.ts
@@ -0,0 +1,162 @@
+
+import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+
+import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "../data-courses";
+import { SC_ECON_110 } from "../data-studentcourses";
+
+// INTRO
+
+const ECON_MATH: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "MATH",
+ subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
+ courses_required: 1,
+ courses_options: [null, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_INTRO_MICRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTRO MICRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_108, ECON_110, ECON_115],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [SC_ECON_110],
+}
+
+const ECON_INTRO_MACRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTRO MACRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_111, ECON_116],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_INTRO: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "INTRO",
+ req_desc: "",
+
+ courses_required_count: 3,
+ courses_satisfied_count: 1,
+
+ subreqs_list: [ECON_MATH, ECON_INTRO_MICRO, ECON_INTRO_MACRO]
+}
+
+// CORE
+
+const ECON_CORE_MICRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTERMEDIATE MICRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_121, ECON_125],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE_MACRO: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "INTERMEDIATE MACRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_122, ECON_126],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE_METRICS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "ECONOMETRICS",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_117, ECON_123, ECON_136],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "CORE",
+ req_desc: "",
+
+ courses_required_count: 3,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [ECON_CORE_MICRO, ECON_CORE_MACRO, ECON_CORE_METRICS]
+}
+
+// ELECTIVE
+
+const ECON_RANGE_ELECS: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "Standard elective or DUS approved extra-department substitution.",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SUB_ELEC: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "",
+ subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
+ courses_required: 3,
+ courses_options: [null, null, null],
+ courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
+ courses_any_bool: true,
+ student_courses_satisfying: []
+}
+
+const ECON_ELECTIVES: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "ELECTIVE",
+ req_desc: "",
+
+ courses_required_count: 4,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [ECON_SUB_ELEC, ECON_RANGE_ELECS]
+}
+
+// SENIOR
+
+const ECON_SEN_SUB: DegreeSubrequirement = {
+ subreq_type_id: 1,
+ subreq_name: "SENIOR REQUIREMENT",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SENIOR: DegreeRequirement = {
+ req_type_id: 1,
+ req_name: "SENIOR",
+ req_desc: "",
+
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+
+ subreqs_list: [ECON_SEN_SUB]
+}
+
+// FINAL
+
+export const PLSC_CONFIG: DegreeConfiguration = {
+ reqs_list: [ECON_INTRO, ECON_CORE, ECON_ELECTIVES, ECON_SENIOR]
+}
diff --git a/frontend/src/database/data-courses.ts b/frontend/src/database/data-courses.ts
index c2c42f8..71e83a5 100644
--- a/frontend/src/database/data-courses.ts
+++ b/frontend/src/database/data-courses.ts
@@ -13,3 +13,30 @@ export const CPSC_323: Course = { codes: ["CPSC 323"], title: "Introduction To S
export const CPSC_365: Course = { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const CPSC_366: Course = { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const CPSC_490: Course = { codes: ["CPSC 490"], title: "Senior Project", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+// ECON PROGRAM
+export const MATH_110: Course = { codes: ["MATH 110"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_111: Course = { codes: ["MATH 111"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_112: Course = { codes: ["MATH 112"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_115: Course = { codes: ["MATH 115"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_116: Course = { codes: ["MATH 116"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ENAS_151: Course = { codes: ["ENAS 151"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_118: Course = { codes: ["MATH 118"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_120: Course = { codes: ["MATH 120"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+export const ECON_108: Course = { codes: ["ECON 108"], title: "Introductory Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_110: Course = { codes: ["ECON 110"], title: "Introductory Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_115: Course = { codes: ["ECON 115"], title: "Introductory Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+export const ECON_111: Course = { codes: ["ECON 111"], title: "Introductory Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_116: Course = { codes: ["ECON 116"], title: "Introductory Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+export const ECON_121: Course = { codes: ["ECON 121"], title: "Intermediate Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_125: Course = { codes: ["ECON 125"], title: "Intermediate Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+export const ECON_122: Course = { codes: ["ECON 122"], title: "Intermediate Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_126: Course = { codes: ["ECON 126"], title: "Intermediate Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+export const ECON_117: Course = { codes: ["ECON 117"], title: "Econometrics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_123: Course = { codes: ["ECON 123"], title: "Econometrics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_136: Course = { codes: ["ECON 136"], title: "Econometrics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
diff --git a/frontend/src/database/data-degree.ts b/frontend/src/database/data-degree.ts
index 1536dd2..ca1b720 100644
--- a/frontend/src/database/data-degree.ts
+++ b/frontend/src/database/data-degree.ts
@@ -2,48 +2,48 @@
import { DegreeMetadata } from "@/types/type-program";
export const ALL_PROGRAM_METADATAS: DegreeMetadata[][] = [
- [{
- name: "Computer Science",
- abbr: "CPSC",
- degreeType: "BACH_ART",
- dus: { address: "AKW 208 432-6400", email: "cpsc.yale.edu", name: "Y. Richard Yang" },
- about: "The Department of Computer Science offers a B.A. degree program, as well as four combined major programs in cooperation with other departments: Electrical Engineering and Computer Science, Computer Science and Economics, Computer Science and Mathematics, and Computer Science and Psychology. Each program not only provides a solid technical education but also allows students either to take a broad range of courses in other disciplines or to complete the requirements of a second major.",
- stats: { courses: 10, rating: 0, type: "QR", workload: 0 },
- students: 0,
- wesbiteLink: "http://cpsc.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/computer-science/",
- }],
- [{
- name: "History",
- abbr: "HIST",
- degreeType: "BACH_ART",
- dus: { address: "AKW 208 432-6400", email: "cpsc.yale.edu", name: "Y. Richard Yang" },
- about: "The History major is for students who understand that shaping the future requires knowing the past. History courses explore many centuries of human experimentation and ingenuity, from the global to the individual scale. History majors learn to be effective storytellers and analysts, and to craft arguments that speak to broad audiences. They make extensive use of Yale’s vast library resources to create pioneering original research projects. Students of history learn to think about politics and government, sexuality, the economy, cultural and intellectual life, war and society, and other themes in broadly humanistic—rather than narrowly technocratic—ways.",
- stats: { courses: 10, rating: 0, type: "QR", workload: 0 },
- students: 0,
- wesbiteLink: "http://cpsc.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/computer-science/",
- }],
- [{
- name: "Political Science",
- abbr: "PLSC",
- degreeType: "BACH_ART",
- dus: { address: "AKW 208 432-6400", email: "cpsc.yale.edu", name: "Y. Richard Yang" },
- about: "Political science addresses how individuals and groups organize, allocate, and challenge the power to make collective decisions involving public issues. The goal of the major is to enable students to think critically and analytically about the agents, incentives, and institutions that shape political phenomena within human society. The subfields of political philosophy and analytical political theory (which includes the study of both qualitative and quantitative methodology) support the acquisition of the lenses through which such thought skills can be enriched.",
- stats: { courses: 10, rating: 0, type: "QR", workload: 0 },
- students: 0,
- wesbiteLink: "http://cpsc.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/computer-science/",
- }],
[{
- name: "Environmental Studies",
- abbr: "EVST",
- degreeType: "BACH_ART",
- dus: { address: "AKW 208 432-6400", email: "cpsc.yale.edu", name: "Y. Richard Yang" },
- about: "Environmental Studies offers the opportunity to examine human relations with their environments from diverse perspectives. The major encourages interdisciplinary study in (1) social sciences, including anthropology, political science, law, economics, and ethics; (2) humanities, to include history, literature, religion, and the arts; and (3) natural sciences, such as biology, ecology, human health, geology, and chemistry. Students work with faculty advisers and the directors of undergraduate studies (DUS) to concentrate on some of the most pressing environmental and sustainability problems of our time.",
- stats: { courses: 10, rating: 0, type: "QR", workload: 0 },
- students: 0,
- wesbiteLink: "http://cpsc.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/computer-science/",
- }]
+ name: "History",
+ abbr: "HIST",
+ degreeType: "BACH_ART",
+ dus: { address: "HQ 211, (203) 432-1366", email: "history@yale.edu", name: "Alan Mikhail" },
+ about: "The History major offers a broad exploration of human experience across time, cultures, and societies. Students gain expertise in archival research, critical analysis, and historical interpretation. The major prepares students to engage with contemporary issues by understanding their historical contexts, whether in politics, economics, or cultural transformations. History students learn to construct arguments based on evidence and develop a strong capacity for analytical reasoning and effective communication.",
+ stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
+ students: 0,
+ wesbiteLink: "https://history.yale.edu",
+ catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/history/",
+ }],
+ [{
+ name: "Computer Science",
+ abbr: "CPSC",
+ degreeType: "BACH_ART",
+ dus: { address: "AKW 208, (203) 432-6400", email: "cpsc@yale.edu", name: "Y. Richard Yang" },
+ about: "The Department of Computer Science offers a B.A. degree program, as well as four combined major programs in cooperation with other departments: Electrical Engineering and Computer Science, Computer Science and Economics, Computer Science and Mathematics, and Computer Science and Psychology. Each program not only provides a solid technical education but also allows students either to take a broad range of courses in other disciplines or to complete the requirements of a second major.",
+ stats: { courses: 0, rating: 0, type: "QR", workload: 0 },
+ students: 0,
+ wesbiteLink: "http://cpsc.yale.edu",
+ catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/computer-science/",
+ }],
+ [{
+ name: "Political Science",
+ abbr: "PLSC",
+ degreeType: "BACH_ART",
+ dus: { address: "Rosenkranz Hall 130, (203) 432-5248", email: "politicalscience@yale.edu", name: "Isabela Mares" },
+ about: "The Political Science major examines governments, political behavior, and institutional structures at local, national, and global levels. Students engage with the theoretical foundations of politics, quantitative and qualitative methodologies, and policy analysis. The program prepares students for careers in law, public policy, international relations, and academia while offering flexibility to explore subfields such as comparative politics, American politics, and political philosophy.",
+ stats: { courses: 0, rating: 0, type: "So", workload: 0 },
+ students: 0,
+ wesbiteLink: "https://politicalscience.yale.edu",
+ catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/political-science/",
+ }],
+ [{
+ name: "Economics",
+ abbr: "ECON",
+ degreeType: "BACH_ART",
+ dus: { address: "28 Hillhouse Ave, (203) 432-3576", email: "economics@yale.edu", name: "Dirk Bergemann" },
+ about: "The Economics major provides a rigorous framework for understanding financial markets, public policy, and decision-making. Students learn analytical techniques in microeconomics, macroeconomics, and econometrics, developing critical skills in data interpretation and policy evaluation. The major offers pathways in finance, economic development, and quantitative analysis, preparing students for careers in government, consulting, business, and research.",
+ stats: { courses: 0, rating: 0, type: "QR", workload: 0 },
+ students: 0,
+ wesbiteLink: "https://economics.yale.edu",
+ catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/economics/",
+ }]
];
diff --git a/frontend/src/database/data-studentcourses.ts b/frontend/src/database/data-studentcourses.ts
index 1fedb89..54120ca 100644
--- a/frontend/src/database/data-studentcourses.ts
+++ b/frontend/src/database/data-studentcourses.ts
@@ -1,11 +1,14 @@
import { StudentCourse } from "@/types/type-user"
-import { CPSC_201, CPSC_202, CPSC_223, CPSC_323 } from "./data-courses"
+import { CPSC_201, CPSC_202, CPSC_223, CPSC_323, ECON_110 } from "./data-courses"
+// CPSC COURSES
export const SC_CPSC_201: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_201 }
export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
export const SC_CPSC_223: StudentCourse = { term: 202501, status: "DA", result: "GRADE_PASS", course: CPSC_223 }
export const SC_CPSC_323: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_323 }
+// ECON COURSES
+export const SC_ECON_110: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: ECON_110 }
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index ea0c37b..e60e861 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,31 +1,30 @@
import { User } from "./../types/type-user";
-import { SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "./data-studentcourses";
-import { CPSC_CONFIG } from "./data-cpsc";
+import { CPSC_CONFIG } from "./configs/data-cpsc";
+import { ECON_CONFIG } from "./configs/data-econ";
+import { HIST_CONFIG } from "./configs/data-hist";
+import { PLSC_CONFIG } from "./configs/data-plsc";
export const Ryan: User = {
name: "Ryan",
netID: "rgg32",
onboard: false,
FYP: {
- studentCourses: [SC_CPSC_201, SC_CPSC_223, SC_CPSC_323],
+ studentCourses: [],
studentTermArrangement: {
first_year: [0, 202403, 202501],
sophomore: [0, 202503, 202601],
junior: [0, 202603, 202701],
senior: [0, 202703, 202801],
},
- languagePlacement: {
- language: "Spanish",
- level: 5,
- },
+ languagePlacement: { language: "Spanish", level: 5 },
degreeDeclarations: [],
degreeConfigurations: [
+ [HIST_CONFIG],
[CPSC_CONFIG],
- [],
- [],
- []
+ [PLSC_CONFIG],
+ [ECON_CONFIG]
],
}
}
@@ -42,20 +41,13 @@ export const NullUser: User = {
junior: [],
senior: [],
},
- languagePlacement: {
- language: "",
- level: 0,
- },
+ languagePlacement: { language: "", level: 0 },
degreeDeclarations: [],
degreeConfigurations: [
- [
- ],
- [
- ],
- [
- ],
- [
- ]
+ [],
+ [],
+ [],
+ []
],
}
}
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 2eda0b0..59c1bf4 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -63,7 +63,11 @@ export interface DegreeRequirement {
courses_required_count: number;
courses_satisfied_count: number;
-
+
+ subreqs_required_count?: number;
+ subreqs_satisfied_count?: number;
+
+ checkbox?: boolean;
subreqs_list: DegreeSubrequirement[];
}
From 63eb98c8852dba844f985f3fd3d75b9baf468574 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Mon, 10 Mar 2025 14:33:27 -0700
Subject: [PATCH 16/38] bloody trainwreck
---
.../app/majors/metadata/Metadata.module.css | 34 +++
frontend/src/app/majors/metadata/Metadata.tsx | 140 +++++----
.../overhead/major-search/MajorSearch.tsx | 2 +-
.../src/app/majors/overhead/pinned/Pinned.tsx | 2 +-
frontend/src/app/majors/page.tsx | 35 +--
.../app/majors/requirements/Requirements.tsx | 99 ++++---
frontend/src/database/configs/data-econ.ts | 162 -----------
frontend/src/database/configs/data-hist.ts | 202 -------------
frontend/src/database/configs/data-plsc.ts | 162 -----------
frontend/src/database/data-degree.ts | 49 ----
frontend/src/database/data-user.ts | 59 ++--
.../data-cpsc.ts => programs/concs-cpsc.ts} | 93 +++---
.../database/programs/configs/config-econ.ts | 162 +++++++++++
.../database/programs/configs/config-hist.ts | 273 ++++++++++++++++++
.../database/programs/configs/config-plsc.ts | 201 +++++++++++++
.../src/database/programs/data-program.ts | 73 +++++
.../src/database/programs/metas/meta-econ.ts | 17 ++
.../src/database/programs/metas/meta-hist.ts | 23 ++
.../src/database/programs/metas/meta-plsc.ts | 17 ++
frontend/src/types/type-program.ts | 75 ++---
frontend/src/types/type-user.ts | 6 +-
21 files changed, 1068 insertions(+), 818 deletions(-)
delete mode 100644 frontend/src/database/configs/data-econ.ts
delete mode 100644 frontend/src/database/configs/data-hist.ts
delete mode 100644 frontend/src/database/configs/data-plsc.ts
delete mode 100644 frontend/src/database/data-degree.ts
rename frontend/src/database/{configs/data-cpsc.ts => programs/concs-cpsc.ts} (53%)
create mode 100644 frontend/src/database/programs/configs/config-econ.ts
create mode 100644 frontend/src/database/programs/configs/config-hist.ts
create mode 100644 frontend/src/database/programs/configs/config-plsc.ts
create mode 100644 frontend/src/database/programs/data-program.ts
create mode 100644 frontend/src/database/programs/metas/meta-econ.ts
create mode 100644 frontend/src/database/programs/metas/meta-hist.ts
create mode 100644 frontend/src/database/programs/metas/meta-plsc.ts
diff --git a/frontend/src/app/majors/metadata/Metadata.module.css b/frontend/src/app/majors/metadata/Metadata.module.css
index eefa8bd..5293146 100644
--- a/frontend/src/app/majors/metadata/Metadata.module.css
+++ b/frontend/src/app/majors/metadata/Metadata.module.css
@@ -92,4 +92,38 @@
.thumbtack:active {
opacity: 0.5; /* Even lighter on click */
+}
+
+
+.ScrollButton {
+ background-color: white;
+ border: none;
+ cursor: pointer;
+ padding: 10px;
+ display: inline-block;
+}
+
+.ToggleContainer {
+ display: flex;
+ flex-direction: row;
+
+ margin-left: 80px;
+ margin-bottom: 8px;
+}
+
+.ToggleOption {
+ padding: 4px 10px;
+ cursor: pointer;
+ background-color: white;
+ color: black;
+ transition: background-color 0.3s, color 0.3s;
+ border-radius: 5px;
+
+ border: 1px solid rgb(196, 196, 196);
+
+}
+
+.ToggleOption.active {
+ background-color: #598ff4;
+ color: white;
}
\ No newline at end of file
diff --git a/frontend/src/app/majors/metadata/Metadata.tsx b/frontend/src/app/majors/metadata/Metadata.tsx
index 87316bc..33f0395 100644
--- a/frontend/src/app/majors/metadata/Metadata.tsx
+++ b/frontend/src/app/majors/metadata/Metadata.tsx
@@ -3,7 +3,7 @@ import { useState, useEffect } from "react";
import Link from 'next/link';
import { User } from "@/types/type-user";
-import { DegreeMetadata } from "@/types/type-program";
+import { Program } from "@/types/type-program";
import { pinProgram, addProgram } from "./MetadataUtils";
import Style from "./Metadata.module.css";
@@ -15,7 +15,7 @@ function MetadataTopshelf(props: {
degreeMetadata: DegreeMetadata
}) {
return (
-
+
pinProgram(props.programIndex, 0, props.user, props.setUser)}>
@@ -27,7 +27,7 @@ function MetadataTopshelf(props: {
{props.degreeMetadata.name}
- {props.degreeMetadata.students}
+ {props.degreeMetadata.info.students}
MAJOR
@@ -41,7 +41,7 @@ function MetadataTopshelf(props: {
);
}
-function MetadataStats(props: { degreeMetadata: DegreeMetadata }){
+function MetadataStats(props: { concMetadata: ConcMetadata }){
return(
@@ -53,81 +53,118 @@ function MetadataStats(props: { degreeMetadata: DegreeMetadata }){
COURSES
- {props.degreeMetadata.stats.courses}
+ {props.concMetadata.stats.courses}
RATING
-
{props.degreeMetadata.stats.rating}
+
{props.concMetadata.stats.rating}
WORKLOAD
-
{props.degreeMetadata.stats.workload}
+
{props.concMetadata.stats.workload}
TYPE
-
{props.degreeMetadata.stats.type}
+
{props.concMetadata.stats.type}
);
}
+function MetadataBody(props: { concIndex: number, degreeMetadata: DegreeMetadata }){
+
+ const { concIndex, degreeMetadata } = props;
+
+ return(
+
+
+
+ ABOUT
+
+
+ {degreeMetadata.concs[concIndex].about}
+
+
+ DUS
+
+
+ {degreeMetadata.info.dus.name}; {degreeMetadata.info.dus.address}
+
+
+
MAJOR CATALOG
+
MAJOR WEBSITE
+
+
+ );
+}
+
+function MetadataToggle(props: { degreeMetadatas: DegreeMetadata[], degreeIndex: number, setDegreeIndex: Function, concIndex: number, setConcIndex: Function }){
+ // TODO
+ // If the currently selected degreeMetadata's concs attribute has length greater than 1, then
+ // display an additional set of identical toggle buttons below the current set where
+ // each divs content is now conc.conc_name and clicking on one calls setConcIndex for the newly clicked one.
+
+ return (
+
+
+ {props.degreeMetadatas.map((metadata, index) => (
+
props.setDegreeIndex(index)}>
+ {metadata.degreeType}
+
+ ))}
+
+
+ {props.degreeMetadatas[props.degreeIndex].concs.length > 1 && (
+
+ {props.degreeMetadatas[props.degreeIndex].concs.map((conc, index) => (
+
props.setConcIndex(index)}>
+ {conc.conc_name}
+
+ ))}
+
+ )}
+
+
+ );
+}
+
function MetadataContent(props: {
user: User,
setUser: Function,
- degreeMetadata: DegreeMetadata,
programIndex: number,
+ degreeMetadatas: DegreeMetadata[],
+ degreeIndex: number,
+ setDegreeIndex: Function
+ concIndex: number,
+ setConcIndex: Function
}){
return (
-
-
-
-
- ABOUT
-
-
- {props.degreeMetadata.about}
-
-
- DUS
-
-
- {props.degreeMetadata.dus.name}; {props.degreeMetadata.dus.address}
-
-
-
-
MAJOR CATALOG
-
MAJOR WEBSITE
-
-
+
+
+
);
}
-function MetadataScrollButton(props: {
- shiftProgramIndex: Function;
- peekProgram: Function;
- dir: number;
-}) {
+function MetadataScrollButton(props: { shiftProgramIndex: Function; peekProgram: Function; dir: number })
+{
return (
-
props.shiftProgramIndex(props.dir)}
- >
+
props.shiftProgramIndex(props.dir)}>
@@ -144,17 +181,18 @@ function MetadataScrollButton(props: {
function Metadata(props: {
- user: User,
- setUser: Function,
- programMetadatas: DegreeMetadata[],
- programIndex: number,
- shiftProgramIndex: Function,
+ program: Program,
+ index: { conc: number, deg: number, prog: number }
peekProgram: Function
}) {
return (
-
+
);
diff --git a/frontend/src/app/majors/overhead/major-search/MajorSearch.tsx b/frontend/src/app/majors/overhead/major-search/MajorSearch.tsx
index ff42cc7..24b6803 100644
--- a/frontend/src/app/majors/overhead/major-search/MajorSearch.tsx
+++ b/frontend/src/app/majors/overhead/major-search/MajorSearch.tsx
@@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from "react";
import Style from "./MajorSearch.module.css";
import { User } from "@/types/type-user";
-import { ALL_PROGRAM_METADATAS } from "@/database/data-degree";
+import { ALL_PROGRAM_METADATAS } from "@/database/programs/metas/meta-econ";
function MajorSearchBar(props: { user: User; setProgramIndex: Function }) {
const [searchTerm, setSearchTerm] = useState("");
diff --git a/frontend/src/app/majors/overhead/pinned/Pinned.tsx b/frontend/src/app/majors/overhead/pinned/Pinned.tsx
index d5f7d1b..5ee46c5 100644
--- a/frontend/src/app/majors/overhead/pinned/Pinned.tsx
+++ b/frontend/src/app/majors/overhead/pinned/Pinned.tsx
@@ -3,7 +3,7 @@ import Style from "./Pinned.module.css";
import { User } from "@/types/type-user";
import { StudentDegree } from "@/types/type-program";
-import { ALL_PROGRAM_METADATAS } from "@/database/data-degree";
+import { ALL_PROGRAM_METADATAS } from "@/database/programs/metas/meta-econ";
function DegreeIcon(props: { studentDegree: StudentDegree, setProgramIndex: Function }) {
const mark = (status: string) => {
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 38552a1..ff77375 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -3,9 +3,6 @@
import { useState } from "react";
import { useAuth } from "../providers";
-import { DegreeMetadata } from "@/types/type-program";
-import { ALL_PROGRAM_METADATAS } from "@/database/data-degree";
-
import Style from "./Majors.module.css";
import NavBar from "@/components/navbar/NavBar";
import Overhead from "./overhead/Overhead";
@@ -15,37 +12,31 @@ import Requirements from "./requirements/Requirements";
function Majors()
{
const { user, setUser } = useAuth();
+ const { programs } = user.FYP.programs;
- const [programIndex, setProgramIndex] = useState(0);
-
- const allProgramMetadatas: DegreeMetadata[][] = ALL_PROGRAM_METADATAS;
-
- const shiftProgramIndex: Function = (dir: number) => {
- setProgramIndex((programIndex + dir + allProgramMetadatas.length) % allProgramMetadatas.length);
- };
+ const [index, setIndex] = useState({ conc: 0, deg: 0, prog: 0});
+ const updateIndex: Function = (index: { conc: number, deg: number, prog: number}) => {
+ setIndex(index)
+ };
- const peekProgram = (dir: number) => {
- return allProgramMetadatas[(programIndex + dir + allProgramMetadatas.length) % allProgramMetadatas.length][0];
+ const peekProgram = (dir: number) => {
+ return programs[(index.prog + dir + programs.length) % programs.length];
};
return(
-
}/>
+ {/* utility={} */}
+
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index da62ea5..82fce59 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -5,11 +5,11 @@ import Style from "./Requirements.module.css";
import { useAuth } from "@/app/providers";
import { User, Course } from "@/types/type-user";
-import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
import { CourseIcon } from "@/components/course-icon/CourseIcon";
-function RenderSubrequirementCourse(props: { course: Course | null, subreq: DegreeSubrequirement; user: User }){
+function RenderSubrequirementCourse(props: { course: Course | null, subreq: ConcentrationSubrequirement; user: User }){
// TODO
@@ -30,7 +30,7 @@ function RenderSubrequirementCourse(props: { course: Course | null, subreq: Degr
)
}
-function RenderSubrequirement(props: { subreq: DegreeSubrequirement; user: User }) {
+function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement; user: User }) {
const [showAll, setShowAll] = useState(false);
// Separate null and non-null courses
@@ -74,61 +74,67 @@ function RenderSubrequirement(props: { subreq: DegreeSubrequirement; user: User
);
}
-function RenderRequirement(props: { programIndex: number, req: DegreeRequirement; user: User }){
+function RenderRequirement(props: { req: ConcentrationRequirement }){
- const { user, setUser } = useAuth();
- const { req, programIndex } = props;
- const { subreqs_list, subreqs_required_count } = req;
+ // const { user, setUser } = useAuth();
+ // const { req, programIndex, degreeIndex } = props;
+ const { subreqs_list, subreqs_required_count } = props.req;
- // Get the correct degree configuration (assumes only one degree per program)
- const degreeConfig = user.FYP.degreeConfigurations[programIndex][0];
+ // // Get the correct degree configuration (assumes only one degree per program)
+ // const degreeConfig = user.FYP.degreeConfigurations[programIndex][0];
// Find the corresponding requirement in `degreeConfig`
- const requirement = degreeConfig.reqs_list.find((r: DegreeRequirement) => r.req_name === req.req_name);
+ // const requirement = degreeConfig[0].reqs_list.find((r: DegreeRequirement) => r.req_name === req.req_name);
- if (!requirement) return null; // Fail-safe, shouldn't happen
+ // if (!requirement) return null; // Fail-safe, shouldn't happen
// Move clicked subreq to the front if it's beyond the first `subreqs_required_count`
- const handleSubreqClick = (subreq: DegreeSubrequirement) => {
- if (!subreqs_required_count) return; // Ignore clicks if not applicable
+ // const handleSubreqClick = (subreq: DegreeSubrequirement) => {
+ // if (!subreqs_required_count) return; // Ignore clicks if not applicable
- setUser((prevUser: User) => {
- const newUser = { ...prevUser };
+ // setUser((prevUser: User) => {
+ // const newUser = { ...prevUser };
- // Get the degree and requirement again inside state update
- const updatedDegree = newUser.FYP.degreeConfigurations[programIndex][0];
- const updatedRequirement = updatedDegree.reqs_list.find((r) => r.req_name === req.req_name);
+ // // Get the degree and requirement again inside state update
+ // const updatedDegree = newUser.FYP.degreeConfigurations[programIndex][degreeIndex];
+ // const updatedRequirement = updatedDegree[0].reqs_list.find((r) => r.req_name === req.req_name); // FIXXX
- if (!updatedRequirement) return prevUser; // Failsafe
+ // if (!updatedRequirement) return prevUser; // Failsafe
- const updatedSubreqs = [...updatedRequirement.subreqs_list];
- const index = updatedSubreqs.findIndex((s) => s.subreq_name === subreq.subreq_name);
+ // const updatedSubreqs = [...updatedRequirement.subreqs_list];
+ // const index = updatedSubreqs.findIndex((s) => s.subreq_name === subreq.subreq_name);
- if (index >= subreqs_required_count) {
- // Move it to the front
- updatedSubreqs.splice(index, 1);
- updatedSubreqs.unshift(subreq);
- }
+ // if (index >= subreqs_required_count) {
+ // // Move it to the front
+ // updatedSubreqs.splice(index, 1);
+ // updatedSubreqs.unshift(subreq);
+ // }
- // Update the requirement's subreqs_list in user state
- updatedRequirement.subreqs_list = updatedSubreqs;
+ // // Update the requirement's subreqs_list in user state
+ // updatedRequirement.subreqs_list = updatedSubreqs;
- return newUser;
- });
- };
+ // return newUser;
+ // });
+ // };
return (
-
{props.req.req_name}
+
+ {props.req.req_name}
+
{props.req.checkbox !== undefined ? props.req.courses_satisfied_count === props.req.courses_required_count ? "✅" : "❌" : `${props.req.courses_satisfied_count}|${props.req.courses_required_count}`}
+
+ {props.req.req_desc}
+
+
{/* Subreq Toggle Buttons - Only show if subreqs_required_count exists and < total subreqs */}
- {subreqs_required_count && subreqs_list.length > subreqs_required_count && (
+ {/* {subreqs_required_count && subreqs_list.length > subreqs_required_count && (
{subreqs_list.map((subreq, index) => (
handleSubreqClick(subreq)}>
@@ -136,7 +142,7 @@ function RenderRequirement(props: { programIndex: number, req: DegreeRequirement
))}
- )}
+ )} */}
{/* Display Selected Subreqs - Enforce subreqs_required_count if present */}
@@ -153,25 +159,26 @@ function RenderRequirement(props: { programIndex: number, req: DegreeRequirement
}
-function RequirementsContent(props: { edit: boolean, programIndex: number, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function })
+// function RequirementsContent(props: { edit: boolean, programIndex: number, degreeIndex: number, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function })
+function RequirementsContent(props: { conc: DegreeConcentration })
{
return(
- {props.degreeConfiguration.reqs_list.map((req, index) => (
-
+ {props.conc.conc_reqs.map((req, index) => (
+
))}
);
}
-function Requirements(props: { user: User, setUser: Function, programIndex: number, degreeConfiguration: DegreeConfiguration })
+// function Requirements(props: { user: User, setUser: Function, programIndex: number, degreeIndex: number, degreeConfiguration: DegreeConfiguration })
+function Requirements(props: { conc: DegreeConcentration })
{
-
- const [edit, setEdit] = useState(false);
- const updateEdit = () => {
- setEdit(!edit);
- };
+ // const [edit, setEdit] = useState(false);
+ // const updateEdit = () => {
+ // setEdit(!edit);
+ // };
return(
@@ -180,13 +187,15 @@ function Requirements(props: { user: User, setUser: Function, programIndex: numb
Requirements
);
diff --git a/frontend/src/database/configs/data-econ.ts b/frontend/src/database/configs/data-econ.ts
deleted file mode 100644
index 68adfb1..0000000
--- a/frontend/src/database/configs/data-econ.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-
-import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-
-import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "../data-courses";
-import { SC_ECON_110 } from "../data-studentcourses";
-
-// INTRO
-
-const ECON_MATH: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "MATH",
- subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
- courses_required: 1,
- courses_options: [null, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_INTRO_MICRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTRO MICRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_108, ECON_110, ECON_115],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [SC_ECON_110],
-}
-
-const ECON_INTRO_MACRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTRO MACRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_111, ECON_116],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_INTRO: DegreeRequirement = {
- req_type_id: 1,
- req_name: "INTRO",
- req_desc: "",
-
- courses_required_count: 3,
- courses_satisfied_count: 1,
-
- subreqs_list: [ECON_MATH, ECON_INTRO_MICRO, ECON_INTRO_MACRO]
-}
-
-// CORE
-
-const ECON_CORE_MICRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTERMEDIATE MICRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_121, ECON_125],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_CORE_MACRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTERMEDIATE MACRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_122, ECON_126],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_CORE_METRICS: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "ECONOMETRICS",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_117, ECON_123, ECON_136],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_CORE: DegreeRequirement = {
- req_type_id: 1,
- req_name: "CORE",
- req_desc: "",
-
- courses_required_count: 3,
- courses_satisfied_count: 0,
-
- subreqs_list: [ECON_CORE_MICRO, ECON_CORE_MACRO, ECON_CORE_METRICS]
-}
-
-// ELECTIVE
-
-const ECON_RANGE_ELECS: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "",
- subreq_desc: "Standard elective or DUS approved extra-department substitution.",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const ECON_SUB_ELEC: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "",
- subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
- courses_required: 3,
- courses_options: [null, null, null],
- courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
- courses_any_bool: true,
- student_courses_satisfying: []
-}
-
-const ECON_ELECTIVES: DegreeRequirement = {
- req_type_id: 1,
- req_name: "ELECTIVE",
- req_desc: "",
-
- courses_required_count: 4,
- courses_satisfied_count: 0,
-
- subreqs_list: [ECON_SUB_ELEC, ECON_RANGE_ELECS]
-}
-
-// SENIOR
-
-const ECON_SEN_SUB: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "SENIOR REQUIREMENT",
- subreq_desc: "",
- courses_required: 2,
- courses_options: [null, null],
- courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const ECON_SENIOR: DegreeRequirement = {
- req_type_id: 1,
- req_name: "SENIOR",
- req_desc: "",
-
- courses_required_count: 2,
- courses_satisfied_count: 0,
-
- subreqs_list: [ECON_SEN_SUB]
-}
-
-// FINAL
-
-export const ECON_CONFIG: DegreeConfiguration = {
- reqs_list: [ECON_INTRO, ECON_CORE, ECON_ELECTIVES, ECON_SENIOR]
-}
diff --git a/frontend/src/database/configs/data-hist.ts b/frontend/src/database/configs/data-hist.ts
deleted file mode 100644
index f551242..0000000
--- a/frontend/src/database/configs/data-hist.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-
-import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-
-// PRE
-
-const HIST_PRE: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "PRE 1800",
- subreq_desc: "",
- courses_required: 2,
- courses_options: [null, null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_PREINDUSTRIAL: DegreeRequirement = {
- req_type_id: 1,
- req_name: "PREINDUSTRIAL",
- req_desc: "",
-
- courses_required_count: 2,
- courses_satisfied_count: 0,
-
- checkbox: true,
- subreqs_list: [HIST_PRE]
-}
-
-// GLOBAL
-
-const HIST_CORE_GLOB_AFRICA: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "AFRICA",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_CORE_GLOB_ASIA: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "ASIA",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_CORE_GLOB_EUROPE: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "EUROPE",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_CORE_GLOB_LA: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "LATIN AMERICA",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_CORE_GLOB_ME: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "MIDDLE EAST",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_CORE_GLOB_US: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "U.S.",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const HIST_GLOB_CORE: DegreeRequirement = {
- req_type_id: 1,
- req_name: "GLOBAL",
- req_desc: "",
-
- courses_required_count: 5,
- courses_satisfied_count: 0,
-
- subreqs_required_count: 5,
- subreqs_satisfied_count: 0,
-
- subreqs_list: [HIST_CORE_GLOB_AFRICA, HIST_CORE_GLOB_ASIA, HIST_CORE_GLOB_EUROPE, HIST_CORE_GLOB_LA, HIST_CORE_GLOB_ME, HIST_CORE_GLOB_US]
-}
-
-// SEMINAR
-
-const HIST_DEPT_SEMINAR: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "DEPARTMENTAL",
- subreq_desc: "",
- courses_required: 2,
- courses_options: [null, null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const HIST_SEMINAR: DegreeRequirement = {
- req_type_id: 1,
- req_name: "SEMINAR",
- req_desc: "",
-
- courses_required_count: 2,
- courses_satisfied_count: 0,
-
- checkbox: true,
- subreqs_list: [HIST_DEPT_SEMINAR]
-}
-
-// ELECTIVE
-
-const HIST_ELEC_INDIV: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "",
- subreq_desc: "",
- courses_required: 5,
- courses_options: [null, null, null, null, null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const HIST_ELECTIVE: DegreeRequirement = {
- req_type_id: 1,
- req_name: "ELECTIVE",
- req_desc: "",
-
- courses_required_count: 5,
- courses_satisfied_count: 0,
-
- subreqs_list: [HIST_ELEC_INDIV]
-}
-
-// SENIOR
-
-const ECON_SEN_ONE: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "ONE TERM",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const ECON_SEN_TWO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "TWO TERM",
- subreq_desc: "",
- courses_required: 2,
- courses_options: [null, null],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const ECON_SENIOR: DegreeRequirement = {
- req_type_id: 1,
- req_name: "SENIOR",
- req_desc: "",
-
- courses_required_count: 0,
- courses_satisfied_count: 0,
-
- subreqs_required_count: 1,
- subreqs_satisfied_count: 0,
-
- subreqs_list: [ECON_SEN_ONE, ECON_SEN_TWO]
-}
-
-// FINAL
-
-export const HIST_CONFIG: DegreeConfiguration = {
- reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_GLOB_CORE, HIST_ELECTIVE, ECON_SENIOR]
-}
diff --git a/frontend/src/database/configs/data-plsc.ts b/frontend/src/database/configs/data-plsc.ts
deleted file mode 100644
index 55b7cc8..0000000
--- a/frontend/src/database/configs/data-plsc.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-
-import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-
-import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "../data-courses";
-import { SC_ECON_110 } from "../data-studentcourses";
-
-// INTRO
-
-const ECON_MATH: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "MATH",
- subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
- courses_required: 1,
- courses_options: [null, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_INTRO_MICRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTRO MICRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_108, ECON_110, ECON_115],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [SC_ECON_110],
-}
-
-const ECON_INTRO_MACRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTRO MACRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_111, ECON_116],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_INTRO: DegreeRequirement = {
- req_type_id: 1,
- req_name: "INTRO",
- req_desc: "",
-
- courses_required_count: 3,
- courses_satisfied_count: 1,
-
- subreqs_list: [ECON_MATH, ECON_INTRO_MICRO, ECON_INTRO_MACRO]
-}
-
-// CORE
-
-const ECON_CORE_MICRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTERMEDIATE MICRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_121, ECON_125],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_CORE_MACRO: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "INTERMEDIATE MACRO",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_122, ECON_126],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_CORE_METRICS: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "ECONOMETRICS",
- subreq_desc: "",
- courses_required: 1,
- courses_options: [ECON_117, ECON_123, ECON_136],
- courses_elective_range: null,
- courses_any_bool: false,
- student_courses_satisfying: [],
-}
-
-const ECON_CORE: DegreeRequirement = {
- req_type_id: 1,
- req_name: "CORE",
- req_desc: "",
-
- courses_required_count: 3,
- courses_satisfied_count: 0,
-
- subreqs_list: [ECON_CORE_MICRO, ECON_CORE_MACRO, ECON_CORE_METRICS]
-}
-
-// ELECTIVE
-
-const ECON_RANGE_ELECS: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "",
- subreq_desc: "Standard elective or DUS approved extra-department substitution.",
- courses_required: 1,
- courses_options: [null],
- courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const ECON_SUB_ELEC: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "",
- subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
- courses_required: 3,
- courses_options: [null, null, null],
- courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
- courses_any_bool: true,
- student_courses_satisfying: []
-}
-
-const ECON_ELECTIVES: DegreeRequirement = {
- req_type_id: 1,
- req_name: "ELECTIVE",
- req_desc: "",
-
- courses_required_count: 4,
- courses_satisfied_count: 0,
-
- subreqs_list: [ECON_SUB_ELEC, ECON_RANGE_ELECS]
-}
-
-// SENIOR
-
-const ECON_SEN_SUB: DegreeSubrequirement = {
- subreq_type_id: 1,
- subreq_name: "SENIOR REQUIREMENT",
- subreq_desc: "",
- courses_required: 2,
- courses_options: [null, null],
- courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
- courses_any_bool: false,
- student_courses_satisfying: []
-}
-
-const ECON_SENIOR: DegreeRequirement = {
- req_type_id: 1,
- req_name: "SENIOR",
- req_desc: "",
-
- courses_required_count: 2,
- courses_satisfied_count: 0,
-
- subreqs_list: [ECON_SEN_SUB]
-}
-
-// FINAL
-
-export const PLSC_CONFIG: DegreeConfiguration = {
- reqs_list: [ECON_INTRO, ECON_CORE, ECON_ELECTIVES, ECON_SENIOR]
-}
diff --git a/frontend/src/database/data-degree.ts b/frontend/src/database/data-degree.ts
deleted file mode 100644
index ca1b720..0000000
--- a/frontend/src/database/data-degree.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-
-import { DegreeMetadata } from "@/types/type-program";
-
-export const ALL_PROGRAM_METADATAS: DegreeMetadata[][] = [
- [{
- name: "History",
- abbr: "HIST",
- degreeType: "BACH_ART",
- dus: { address: "HQ 211, (203) 432-1366", email: "history@yale.edu", name: "Alan Mikhail" },
- about: "The History major offers a broad exploration of human experience across time, cultures, and societies. Students gain expertise in archival research, critical analysis, and historical interpretation. The major prepares students to engage with contemporary issues by understanding their historical contexts, whether in politics, economics, or cultural transformations. History students learn to construct arguments based on evidence and develop a strong capacity for analytical reasoning and effective communication.",
- stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
- students: 0,
- wesbiteLink: "https://history.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/history/",
- }],
- [{
- name: "Computer Science",
- abbr: "CPSC",
- degreeType: "BACH_ART",
- dus: { address: "AKW 208, (203) 432-6400", email: "cpsc@yale.edu", name: "Y. Richard Yang" },
- about: "The Department of Computer Science offers a B.A. degree program, as well as four combined major programs in cooperation with other departments: Electrical Engineering and Computer Science, Computer Science and Economics, Computer Science and Mathematics, and Computer Science and Psychology. Each program not only provides a solid technical education but also allows students either to take a broad range of courses in other disciplines or to complete the requirements of a second major.",
- stats: { courses: 0, rating: 0, type: "QR", workload: 0 },
- students: 0,
- wesbiteLink: "http://cpsc.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/computer-science/",
- }],
- [{
- name: "Political Science",
- abbr: "PLSC",
- degreeType: "BACH_ART",
- dus: { address: "Rosenkranz Hall 130, (203) 432-5248", email: "politicalscience@yale.edu", name: "Isabela Mares" },
- about: "The Political Science major examines governments, political behavior, and institutional structures at local, national, and global levels. Students engage with the theoretical foundations of politics, quantitative and qualitative methodologies, and policy analysis. The program prepares students for careers in law, public policy, international relations, and academia while offering flexibility to explore subfields such as comparative politics, American politics, and political philosophy.",
- stats: { courses: 0, rating: 0, type: "So", workload: 0 },
- students: 0,
- wesbiteLink: "https://politicalscience.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/political-science/",
- }],
- [{
- name: "Economics",
- abbr: "ECON",
- degreeType: "BACH_ART",
- dus: { address: "28 Hillhouse Ave, (203) 432-3576", email: "economics@yale.edu", name: "Dirk Bergemann" },
- about: "The Economics major provides a rigorous framework for understanding financial markets, public policy, and decision-making. Students learn analytical techniques in microeconomics, macroeconomics, and econometrics, developing critical skills in data interpretation and policy evaluation. The major offers pathways in finance, economic development, and quantitative analysis, preparing students for careers in government, consulting, business, and research.",
- stats: { courses: 0, rating: 0, type: "QR", workload: 0 },
- students: 0,
- wesbiteLink: "https://economics.yale.edu",
- catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/economics/",
- }]
-];
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index e60e861..e2d5c5e 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,10 +1,6 @@
import { User } from "./../types/type-user";
-
-import { CPSC_CONFIG } from "./configs/data-cpsc";
-import { ECON_CONFIG } from "./configs/data-econ";
-import { HIST_CONFIG } from "./configs/data-hist";
-import { PLSC_CONFIG } from "./configs/data-plsc";
+import { PROG_CPSC } from "./programs/data-program";
export const Ryan: User = {
name: "Ryan",
@@ -19,38 +15,33 @@ export const Ryan: User = {
senior: [0, 202703, 202801],
},
languagePlacement: { language: "Spanish", level: 5 },
- degreeDeclarations: [],
- degreeConfigurations: [
- [HIST_CONFIG],
- [CPSC_CONFIG],
- [PLSC_CONFIG],
- [ECON_CONFIG]
- ],
+ programs: [PROG_CPSC],
+ declarations: [],
}
}
-export const NullUser: User = {
- name: "",
- netID: "",
- onboard: false,
- FYP: {
- studentCourses: [],
- studentTermArrangement: {
- first_year: [],
- sophomore: [],
- junior: [],
- senior: [],
- },
- languagePlacement: { language: "", level: 0 },
- degreeDeclarations: [],
- degreeConfigurations: [
- [],
- [],
- [],
- []
- ],
- }
-}
+// export const NullUser: User = {
+// name: "",
+// netID: "",
+// onboard: false,
+// FYP: {
+// studentCourses: [],
+// studentTermArrangement: {
+// first_year: [],
+// sophomore: [],
+// junior: [],
+// senior: [],
+// },
+// languagePlacement: { language: "", level: 0 },
+// degreeDeclarations: [],
+// degreeConfigurations: [
+// [],
+// [],
+// [],
+// []
+// ],
+// }
+// }
diff --git a/frontend/src/database/configs/data-cpsc.ts b/frontend/src/database/programs/concs-cpsc.ts
similarity index 53%
rename from frontend/src/database/configs/data-cpsc.ts
rename to frontend/src/database/programs/concs-cpsc.ts
index afdbc40..601e08c 100644
--- a/frontend/src/database/configs/data-cpsc.ts
+++ b/frontend/src/database/programs/concs-cpsc.ts
@@ -1,11 +1,12 @@
-import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./../data-courses";
-import { SC_CPSC_201, SC_CPSC_202, SC_CPSC_223, SC_CPSC_323 } from "./../data-studentcourses";
+import { SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "./../data-studentcourses";
-const CPSC_INTRO: DegreeSubrequirement = {
- subreq_type_id: 1,
+// CORE
+
+const CORE_SUB_INTRO: ConcentrationSubrequirement = {
subreq_name: "INTRO",
subreq_desc: "",
courses_required: 1,
@@ -15,8 +16,7 @@ const CPSC_INTRO: DegreeSubrequirement = {
student_courses_satisfying: [SC_CPSC_201],
}
-const CPSC_MATH: DegreeSubrequirement = {
- subreq_type_id: 1,
+const CORE_SUB_MATH: ConcentrationSubrequirement = {
subreq_name: "DISCRETE MATH",
subreq_desc: "",
courses_required: 1,
@@ -26,8 +26,7 @@ const CPSC_MATH: DegreeSubrequirement = {
student_courses_satisfying: [],
}
-const CPSC_DATA: DegreeSubrequirement = {
- subreq_type_id: 1,
+const CORE_SUB_DATA: ConcentrationSubrequirement = {
subreq_name: "DATA STRUCTURES",
subreq_desc: "",
courses_required: 1,
@@ -37,8 +36,7 @@ const CPSC_DATA: DegreeSubrequirement = {
student_courses_satisfying: [SC_CPSC_223],
}
-const CPSC_SYSTEMS: DegreeSubrequirement = {
- subreq_type_id: 1,
+const CORE_SUB_SYSTEMS: ConcentrationSubrequirement = {
subreq_name: "SYSTEMS",
subreq_desc: "",
courses_required: 1,
@@ -48,8 +46,7 @@ const CPSC_SYSTEMS: DegreeSubrequirement = {
student_courses_satisfying: [SC_CPSC_323],
}
-const CPSC_ALGOS: DegreeSubrequirement = {
- subreq_type_id: 1,
+const CORE_SUB_ALGOS: ConcentrationSubrequirement = {
subreq_name: "ALGORITHMS",
subreq_desc: "",
courses_required: 1,
@@ -59,52 +56,65 @@ const CPSC_ALGOS: DegreeSubrequirement = {
student_courses_satisfying: [],
}
-const CPSC_CORE: DegreeRequirement = {
- req_type_id: 1,
+const CPSC_CORE: ConcentrationRequirement = {
req_name: "CORE",
req_desc: "",
-
courses_required_count: 5,
courses_satisfied_count: 3,
-
- subreqs_list: [CPSC_INTRO, CPSC_MATH, CPSC_DATA, CPSC_SYSTEMS, CPSC_ALGOS]
+ subreqs_list: [CORE_SUB_INTRO, CORE_SUB_MATH, CORE_SUB_DATA, CORE_SUB_SYSTEMS, CORE_SUB_ALGOS]
}
-const CPSC_RANGE_ELECS: DegreeSubrequirement = {
- subreq_type_id: 1,
+// ELECTIVE
+
+const ELEC_MULT_BA: ConcentrationSubrequirement = {
subreq_name: "",
- subreq_desc: "Standard elective or DUS approved extra-department substitution.",
- courses_required: 1,
- courses_options: [null],
+ subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
+ courses_required: 4,
+ courses_options: [null, null, null, null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: false,
student_courses_satisfying: []
}
-const CPSC_SUB_ELEC: DegreeSubrequirement = {
- subreq_type_id: 1,
+const ELEC_MULT_BS: ConcentrationSubrequirement = {
subreq_name: "",
subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
- courses_required: 3,
- courses_options: [null, null, null],
+ courses_required: 6,
+ courses_options: [null, null, null, null, null, null],
+ courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ELEC_SUB: ConcentrationSubrequirement = {
+ subreq_name: "",
+ subreq_desc: "Standard elective or DUS approved extra-department substitution.",
+ courses_required: 1,
+ courses_options: [null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: true,
student_courses_satisfying: []
}
-const CPSC_ELECTIVES: DegreeRequirement = {
- req_type_id: 1,
+const CPSC_BA_ELEC: ConcentrationRequirement = {
req_name: "ELECTIVE",
req_desc: "",
-
courses_required_count: 4,
courses_satisfied_count: 0,
+ subreqs_list: [ELEC_SUB, ELEC_MULT_BA]
+}
- subreqs_list: [CPSC_SUB_ELEC, CPSC_RANGE_ELECS]
+const CPSC_BS_ELEC: ConcentrationRequirement = {
+ req_name: "ELECTIVE",
+ req_desc: "",
+ courses_required_count: 6,
+ courses_satisfied_count: 0,
+ subreqs_list: [ELEC_SUB, ELEC_MULT_BS]
}
-const CPSC_SENPROJ: DegreeSubrequirement = {
- subreq_type_id: 1,
+// SENIOR
+
+const SEN_PROJ: ConcentrationSubrequirement = {
subreq_name: "SENIOR PROJECT",
subreq_desc: "",
courses_required: 1,
@@ -114,17 +124,24 @@ const CPSC_SENPROJ: DegreeSubrequirement = {
student_courses_satisfying: []
}
-const CPSC_SENIOR: DegreeRequirement = {
- req_type_id: 1,
+const CPSC_SENIOR: ConcentrationRequirement = {
req_name: "SENIOR",
req_desc: "",
-
courses_required_count: 1,
courses_satisfied_count: 0,
+ subreqs_list: [SEN_PROJ]
+}
+
+// EXPORT
- subreqs_list: [CPSC_SENPROJ]
+export const CONC_CPSC_BA_I: DegreeConcentration = {
+ conc_name: "",
+ conc_desc: "",
+ conc_reqs: [CPSC_CORE, CPSC_BA_ELEC, CPSC_SENIOR]
}
-export const CPSC_CONFIG: DegreeConfiguration = {
- reqs_list: [CPSC_CORE, CPSC_ELECTIVES, CPSC_SENIOR]
+export const CONC_CPSC_BS_I: DegreeConcentration = {
+ conc_name: "",
+ conc_desc: "",
+ conc_reqs: [CPSC_CORE, CPSC_BS_ELEC, CPSC_SENIOR]
}
\ No newline at end of file
diff --git a/frontend/src/database/programs/configs/config-econ.ts b/frontend/src/database/programs/configs/config-econ.ts
new file mode 100644
index 0000000..30b1553
--- /dev/null
+++ b/frontend/src/database/programs/configs/config-econ.ts
@@ -0,0 +1,162 @@
+
+// import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+
+// import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "../data-courses";
+// import { SC_ECON_110 } from "../data-studentcourses";
+
+// // INTRO
+
+// const ECON_MATH: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "MATH",
+// subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
+// courses_required: 1,
+// courses_options: [null, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const ECON_INTRO_MICRO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "INTRO MICRO",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [ECON_108, ECON_110, ECON_115],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [SC_ECON_110],
+// }
+
+// const ECON_INTRO_MACRO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "INTRO MACRO",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [ECON_111, ECON_116],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const ECON_INTRO: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "INTRO",
+// req_desc: "",
+
+// courses_required_count: 3,
+// courses_satisfied_count: 1,
+
+// subreqs_list: [ECON_MATH, ECON_INTRO_MICRO, ECON_INTRO_MACRO]
+// }
+
+// // CORE
+
+// const ECON_CORE_MICRO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "INTERMEDIATE MICRO",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [ECON_121, ECON_125],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const ECON_CORE_MACRO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "INTERMEDIATE MACRO",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [ECON_122, ECON_126],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const ECON_CORE_METRICS: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "ECONOMETRICS",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [ECON_117, ECON_123, ECON_136],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const ECON_CORE: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "CORE",
+// req_desc: "",
+
+// courses_required_count: 3,
+// courses_satisfied_count: 0,
+
+// subreqs_list: [ECON_CORE_MICRO, ECON_CORE_MACRO, ECON_CORE_METRICS]
+// }
+
+// // ELECTIVE
+
+// const ECON_RANGE_ELECS: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "",
+// subreq_desc: "Standard elective or DUS approved extra-department substitution.",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const ECON_SUB_ELEC: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "",
+// subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
+// courses_required: 3,
+// courses_options: [null, null, null],
+// courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
+// courses_any_bool: true,
+// student_courses_satisfying: []
+// }
+
+// const ECON_ELECTIVES: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "ELECTIVE",
+// req_desc: "",
+
+// courses_required_count: 4,
+// courses_satisfied_count: 0,
+
+// subreqs_list: [ECON_SUB_ELEC, ECON_RANGE_ELECS]
+// }
+
+// // SENIOR
+
+// const ECON_SEN_SUB: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "SENIOR REQUIREMENT",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const ECON_SENIOR: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SENIOR",
+// req_desc: "",
+
+// courses_required_count: 2,
+// courses_satisfied_count: 0,
+
+// subreqs_list: [ECON_SEN_SUB]
+// }
+
+// // FINAL
+
+// export const ECON_CONFIG: DegreeConfiguration = {
+// reqs_list: [ECON_INTRO, ECON_CORE, ECON_ELECTIVES, ECON_SENIOR]
+// }
diff --git a/frontend/src/database/programs/configs/config-hist.ts b/frontend/src/database/programs/configs/config-hist.ts
new file mode 100644
index 0000000..5786583
--- /dev/null
+++ b/frontend/src/database/programs/configs/config-hist.ts
@@ -0,0 +1,273 @@
+
+// import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+
+// // PRE
+
+// const HIST_PRE: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "PRE 1800",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_PREINDUSTRIAL: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "PREINDUSTRIAL",
+// req_desc: "",
+
+// courses_required_count: 2,
+// courses_satisfied_count: 0,
+
+// checkbox: true,
+// subreqs_list: [HIST_PRE]
+// }
+
+// // GLOBAL
+
+// const HIST_CORE_GLOB_AFRICA: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "AFRICA",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_CORE_GLOB_ASIA: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "ASIA",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_CORE_GLOB_EUROPE: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "EUROPE",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_CORE_GLOB_LA: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "LATIN AMERICA",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_CORE_GLOB_ME: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "MIDDLE EAST",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_CORE_GLOB_US: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "U.S.",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_GLOB_CORE: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "GLOBAL",
+// req_desc: "",
+
+// courses_required_count: 5,
+// courses_satisfied_count: 0,
+
+// subreqs_required_count: 5,
+// subreqs_satisfied_count: 0,
+
+// subreqs_list: [HIST_CORE_GLOB_AFRICA, HIST_CORE_GLOB_ASIA, HIST_CORE_GLOB_EUROPE, HIST_CORE_GLOB_LA, HIST_CORE_GLOB_ME, HIST_CORE_GLOB_US]
+// }
+
+// // SEMINAR
+
+// const HIST_DEPT_SEMINAR: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "DEPARTMENTAL",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const HIST_SEMINAR: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SEMINAR",
+// req_desc: "",
+
+// courses_required_count: 2,
+// courses_satisfied_count: 0,
+
+// checkbox: true,
+// subreqs_list: [HIST_DEPT_SEMINAR]
+// }
+
+// // ELECTIVE
+
+// const HIST_ELEC_SPEC_INDIV: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "",
+// subreq_desc: "",
+// courses_required: 3,
+// courses_options: [null, null, null, null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const HIST_ELEC_GLOB_INDIV: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "",
+// subreq_desc: "",
+// courses_required: 5,
+// courses_options: [null, null, null, null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const HIST_ELECTIVE_SPEC: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "ELECTIVE",
+// req_desc: "",
+
+// courses_required_count: 3,
+// courses_satisfied_count: 0,
+
+// subreqs_list: [HIST_ELEC_SPEC_INDIV]
+// }
+
+// const HIST_ELECTIVE_GLOB: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "ELECTIVE",
+// req_desc: "",
+
+// courses_required_count: 5,
+// courses_satisfied_count: 0,
+
+// subreqs_list: [HIST_ELEC_GLOB_INDIV]
+// }
+
+// // SENIOR
+
+// const ECON_SEN_ONE: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "ONE TERM",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const ECON_SEN_TWO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "TWO TERM",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const ECON_SENIOR: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SENIOR",
+// req_desc: "",
+
+// courses_required_count: 0,
+// courses_satisfied_count: 0,
+
+// subreqs_required_count: 1,
+// subreqs_satisfied_count: 0,
+
+// subreqs_list: [ECON_SEN_ONE, ECON_SEN_TWO]
+// }
+
+// // FINAL
+
+// const HIST_SPEC_CORE_IN: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "REGION OR PATHWAY",
+// subreq_desc: "",
+// courses_required: 5,
+// courses_options: [null, null, null, null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_SPEC_CORE_OUT: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "OUTSIDE",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const HIST_SPEC_CORE: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SPECIALIST",
+// req_desc: "",
+
+// courses_required_count: 7,
+// courses_satisfied_count: 0,
+
+// subreqs_required_count: 2,
+// subreqs_satisfied_count: 0,
+
+// subreqs_list: [HIST_SPEC_CORE_IN, HIST_SPEC_CORE_OUT]
+// }
+
+// // LAST
+
+// export const HIST_CONFIG_BA_SPEC: DegreeConfiguration = {
+// config_name: "SPECIALIST",
+// reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_SPEC_CORE, HIST_ELECTIVE_SPEC, ECON_SENIOR]
+// }
+
+// export const HIST_CONFIG_BA_GLOB: DegreeConfiguration = {
+// config_name: "GLOBALIST",
+// reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_GLOB_CORE, HIST_ELECTIVE_GLOB, ECON_SENIOR]
+// }
+
+// export const HIST_CONFIG_BA: DegreeConfiguration = {
+// config_name: "GLOBALIST",
+// reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_GLOB_CORE, HIST_ELECTIVE_GLOB, ECON_SENIOR]
+// }
\ No newline at end of file
diff --git a/frontend/src/database/programs/configs/config-plsc.ts b/frontend/src/database/programs/configs/config-plsc.ts
new file mode 100644
index 0000000..1649d77
--- /dev/null
+++ b/frontend/src/database/programs/configs/config-plsc.ts
@@ -0,0 +1,201 @@
+
+// import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
+
+// // INTRO
+
+// const PLSC_INTRO_TWO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "INTRO COURSES",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const PLSC_INTRO: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "INTRO",
+// req_desc: "",
+
+// courses_required_count: 3,
+// courses_satisfied_count: 1,
+
+// subreqs_list: [PLSC_INTRO_TWO]
+// }
+
+// // CORE
+
+// const PLSC_CORE_LECTURES: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "CORE LECTURES",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const PLSC_CORE_METHODS: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "METHODS AND FORMAL THEORY",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: [],
+// }
+
+// const PLSC_CORE: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "CORE",
+// req_desc: "",
+
+// courses_required_count: 3,
+// courses_satisfied_count: 0,
+
+// subreqs_list: [PLSC_CORE_LECTURES, PLSC_CORE_METHODS]
+// }
+
+// // ELECTIVE
+
+// const PLSC_SUB_INTL: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "INTERNATIONAL RELATIONS",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SUB_US: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "AMERICAN GOVERNMENT",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SUB_PHIL: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "POLITICAL PHILOSOPHY",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SUB_COMP: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "COMPARATIVE POLITICS",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SUBFIELDS: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SUBFIELDS",
+// req_desc: "",
+
+// courses_required_count: 4,
+// courses_satisfied_count: 0,
+
+// subreqs_required_count: 2,
+// subreqs_satisfied_count: 0,
+
+// subreqs_list: [PLSC_SUB_INTL, PLSC_SUB_US, PLSC_SUB_PHIL, PLSC_SUB_COMP]
+// }
+
+// // SEMINAR
+
+// const PLSC_SEM_ANY: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "YEAR ANY",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SEM_SEN: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "YEAR SENIOR",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SEMINAR: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SEMINAR",
+// req_desc: "Seminar courses taught by PLSC faculty satisfy.",
+
+// courses_required_count: 2,
+// courses_satisfied_count: 0,
+
+// checkbox: true,
+// subreqs_list: [PLSC_SEM_ANY, PLSC_SEM_SEN]
+// }
+
+// // SENIOR
+
+// const PLSC_SEN_ONE: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "ONE TERM",
+// subreq_desc: "",
+// courses_required: 1,
+// courses_options: [null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SEN_TWO: DegreeSubrequirement = {
+// subreq_type_id: 1,
+// subreq_name: "TWO TERM",
+// subreq_desc: "",
+// courses_required: 2,
+// courses_options: [null, null],
+// courses_elective_range: null,
+// courses_any_bool: false,
+// student_courses_satisfying: []
+// }
+
+// const PLSC_SENIOR: DegreeRequirement = {
+// req_type_id: 1,
+// req_name: "SENIOR",
+// req_desc: "",
+
+// courses_required_count: 0,
+// courses_satisfied_count: 0,
+
+// subreqs_required_count: 1,
+// subreqs_satisfied_count: 0,
+
+// subreqs_list: [PLSC_SEN_ONE, PLSC_SEN_TWO]
+// }
+
+// // FINAL
+
+// export const PLSC_CONFIG: DegreeConfiguration = {
+// reqs_list: [PLSC_INTRO, PLSC_CORE, PLSC_SUBFIELDS, PLSC_SEMINAR, PLSC_SENIOR]
+// }
diff --git a/frontend/src/database/programs/data-program.ts b/frontend/src/database/programs/data-program.ts
new file mode 100644
index 0000000..3cf4a92
--- /dev/null
+++ b/frontend/src/database/programs/data-program.ts
@@ -0,0 +1,73 @@
+
+import { Program } from "@/types/type-program";
+import { CONC_CPSC_BA_I, CONC_CPSC_BS_I } from "./concs-cpsc";
+
+export const PROG_CPSC: Program = {
+ prog_data: {
+ prog_name: "Computer Science",
+ prog_abbr: "CPSC",
+ prog_stud_count: 0,
+ prog_dus: { dus_name: "", dus_email: "", dus_address: "" },
+ prog_catolog: "",
+ prog_website: ""
+ },
+ prog_degs: [
+ { deg_type: "B.A.", deg_concs: [CONC_CPSC_BA_I] },
+ { deg_type: "B.S.", deg_concs: [CONC_CPSC_BS_I] }
+ ]
+}
+
+export const PROG_ECON: Program = {
+ prog_data: {
+ prog_name: "Economics",
+ prog_abbr: "ECON",
+ prog_stud_count: 0,
+ prog_dus: { dus_name: "", dus_email: "", dus_address: "" },
+ prog_catolog: "",
+ prog_website: ""
+ },
+ prog_degs: [
+ {
+ deg_type: "B.A.",
+ deg_concs: []
+ },
+ {
+ deg_type: "B.S.",
+ deg_concs: []
+ }
+ ]
+}
+
+export const PROG_PLSC: Program = {
+ prog_data: {
+ prog_name: "Political Science",
+ prog_abbr: "PLSC",
+ prog_stud_count: 0,
+ prog_dus: { dus_name: "", dus_email: "", dus_address: "" },
+ prog_catolog: "",
+ prog_website: ""
+ },
+ prog_degs: [
+ {
+ deg_type: "B.A.",
+ deg_concs: []
+ }
+ ]
+}
+
+export const PROG_HIST: Program = {
+ prog_data: {
+ prog_name: "History",
+ prog_abbr: "HIST",
+ prog_stud_count: 0,
+ prog_dus: { dus_name: "", dus_email: "", dus_address: "" },
+ prog_catolog: "",
+ prog_website: ""
+ },
+ prog_degs: [
+ {
+ deg_type: "B.A.",
+ deg_concs: []
+ }
+ ]
+}
diff --git a/frontend/src/database/programs/metas/meta-econ.ts b/frontend/src/database/programs/metas/meta-econ.ts
new file mode 100644
index 0000000..2518fc1
--- /dev/null
+++ b/frontend/src/database/programs/metas/meta-econ.ts
@@ -0,0 +1,17 @@
+
+// import { ConcMetadata, DegreeMetadata } from "@/types/type-program";
+
+// const CONC_ECON_GEN: ConcMetadata = {
+// conc_name: "",
+// stats: { courses: 0, rating: 0, type: "So", workload: 0 },
+// about: "The Economics major provides a rigorous framework for understanding financial markets, public policy, and decision-making. Students learn analytical techniques in microeconomics, macroeconomics, and econometrics, developing critical skills in data interpretation and policy evaluation. The major offers pathways in finance, economic development, and quantitative analysis, preparing students for careers in government, consulting, business, and research.",
+// }
+
+// export const META_ECON_BA: DegreeMetadata = {
+// name: "Economics",
+// abbr: "ECON",
+// degreeType: "B.A.",
+
+// concs: [CONC_ECON_GEN],
+// info: { students: 0, dus: { address: "28 Hillhouse Ave, (203) 432-3576", email: "economics@yale.edu", name: "Dirk Bergemann" }, wesbiteLink: "https://economics.yale.edu", catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/economics/" }
+// }
diff --git a/frontend/src/database/programs/metas/meta-hist.ts b/frontend/src/database/programs/metas/meta-hist.ts
new file mode 100644
index 0000000..8b492e1
--- /dev/null
+++ b/frontend/src/database/programs/metas/meta-hist.ts
@@ -0,0 +1,23 @@
+
+// import { ConcMetadata, DegreeMetadata } from "@/types/type-program";
+
+// const META_HIST_GLOB: ConcMetadata = {
+// conc_name: "Globalist",
+// stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
+// about: "The History major offers a broad exploration of human experience across time, cultures, and societies. Students gain expertise in archival research, critical analysis, and historical interpretation. The major prepares students to engage with contemporary issues by understanding their historical contexts, whether in politics, economics, or cultural transformations. History students learn to construct arguments based on evidence and develop a strong capacity for analytical reasoning and effective communication.",
+// }
+
+// const META_HIST_SPEC: ConcMetadata = {
+// conc_name: "Specialist",
+// stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
+// about: "The History major offers a broad exploration of human experience across time, cultures, and societies. Students gain expertise in archival research, critical analysis, and historical interpretation. The major prepares students to engage with contemporary issues by understanding their historical contexts, whether in politics, economics, or cultural transformations. History students learn to construct arguments based on evidence and develop a strong capacity for analytical reasoning and effective communication.",
+// }
+
+// export const META_HIST_BA: DegreeMetadata = {
+// name: "History",
+// abbr: "HIST",
+// degreeType: "B.A.",
+
+// concs: [META_HIST_GLOB, META_HIST_SPEC],
+// info: { students: 0, dus: { address: "HQ 211, (203) 432-1366", email: "history@yale.edu", name: "Alan Mikhail" }, wesbiteLink: "https://history.yale.edu", catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/history/" }
+// }
\ No newline at end of file
diff --git a/frontend/src/database/programs/metas/meta-plsc.ts b/frontend/src/database/programs/metas/meta-plsc.ts
new file mode 100644
index 0000000..9ea7064
--- /dev/null
+++ b/frontend/src/database/programs/metas/meta-plsc.ts
@@ -0,0 +1,17 @@
+
+// import { ConcMetadata, DegreeMetadata } from "@/types/type-program";
+
+// const META_PLSC: ConcMetadata = {
+// conc_name: "",
+// stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
+// about: "The Political Science major examines governments, political behavior, and institutional structures at local, national, and global levels. Students engage with the theoretical foundations of politics, quantitative and qualitative methodologies, and policy analysis. The program prepares students for careers in law, public policy, international relations, and academia while offering flexibility to explore subfields such as comparative politics, American politics, and political philosophy.",
+// }
+
+// export const META_PLSC_BA: DegreeMetadata = {
+// name: "Political Science",
+// abbr: "PLSC",
+// degreeType: "B.A.",
+
+// concs: [META_PLSC],
+// info: { students: 0, dus: { address: "Rosenkranz Hall 130, (203) 432-5248", email: "politicalscience@yale.edu", name: "Isabela Mares" }, wesbiteLink: "https://politicalscience.yale.edu", catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/history/" }
+// }
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 59c1bf4..a18486a 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -7,33 +7,6 @@ export interface StudentDegree {
degreeIndex: number;
}
-interface DUS {
- name: string;
- address: string;
- email: string;
-}
-
-interface DegreeMetadataStats {
- courses: number;
- rating: number;
- workload: number;
- type: string;
-}
-
-export interface DegreeMetadata {
- name: string;
- abbr: string;
- degreeType: string;
- stats: DegreeMetadataStats;
- students: number;
- about: string;
- dus: DUS;
- catologLink: string;
- wesbiteLink: string;
-}
-
-// \BEGIN{MAJOR MAGIC}
-
export interface ElectiveRange {
dept: string;
min_code: number;
@@ -42,9 +15,7 @@ export interface ElectiveRange {
export type SubreqElectiveRange = ElectiveRange| null;
-// subreq: 1 | set options
-export interface DegreeSubrequirement {
- subreq_type_id: number;
+export interface ConcentrationSubrequirement {
subreq_name: string;
subreq_desc: string;
@@ -56,8 +27,7 @@ export interface DegreeSubrequirement {
student_courses_satisfying: StudentCourse[];
}
-export interface DegreeRequirement {
- req_type_id: number;
+export interface ConcentrationRequirement {
req_name: string;
req_desc: string;
@@ -68,27 +38,36 @@ export interface DegreeRequirement {
subreqs_satisfied_count?: number;
checkbox?: boolean;
- subreqs_list: DegreeSubrequirement[];
+ subreqs_list: ConcentrationSubrequirement[];
}
-// export interface DegreeRequirementTypeTwo {
-// req_type_id: number;
-// req_name: string;
-// req_desc: string;
-
-// checkbox_bool: boolean;
-// user_courses_satisfying: Course[];
-// }
+export interface DegreeConcentration {
+ conc_name: string;
+ conc_desc: string;
+ conc_reqs: ConcentrationRequirement[];
+}
-// export type DegreeRequirement = DegreeRequirementTypeOne | DegreeRequirementTypeTwo;
+export interface ProgramDegree {
+ deg_type: string;
+ deg_concs: DegreeConcentration[];
+}
-export interface DegreeConfiguration {
- reqs_list: DegreeRequirement[];
+interface ProgDUS {
+ dus_name: string;
+ dus_email: string;
+ dus_address: string;
}
-export interface Degree {
- metadata: DegreeMetadata;
- configuration: DegreeConfiguration;
+interface ProgramMetadata {
+ prog_name: string;
+ prog_abbr: string;
+ prog_stud_count: number;
+ prog_dus: ProgDUS;
+ prog_catolog: string;
+ prog_website: string;
}
-// \END{MAJOR MAGIC}
+export interface Program {
+ prog_data: ProgramMetadata;
+ prog_degs: ProgramDegree[];
+}
diff --git a/frontend/src/types/type-user.ts b/frontend/src/types/type-user.ts
index ce21d91..85f4a23 100644
--- a/frontend/src/types/type-user.ts
+++ b/frontend/src/types/type-user.ts
@@ -1,5 +1,5 @@
-import { DegreeConfiguration, StudentDegree } from "./type-program";
+import { Program, StudentDegree } from "./type-program";
export interface LanguagePlacement {
language: string;
@@ -42,8 +42,8 @@ export interface FYP {
languagePlacement: LanguagePlacement;
studentCourses: StudentCourse[];
studentTermArrangement: StudentTermArrangement;
- degreeConfigurations: DegreeConfiguration[][];
- degreeDeclarations: StudentDegree[];
+ programs: Program[];
+ declarations: StudentDegree[];
}
export interface User {
From 117400f28a9a9ba25af30fe58464206595b0c2db Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Mon, 10 Mar 2025 18:26:55 -0700
Subject: [PATCH 17/38] programs restored
---
frontend/src/app/majors/metadata/Metadata.tsx | 189 ++++++------
frontend/src/app/majors/page.tsx | 19 +-
frontend/src/database/data-courses.ts | 8 +-
frontend/src/database/data-user.ts | 4 +-
.../programs/{ => concs}/concs-cpsc.ts | 12 +-
.../src/database/programs/concs/concs-econ.ts | 143 +++++++++
.../src/database/programs/concs/concs-hist.ts | 233 +++++++++++++++
.../src/database/programs/concs/concs-plsc.ts | 220 ++++++++++++++
.../database/programs/configs/config-econ.ts | 162 -----------
.../database/programs/configs/config-hist.ts | 273 ------------------
.../database/programs/configs/config-plsc.ts | 201 -------------
.../src/database/programs/data-program.ts | 21 +-
.../src/database/programs/metas/meta-econ.ts | 17 --
.../src/database/programs/metas/meta-hist.ts | 23 --
.../src/database/programs/metas/meta-plsc.ts | 17 --
frontend/src/types/type-program.ts | 6 +
16 files changed, 717 insertions(+), 831 deletions(-)
rename frontend/src/database/programs/{ => concs}/concs-cpsc.ts (93%)
create mode 100644 frontend/src/database/programs/concs/concs-econ.ts
create mode 100644 frontend/src/database/programs/concs/concs-hist.ts
create mode 100644 frontend/src/database/programs/concs/concs-plsc.ts
delete mode 100644 frontend/src/database/programs/configs/config-econ.ts
delete mode 100644 frontend/src/database/programs/configs/config-hist.ts
delete mode 100644 frontend/src/database/programs/configs/config-plsc.ts
delete mode 100644 frontend/src/database/programs/metas/meta-econ.ts
delete mode 100644 frontend/src/database/programs/metas/meta-hist.ts
delete mode 100644 frontend/src/database/programs/metas/meta-plsc.ts
diff --git a/frontend/src/app/majors/metadata/Metadata.tsx b/frontend/src/app/majors/metadata/Metadata.tsx
index 33f0395..2c2904e 100644
--- a/frontend/src/app/majors/metadata/Metadata.tsx
+++ b/frontend/src/app/majors/metadata/Metadata.tsx
@@ -3,129 +3,129 @@ import { useState, useEffect } from "react";
import Link from 'next/link';
import { User } from "@/types/type-user";
-import { Program } from "@/types/type-program";
+import { MajorsIndex, Program } from "@/types/type-program";
import { pinProgram, addProgram } from "./MetadataUtils";
import Style from "./Metadata.module.css";
-function MetadataTopshelf(props: {
- user: User,
- setUser: Function,
- programIndex: number,
- degreeMetadata: DegreeMetadata
-}) {
+function MetadataTopshelf(props: { program: Program })
+{
return (
-
pinProgram(props.programIndex, 0, props.user, props.setUser)}>
+ {/*
pinProgram(props.programIndex, 0, props.user, props.setUser)}>
addProgram(props.programIndex, 0, props.user, props.setUser)}>
-
+
*/}
-
{props.degreeMetadata.name}
+
+ {props.program.prog_data.prog_name}
+
- {props.degreeMetadata.info.students}
+ {props.program.prog_data.prog_stud_count}
MAJOR
- {props.degreeMetadata.abbr}
+ {props.program.prog_data.prog_abbr}
);
}
-function MetadataStats(props: { concMetadata: ConcMetadata }){
- return(
-
-
- STATS
-
-
-
-
- COURSES
-
-
- {props.concMetadata.stats.courses}
-
-
-
-
- RATING
-
-
{props.concMetadata.stats.rating}
-
-
-
- WORKLOAD
-
-
{props.concMetadata.stats.workload}
-
-
-
- TYPE
-
-
{props.concMetadata.stats.type}
-
-
-
- );
-}
-
-function MetadataBody(props: { concIndex: number, degreeMetadata: DegreeMetadata }){
-
- const { concIndex, degreeMetadata } = props;
+// function MetadataStats(props: { concMetadata: ConcMetadata }){
+// return(
+//
+//
+// STATS
+//
+//
+//
+//
+// COURSES
+//
+//
+// {props.concMetadata.stats.courses}
+//
+//
+//
+//
+// RATING
+//
+//
{props.concMetadata.stats.rating}
+//
+//
+//
+// WORKLOAD
+//
+//
{props.concMetadata.stats.workload}
+//
+//
+//
+// TYPE
+//
+//
{props.concMetadata.stats.type}
+//
+//
+//
+// );
+// }
+
+function MetadataBody(props: { program: Program, index: MajorsIndex }){
return(
-
+ {/* */}
ABOUT
- {degreeMetadata.concs[concIndex].about}
+ {props.program.prog_degs[props.index.deg].deg_concs[props.index.conc].conc_desc}
DUS
- {degreeMetadata.info.dus.name}; {degreeMetadata.info.dus.address}
+ {props.program.prog_data.prog_dus.dus_name}; {props.program.prog_data.prog_dus.dus_email}
-
MAJOR CATALOG
-
MAJOR WEBSITE
+
MAJOR CATALOG
+
MAJOR WEBSITE
);
}
-function MetadataToggle(props: { degreeMetadatas: DegreeMetadata[], degreeIndex: number, setDegreeIndex: Function, concIndex: number, setConcIndex: Function }){
- // TODO
- // If the currently selected degreeMetadata's concs attribute has length greater than 1, then
- // display an additional set of identical toggle buttons below the current set where
- // each divs content is now conc.conc_name and clicking on one calls setConcIndex for the newly clicked one.
-
+function MetadataToggle(props: { program: Program, index: MajorsIndex, setIndex: Function })
+{
return (
- {props.degreeMetadatas.map((metadata, index) => (
-
props.setDegreeIndex(index)}>
- {metadata.degreeType}
+ {props.program.prog_degs.map((deg, index) => (
+
props.setIndex({ prog: props.index.prog, deg: index, conc: props.index.conc })}
+ >
+ {deg.deg_type}
))}
- {props.degreeMetadatas[props.degreeIndex].concs.length > 1 && (
+ {props.program.prog_degs[props.index.deg].deg_concs.length > 1 && (
- {props.degreeMetadatas[props.degreeIndex].concs.map((conc, index) => (
-
props.setConcIndex(index)}>
+ {props.program.prog_degs[props.index.deg].deg_concs.map((conc, index) => (
+
props.setIndex({ prog: props.index.prog, deg: props.index.deg, conc: index })}
+ >
{conc.conc_name}
))}
@@ -136,42 +136,28 @@ function MetadataToggle(props: { degreeMetadatas: DegreeMetadata[], degreeIndex:
);
}
-function MetadataContent(props: {
- user: User,
- setUser: Function,
- programIndex: number,
- degreeMetadatas: DegreeMetadata[],
- degreeIndex: number,
- setDegreeIndex: Function
- concIndex: number,
- setConcIndex: Function
-}){
+function MetadataContent(props: { program: Program, index: MajorsIndex, setIndex: Function })
+{
return (
-
-
-
+
+
+
);
}
-function MetadataScrollButton(props: { shiftProgramIndex: Function; peekProgram: Function; dir: number })
+function MetadataScrollButton(props: { index: MajorsIndex, setIndex: Function; peekProgram: Function; dir: number })
{
return (
-
props.shiftProgramIndex(props.dir)}>
+
props.setIndex({ conc: 0, deg: 0, prog: props.index.prog + props.dir })}>
- {props.peekProgram(props.dir).name}
+ {props.peekProgram(props.dir).prog_name}
- {props.peekProgram(props.dir).abbr}
+ {props.peekProgram(props.dir).prog_abbr}
@@ -180,20 +166,13 @@ function MetadataScrollButton(props: { shiftProgramIndex: Function; peekProgram:
}
-function Metadata(props: {
- program: Program,
- index: { conc: number, deg: number, prog: number }
- peekProgram: Function
-}) {
+function Metadata(props: { program: Program, index: MajorsIndex, setIndex: Function, peekProgram: Function})
+{
return (
-
-
-
+
+
+
);
}
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index ff77375..35e197e 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -2,6 +2,7 @@
"use client";
import { useState } from "react";
import { useAuth } from "../providers";
+import { MajorsIndex } from "@/types/type-program";
import Style from "./Majors.module.css";
import NavBar from "@/components/navbar/NavBar";
@@ -11,16 +12,16 @@ import Requirements from "./requirements/Requirements";
function Majors()
{
- const { user, setUser } = useAuth();
- const { programs } = user.FYP.programs;
+ const { user } = useAuth();
- const [index, setIndex] = useState({ conc: 0, deg: 0, prog: 0});
- const updateIndex: Function = (index: { conc: number, deg: number, prog: number}) => {
- setIndex(index)
+ const [index, setIndex] = useState
({ conc: 0, deg: 0, prog: 0});
+ const updateIndex: Function = (index: MajorsIndex) => {
+ index.prog = index.prog % user.FYP.programs.length;
+ setIndex(index);
};
const peekProgram = (dir: number) => {
- return programs[(index.prog + dir + programs.length) % programs.length];
+ return user.FYP.programs[(index.prog + dir + user.FYP.programs.length) % user.FYP.programs.length].prog_data;
};
return(
@@ -29,15 +30,13 @@ function Majors()
);
diff --git a/frontend/src/database/data-courses.ts b/frontend/src/database/data-courses.ts
index 71e83a5..5939794 100644
--- a/frontend/src/database/data-courses.ts
+++ b/frontend/src/database/data-courses.ts
@@ -1,9 +1,15 @@
import { Course } from "@/types/type-user"
-// HSAR ONE
+// HSAR PROGRAM
export const HSAR_401: Course = { codes: ["HSAR 401"], title: "Critical Approaches To Art History", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+// PLSC PROGRAM
+export const PLSC_474: Course = { codes: ["PSLC 474"], title: "", credit: 1, dist: ["So"], seasons: ["Spring"]}
+export const PLSC_490: Course = { codes: ["PSLC 490"], title: "", credit: 1, dist: ["So"], seasons: ["Fall", "Spring"]}
+export const PLSC_493: Course = { codes: ["PSLC 493"], title: "", credit: 1, dist: ["So"], seasons: ["Fall", "Spring"]}
+
+
// CPSC PROGRAM
export const CPSC_201: Course = { codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const CPSC_202: Course = { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index e2d5c5e..bf2f7f3 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,6 +1,6 @@
import { User } from "./../types/type-user";
-import { PROG_CPSC } from "./programs/data-program";
+import { PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC } from "./programs/data-program";
export const Ryan: User = {
name: "Ryan",
@@ -15,7 +15,7 @@ export const Ryan: User = {
senior: [0, 202703, 202801],
},
languagePlacement: { language: "Spanish", level: 5 },
- programs: [PROG_CPSC],
+ programs: [PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC],
declarations: [],
}
}
diff --git a/frontend/src/database/programs/concs-cpsc.ts b/frontend/src/database/programs/concs/concs-cpsc.ts
similarity index 93%
rename from frontend/src/database/programs/concs-cpsc.ts
rename to frontend/src/database/programs/concs/concs-cpsc.ts
index 601e08c..45651e9 100644
--- a/frontend/src/database/programs/concs-cpsc.ts
+++ b/frontend/src/database/programs/concs/concs-cpsc.ts
@@ -1,8 +1,8 @@
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
-import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "./../data-courses";
-import { SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "./../data-studentcourses";
+import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "../../data-courses";
+import { SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "../../data-studentcourses";
// CORE
@@ -69,8 +69,8 @@ const CPSC_CORE: ConcentrationRequirement = {
const ELEC_MULT_BA: ConcentrationSubrequirement = {
subreq_name: "",
subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
- courses_required: 4,
- courses_options: [null, null, null, null],
+ courses_required: 3,
+ courses_options: [null, null, null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: false,
student_courses_satisfying: []
@@ -79,8 +79,8 @@ const ELEC_MULT_BA: ConcentrationSubrequirement = {
const ELEC_MULT_BS: ConcentrationSubrequirement = {
subreq_name: "",
subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
- courses_required: 6,
- courses_options: [null, null, null, null, null, null],
+ courses_required: 5,
+ courses_options: [null, null, null, null, null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: false,
student_courses_satisfying: []
diff --git a/frontend/src/database/programs/concs/concs-econ.ts b/frontend/src/database/programs/concs/concs-econ.ts
new file mode 100644
index 0000000..7f5df20
--- /dev/null
+++ b/frontend/src/database/programs/concs/concs-econ.ts
@@ -0,0 +1,143 @@
+
+import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
+
+import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "./../../data-courses";
+import { SC_ECON_110 } from "./../../data-studentcourses";
+
+// INTRO
+
+const INTRO_MATH: ConcentrationSubrequirement = {
+ subreq_name: "MATH",
+ subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
+ courses_required: 1,
+ courses_options: [MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const INTRO_MICRO: ConcentrationSubrequirement = {
+ subreq_name: "INTRO MICRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_108, ECON_110, ECON_115],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [SC_ECON_110],
+}
+
+const INTRO_MACRO: ConcentrationSubrequirement = {
+ subreq_name: "INTRO MACRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_111, ECON_116],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_INTRO: ConcentrationRequirement = {
+ req_name: "INTRO",
+ req_desc: "",
+ courses_required_count: 3,
+ courses_satisfied_count: 1,
+ subreqs_list: [INTRO_MATH, INTRO_MICRO, INTRO_MACRO]
+}
+
+// CORE
+
+const CORE_MICRO: ConcentrationSubrequirement = {
+ subreq_name: "INTERMEDIATE MICRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_121, ECON_125],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const CORE_MACRO: ConcentrationSubrequirement = {
+ subreq_name: "INTERMEDIATE MACRO",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_122, ECON_126],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const CORE_METRICS: ConcentrationSubrequirement = {
+ subreq_name: "ECONOMETRICS",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [ECON_117, ECON_123, ECON_136],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const ECON_CORE: ConcentrationRequirement = {
+ req_name: "CORE",
+ req_desc: "",
+ courses_required_count: 3,
+ courses_satisfied_count: 0,
+ subreqs_list: [CORE_MICRO, CORE_MACRO, CORE_METRICS]
+}
+
+// ELECTIVE
+
+const ELEC_STAN: ConcentrationSubrequirement = {
+ subreq_name: "",
+ subreq_desc: "Standard elective or DUS approved extra-department substitution.",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ELEC_SUB: ConcentrationSubrequirement = {
+ subreq_name: "",
+ subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
+ courses_required: 3,
+ courses_options: [null, null, null],
+ courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
+ courses_any_bool: true,
+ student_courses_satisfying: []
+}
+
+const ECON_ELECTIVE: ConcentrationRequirement = {
+ req_name: "ELECTIVE",
+ req_desc: "",
+ courses_required_count: 4,
+ courses_satisfied_count: 0,
+ subreqs_list: [ELEC_STAN, ELEC_SUB]
+}
+
+// SENIOR
+
+const SEN_REQ: ConcentrationSubrequirement = {
+ subreq_name: "SENIOR REQUIREMENT",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const ECON_SEN: ConcentrationRequirement = {
+ req_name: "SENIOR",
+ req_desc: "",
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+ subreqs_list: [SEN_REQ]
+}
+
+// // FINAL
+
+export const CONC_ECON_BA_I: DegreeConcentration = {
+ conc_name: "",
+ conc_desc: "",
+ conc_reqs: [ECON_INTRO, ECON_CORE, ECON_ELECTIVE, ECON_SEN]
+}
diff --git a/frontend/src/database/programs/concs/concs-hist.ts b/frontend/src/database/programs/concs/concs-hist.ts
new file mode 100644
index 0000000..1cfa69a
--- /dev/null
+++ b/frontend/src/database/programs/concs/concs-hist.ts
@@ -0,0 +1,233 @@
+import { ConcentrationRequirement, ConcentrationSubrequirement, DegreeConcentration } from "@/types/type-program";
+
+// PRE
+
+const PRE_REQ: ConcentrationSubrequirement = {
+ subreq_name: "PRE 1800",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_PRE: ConcentrationRequirement = {
+ req_name: "PREINDUSTRIAL",
+ req_desc: "",
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+ checkbox: true,
+ subreqs_list: [PRE_REQ]
+}
+
+// GLOB CORE
+
+const GLOB_CORE_AFRICA: ConcentrationSubrequirement = {
+ subreq_name: "AFRICA",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const GLOB_CORE_ASIA: ConcentrationSubrequirement = {
+ subreq_name: "ASIA",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const GLOB_CORE_EURO: ConcentrationSubrequirement = {
+ subreq_name: "EUROPE",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const GLOB_CORE_LA: ConcentrationSubrequirement = {
+ subreq_name: "LATIN AMERICA",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const GLOB_CORE_ME: ConcentrationSubrequirement = {
+ subreq_name: "MIDDLE EAST",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const GLOB_CORE_US: ConcentrationSubrequirement = {
+ subreq_name: "U.S.",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_GLOB_CORE: ConcentrationRequirement = {
+ req_name: "GLOBAL",
+ req_desc: "",
+ courses_required_count: 5,
+ courses_satisfied_count: 0,
+ subreqs_required_count: 5,
+ subreqs_satisfied_count: 0,
+ subreqs_list: [GLOB_CORE_AFRICA, GLOB_CORE_AFRICA, GLOB_CORE_EURO, GLOB_CORE_LA, GLOB_CORE_ME, GLOB_CORE_US]
+}
+
+// SPEC CORE
+
+const SPEC_CORE_IN: ConcentrationSubrequirement = {
+ subreq_name: "REGION OR PATHWAY",
+ subreq_desc: "",
+ courses_required: 5,
+ courses_options: [null, null, null, null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const SPEC_CORE_OUT: ConcentrationSubrequirement = {
+ subreq_name: "OUTSIDE",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const HIST_SPEC_CORE: ConcentrationRequirement = {
+ req_name: "SPECIALIST",
+ req_desc: "",
+ courses_required_count: 7,
+ courses_satisfied_count: 0,
+ subreqs_required_count: 2,
+ subreqs_satisfied_count: 0,
+ subreqs_list: [SPEC_CORE_IN, SPEC_CORE_OUT]
+}
+
+// SEMINAR
+
+const SEM_REQ: ConcentrationSubrequirement = {
+ subreq_name: "DEPARTMENTAL",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const HIST_SEM: ConcentrationRequirement = {
+ req_name: "SEMINAR",
+ req_desc: "",
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+ checkbox: true,
+ subreqs_list: [SEM_REQ]
+}
+
+// GLOB ELEC
+
+const GLOB_ELEC_REQ: ConcentrationSubrequirement = {
+ subreq_name: "",
+ subreq_desc: "",
+ courses_required: 5,
+ courses_options: [null, null, null, null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const HIST_GLOB_ELEC: ConcentrationRequirement = {
+ req_name: "ELECTIVE",
+ req_desc: "",
+ courses_required_count: 5,
+ courses_satisfied_count: 0,
+ subreqs_list: [GLOB_ELEC_REQ]
+}
+
+// SPEC ELEC
+
+const SPEC_ELEC_REQ: ConcentrationSubrequirement = {
+ subreq_name: "",
+ subreq_desc: "",
+ courses_required: 3,
+ courses_options: [null, null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const HIST_SPEC_ELEC: ConcentrationRequirement = {
+ req_name: "ELECTIVE",
+ req_desc: "",
+ courses_required_count: 3,
+ courses_satisfied_count: 0,
+ subreqs_list: [SPEC_ELEC_REQ]
+}
+
+// SENIOR
+
+const SEN_ONE: ConcentrationSubrequirement = {
+ subreq_name: "ONE TERM",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const SEN_TWO: ConcentrationSubrequirement = {
+ subreq_name: "TWO TERM",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const HIST_SEN: ConcentrationRequirement = {
+ req_name: "SENIOR",
+ req_desc: "",
+ courses_required_count: 0,
+ courses_satisfied_count: 0,
+ subreqs_required_count: 1,
+ subreqs_satisfied_count: 0,
+ subreqs_list: [SEN_ONE, SEN_TWO]
+}
+
+// EXPORT
+
+export const CONC_HIST_BA_GLOB: DegreeConcentration = {
+ conc_name: "GLOBALIST",
+ conc_desc: "",
+ conc_reqs: [HIST_PRE, HIST_GLOB_CORE, HIST_SEM, HIST_GLOB_ELEC, HIST_SEN]
+}
+
+export const CONC_HIST_BA_SPEC: DegreeConcentration = {
+ conc_name: "SPECIALIST",
+ conc_desc: "",
+ conc_reqs: [HIST_PRE, HIST_SPEC_CORE, HIST_SEM, HIST_SPEC_ELEC, HIST_SEN]
+}
diff --git a/frontend/src/database/programs/concs/concs-plsc.ts b/frontend/src/database/programs/concs/concs-plsc.ts
new file mode 100644
index 0000000..422947f
--- /dev/null
+++ b/frontend/src/database/programs/concs/concs-plsc.ts
@@ -0,0 +1,220 @@
+
+import { DegreeConcentration, ConcentrationRequirement, ConcentrationSubrequirement } from "@/types/type-program";
+import { PLSC_474, PLSC_490, PLSC_493 } from "@/database/data-courses";
+
+// INTRO
+
+const INTRO_REQ: ConcentrationSubrequirement = {
+ subreq_name: "INTRO COURSES",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const PLSC_INTRO: ConcentrationRequirement = {
+ req_name: "INTRO",
+ req_desc: "",
+ courses_required_count: 3,
+ courses_satisfied_count: 1,
+ subreqs_list: [INTRO_REQ]
+}
+
+// CORE
+
+const CORE_LECT: ConcentrationSubrequirement = {
+ subreq_name: "CORE LECTURES",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const CORE_METH: ConcentrationSubrequirement = {
+ subreq_name: "METHODS AND FORMAL THEORY",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const PLSC_CORE_STAN: ConcentrationRequirement = {
+ req_name: "CORE",
+ req_desc: "",
+ courses_required_count: 3,
+ courses_satisfied_count: 0,
+ subreqs_list: [CORE_LECT, CORE_METH]
+}
+
+const CORE_RESE: ConcentrationSubrequirement = {
+ subreq_name: "RESEARCH",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [PLSC_474],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: [],
+}
+
+const PLSC_CORE_INTE: ConcentrationRequirement = {
+ req_name: "CORE",
+ req_desc: "",
+ courses_required_count: 4,
+ courses_satisfied_count: 0,
+ subreqs_list: [CORE_LECT, CORE_METH, CORE_RESE]
+}
+
+// ELECTIVE
+
+const SUB_INTL: ConcentrationSubrequirement = {
+ subreq_name: "INTERNATIONAL RELATIONS",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const SUB_US: ConcentrationSubrequirement = {
+ subreq_name: "AMERICAN GOVERNMENT",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const SUB_PHIL: ConcentrationSubrequirement = {
+ subreq_name: "POLITICAL PHILOSOPHY",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const SUB_COMP: ConcentrationSubrequirement = {
+ subreq_name: "COMPARATIVE POLITICS",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const PLSC_SUB: ConcentrationRequirement = {
+ req_name: "SUBFIELDS",
+ req_desc: "",
+ courses_required_count: 4,
+ courses_satisfied_count: 0,
+ subreqs_required_count: 2,
+ subreqs_satisfied_count: 0,
+ subreqs_list: [SUB_INTL, SUB_US, SUB_PHIL, SUB_COMP]
+}
+
+// SEMINAR
+
+const SEM_ANY: ConcentrationSubrequirement = {
+ subreq_name: "YEAR ANY",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const SEM_SEN: ConcentrationSubrequirement = {
+ subreq_name: "YEAR SENIOR",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const PLSC_SEMINAR: ConcentrationRequirement = {
+ req_name: "SEMINAR",
+ req_desc: "Seminar courses taught by PLSC faculty satisfy.",
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+ checkbox: true,
+ subreqs_list: [SEM_ANY, SEM_SEN]
+}
+
+// SEN STANDARD
+
+const SEN_STAN_ONE: ConcentrationSubrequirement = {
+ subreq_name: "ONE TERM",
+ subreq_desc: "",
+ courses_required: 1,
+ courses_options: [null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const SEN_STAN_TWO: ConcentrationSubrequirement = {
+ subreq_name: "TWO TERM",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [null, null],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const PLSC_SEN_STAN: ConcentrationRequirement = {
+ req_name: "SENIOR",
+ req_desc: "",
+ courses_required_count: 0,
+ courses_satisfied_count: 0,
+ subreqs_required_count: 1,
+ subreqs_satisfied_count: 0,
+ subreqs_list: [SEN_STAN_ONE, SEN_STAN_TWO]
+}
+
+// SEN INTENSIVE
+
+const SEN_INTE_REQ: ConcentrationSubrequirement = {
+ subreq_name: "TWO TERM",
+ subreq_desc: "",
+ courses_required: 2,
+ courses_options: [PLSC_490, PLSC_493],
+ courses_elective_range: null,
+ courses_any_bool: false,
+ student_courses_satisfying: []
+}
+
+const PLSC_SEN_INTE: ConcentrationRequirement = {
+ req_name: "SENIOR",
+ req_desc: "",
+ courses_required_count: 2,
+ courses_satisfied_count: 0,
+ subreqs_list: [SEN_INTE_REQ]
+}
+
+// EXPORT
+
+export const CONC_PLSC_BA_STAN: DegreeConcentration = {
+ conc_name: "STANDARD",
+ conc_desc: "",
+ conc_reqs: [PLSC_INTRO, PLSC_CORE_STAN, PLSC_SUB, PLSC_SEMINAR, PLSC_SEN_STAN]
+}
+
+export const CONC_PLSC_BA_INTE: DegreeConcentration = {
+ conc_name: "INTENSIVE",
+ conc_desc: "",
+ conc_reqs: [PLSC_INTRO, PLSC_CORE_INTE, PLSC_SUB, PLSC_SEMINAR, PLSC_SEN_INTE]
+}
diff --git a/frontend/src/database/programs/configs/config-econ.ts b/frontend/src/database/programs/configs/config-econ.ts
deleted file mode 100644
index 30b1553..0000000
--- a/frontend/src/database/programs/configs/config-econ.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-
-// import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-
-// import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "../data-courses";
-// import { SC_ECON_110 } from "../data-studentcourses";
-
-// // INTRO
-
-// const ECON_MATH: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "MATH",
-// subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
-// courses_required: 1,
-// courses_options: [null, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const ECON_INTRO_MICRO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "INTRO MICRO",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [ECON_108, ECON_110, ECON_115],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [SC_ECON_110],
-// }
-
-// const ECON_INTRO_MACRO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "INTRO MACRO",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [ECON_111, ECON_116],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const ECON_INTRO: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "INTRO",
-// req_desc: "",
-
-// courses_required_count: 3,
-// courses_satisfied_count: 1,
-
-// subreqs_list: [ECON_MATH, ECON_INTRO_MICRO, ECON_INTRO_MACRO]
-// }
-
-// // CORE
-
-// const ECON_CORE_MICRO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "INTERMEDIATE MICRO",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [ECON_121, ECON_125],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const ECON_CORE_MACRO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "INTERMEDIATE MACRO",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [ECON_122, ECON_126],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const ECON_CORE_METRICS: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "ECONOMETRICS",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [ECON_117, ECON_123, ECON_136],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const ECON_CORE: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "CORE",
-// req_desc: "",
-
-// courses_required_count: 3,
-// courses_satisfied_count: 0,
-
-// subreqs_list: [ECON_CORE_MICRO, ECON_CORE_MACRO, ECON_CORE_METRICS]
-// }
-
-// // ELECTIVE
-
-// const ECON_RANGE_ELECS: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "",
-// subreq_desc: "Standard elective or DUS approved extra-department substitution.",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: { dept: "CPSC", min_code: 123, max_code: 999 },
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const ECON_SUB_ELEC: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "",
-// subreq_desc: "Intermediate or advanced ECON courses, traditionally numbered 123+.",
-// courses_required: 3,
-// courses_options: [null, null, null],
-// courses_elective_range: { dept: "ECON", min_code: 123, max_code: 999 },
-// courses_any_bool: true,
-// student_courses_satisfying: []
-// }
-
-// const ECON_ELECTIVES: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "ELECTIVE",
-// req_desc: "",
-
-// courses_required_count: 4,
-// courses_satisfied_count: 0,
-
-// subreqs_list: [ECON_SUB_ELEC, ECON_RANGE_ELECS]
-// }
-
-// // SENIOR
-
-// const ECON_SEN_SUB: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "SENIOR REQUIREMENT",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: { dept: "ECON", min_code: 400, max_code: 491 },
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const ECON_SENIOR: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SENIOR",
-// req_desc: "",
-
-// courses_required_count: 2,
-// courses_satisfied_count: 0,
-
-// subreqs_list: [ECON_SEN_SUB]
-// }
-
-// // FINAL
-
-// export const ECON_CONFIG: DegreeConfiguration = {
-// reqs_list: [ECON_INTRO, ECON_CORE, ECON_ELECTIVES, ECON_SENIOR]
-// }
diff --git a/frontend/src/database/programs/configs/config-hist.ts b/frontend/src/database/programs/configs/config-hist.ts
deleted file mode 100644
index 5786583..0000000
--- a/frontend/src/database/programs/configs/config-hist.ts
+++ /dev/null
@@ -1,273 +0,0 @@
-
-// import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-
-// // PRE
-
-// const HIST_PRE: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "PRE 1800",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_PREINDUSTRIAL: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "PREINDUSTRIAL",
-// req_desc: "",
-
-// courses_required_count: 2,
-// courses_satisfied_count: 0,
-
-// checkbox: true,
-// subreqs_list: [HIST_PRE]
-// }
-
-// // GLOBAL
-
-// const HIST_CORE_GLOB_AFRICA: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "AFRICA",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_CORE_GLOB_ASIA: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "ASIA",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_CORE_GLOB_EUROPE: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "EUROPE",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_CORE_GLOB_LA: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "LATIN AMERICA",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_CORE_GLOB_ME: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "MIDDLE EAST",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_CORE_GLOB_US: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "U.S.",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_GLOB_CORE: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "GLOBAL",
-// req_desc: "",
-
-// courses_required_count: 5,
-// courses_satisfied_count: 0,
-
-// subreqs_required_count: 5,
-// subreqs_satisfied_count: 0,
-
-// subreqs_list: [HIST_CORE_GLOB_AFRICA, HIST_CORE_GLOB_ASIA, HIST_CORE_GLOB_EUROPE, HIST_CORE_GLOB_LA, HIST_CORE_GLOB_ME, HIST_CORE_GLOB_US]
-// }
-
-// // SEMINAR
-
-// const HIST_DEPT_SEMINAR: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "DEPARTMENTAL",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const HIST_SEMINAR: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SEMINAR",
-// req_desc: "",
-
-// courses_required_count: 2,
-// courses_satisfied_count: 0,
-
-// checkbox: true,
-// subreqs_list: [HIST_DEPT_SEMINAR]
-// }
-
-// // ELECTIVE
-
-// const HIST_ELEC_SPEC_INDIV: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "",
-// subreq_desc: "",
-// courses_required: 3,
-// courses_options: [null, null, null, null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const HIST_ELEC_GLOB_INDIV: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "",
-// subreq_desc: "",
-// courses_required: 5,
-// courses_options: [null, null, null, null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const HIST_ELECTIVE_SPEC: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "ELECTIVE",
-// req_desc: "",
-
-// courses_required_count: 3,
-// courses_satisfied_count: 0,
-
-// subreqs_list: [HIST_ELEC_SPEC_INDIV]
-// }
-
-// const HIST_ELECTIVE_GLOB: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "ELECTIVE",
-// req_desc: "",
-
-// courses_required_count: 5,
-// courses_satisfied_count: 0,
-
-// subreqs_list: [HIST_ELEC_GLOB_INDIV]
-// }
-
-// // SENIOR
-
-// const ECON_SEN_ONE: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "ONE TERM",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const ECON_SEN_TWO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "TWO TERM",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const ECON_SENIOR: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SENIOR",
-// req_desc: "",
-
-// courses_required_count: 0,
-// courses_satisfied_count: 0,
-
-// subreqs_required_count: 1,
-// subreqs_satisfied_count: 0,
-
-// subreqs_list: [ECON_SEN_ONE, ECON_SEN_TWO]
-// }
-
-// // FINAL
-
-// const HIST_SPEC_CORE_IN: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "REGION OR PATHWAY",
-// subreq_desc: "",
-// courses_required: 5,
-// courses_options: [null, null, null, null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_SPEC_CORE_OUT: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "OUTSIDE",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const HIST_SPEC_CORE: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SPECIALIST",
-// req_desc: "",
-
-// courses_required_count: 7,
-// courses_satisfied_count: 0,
-
-// subreqs_required_count: 2,
-// subreqs_satisfied_count: 0,
-
-// subreqs_list: [HIST_SPEC_CORE_IN, HIST_SPEC_CORE_OUT]
-// }
-
-// // LAST
-
-// export const HIST_CONFIG_BA_SPEC: DegreeConfiguration = {
-// config_name: "SPECIALIST",
-// reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_SPEC_CORE, HIST_ELECTIVE_SPEC, ECON_SENIOR]
-// }
-
-// export const HIST_CONFIG_BA_GLOB: DegreeConfiguration = {
-// config_name: "GLOBALIST",
-// reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_GLOB_CORE, HIST_ELECTIVE_GLOB, ECON_SENIOR]
-// }
-
-// export const HIST_CONFIG_BA: DegreeConfiguration = {
-// config_name: "GLOBALIST",
-// reqs_list: [HIST_PREINDUSTRIAL, HIST_SEMINAR, HIST_GLOB_CORE, HIST_ELECTIVE_GLOB, ECON_SENIOR]
-// }
\ No newline at end of file
diff --git a/frontend/src/database/programs/configs/config-plsc.ts b/frontend/src/database/programs/configs/config-plsc.ts
deleted file mode 100644
index 1649d77..0000000
--- a/frontend/src/database/programs/configs/config-plsc.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-
-// import { DegreeConfiguration, DegreeRequirement, DegreeSubrequirement } from "@/types/type-program";
-
-// // INTRO
-
-// const PLSC_INTRO_TWO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "INTRO COURSES",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const PLSC_INTRO: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "INTRO",
-// req_desc: "",
-
-// courses_required_count: 3,
-// courses_satisfied_count: 1,
-
-// subreqs_list: [PLSC_INTRO_TWO]
-// }
-
-// // CORE
-
-// const PLSC_CORE_LECTURES: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "CORE LECTURES",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const PLSC_CORE_METHODS: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "METHODS AND FORMAL THEORY",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: [],
-// }
-
-// const PLSC_CORE: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "CORE",
-// req_desc: "",
-
-// courses_required_count: 3,
-// courses_satisfied_count: 0,
-
-// subreqs_list: [PLSC_CORE_LECTURES, PLSC_CORE_METHODS]
-// }
-
-// // ELECTIVE
-
-// const PLSC_SUB_INTL: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "INTERNATIONAL RELATIONS",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SUB_US: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "AMERICAN GOVERNMENT",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SUB_PHIL: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "POLITICAL PHILOSOPHY",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SUB_COMP: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "COMPARATIVE POLITICS",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SUBFIELDS: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SUBFIELDS",
-// req_desc: "",
-
-// courses_required_count: 4,
-// courses_satisfied_count: 0,
-
-// subreqs_required_count: 2,
-// subreqs_satisfied_count: 0,
-
-// subreqs_list: [PLSC_SUB_INTL, PLSC_SUB_US, PLSC_SUB_PHIL, PLSC_SUB_COMP]
-// }
-
-// // SEMINAR
-
-// const PLSC_SEM_ANY: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "YEAR ANY",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SEM_SEN: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "YEAR SENIOR",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SEMINAR: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SEMINAR",
-// req_desc: "Seminar courses taught by PLSC faculty satisfy.",
-
-// courses_required_count: 2,
-// courses_satisfied_count: 0,
-
-// checkbox: true,
-// subreqs_list: [PLSC_SEM_ANY, PLSC_SEM_SEN]
-// }
-
-// // SENIOR
-
-// const PLSC_SEN_ONE: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "ONE TERM",
-// subreq_desc: "",
-// courses_required: 1,
-// courses_options: [null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SEN_TWO: DegreeSubrequirement = {
-// subreq_type_id: 1,
-// subreq_name: "TWO TERM",
-// subreq_desc: "",
-// courses_required: 2,
-// courses_options: [null, null],
-// courses_elective_range: null,
-// courses_any_bool: false,
-// student_courses_satisfying: []
-// }
-
-// const PLSC_SENIOR: DegreeRequirement = {
-// req_type_id: 1,
-// req_name: "SENIOR",
-// req_desc: "",
-
-// courses_required_count: 0,
-// courses_satisfied_count: 0,
-
-// subreqs_required_count: 1,
-// subreqs_satisfied_count: 0,
-
-// subreqs_list: [PLSC_SEN_ONE, PLSC_SEN_TWO]
-// }
-
-// // FINAL
-
-// export const PLSC_CONFIG: DegreeConfiguration = {
-// reqs_list: [PLSC_INTRO, PLSC_CORE, PLSC_SUBFIELDS, PLSC_SEMINAR, PLSC_SENIOR]
-// }
diff --git a/frontend/src/database/programs/data-program.ts b/frontend/src/database/programs/data-program.ts
index 3cf4a92..d56d96b 100644
--- a/frontend/src/database/programs/data-program.ts
+++ b/frontend/src/database/programs/data-program.ts
@@ -1,6 +1,9 @@
import { Program } from "@/types/type-program";
-import { CONC_CPSC_BA_I, CONC_CPSC_BS_I } from "./concs-cpsc";
+import { CONC_CPSC_BA_I, CONC_CPSC_BS_I } from "./concs/concs-cpsc";
+import { CONC_ECON_BA_I } from "./concs/concs-econ";
+import { CONC_HIST_BA_GLOB, CONC_HIST_BA_SPEC } from "./concs/concs-hist";
+import { CONC_PLSC_BA_INTE, CONC_PLSC_BA_STAN } from "./concs/concs-plsc";
export const PROG_CPSC: Program = {
prog_data: {
@@ -27,14 +30,7 @@ export const PROG_ECON: Program = {
prog_website: ""
},
prog_degs: [
- {
- deg_type: "B.A.",
- deg_concs: []
- },
- {
- deg_type: "B.S.",
- deg_concs: []
- }
+ { deg_type: "B.A.", deg_concs: [CONC_ECON_BA_I] }
]
}
@@ -48,10 +44,7 @@ export const PROG_PLSC: Program = {
prog_website: ""
},
prog_degs: [
- {
- deg_type: "B.A.",
- deg_concs: []
- }
+ { deg_type: "B.A.", deg_concs: [CONC_PLSC_BA_STAN, CONC_PLSC_BA_INTE] }
]
}
@@ -67,7 +60,7 @@ export const PROG_HIST: Program = {
prog_degs: [
{
deg_type: "B.A.",
- deg_concs: []
+ deg_concs: [CONC_HIST_BA_GLOB, CONC_HIST_BA_SPEC]
}
]
}
diff --git a/frontend/src/database/programs/metas/meta-econ.ts b/frontend/src/database/programs/metas/meta-econ.ts
deleted file mode 100644
index 2518fc1..0000000
--- a/frontend/src/database/programs/metas/meta-econ.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-
-// import { ConcMetadata, DegreeMetadata } from "@/types/type-program";
-
-// const CONC_ECON_GEN: ConcMetadata = {
-// conc_name: "",
-// stats: { courses: 0, rating: 0, type: "So", workload: 0 },
-// about: "The Economics major provides a rigorous framework for understanding financial markets, public policy, and decision-making. Students learn analytical techniques in microeconomics, macroeconomics, and econometrics, developing critical skills in data interpretation and policy evaluation. The major offers pathways in finance, economic development, and quantitative analysis, preparing students for careers in government, consulting, business, and research.",
-// }
-
-// export const META_ECON_BA: DegreeMetadata = {
-// name: "Economics",
-// abbr: "ECON",
-// degreeType: "B.A.",
-
-// concs: [CONC_ECON_GEN],
-// info: { students: 0, dus: { address: "28 Hillhouse Ave, (203) 432-3576", email: "economics@yale.edu", name: "Dirk Bergemann" }, wesbiteLink: "https://economics.yale.edu", catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/economics/" }
-// }
diff --git a/frontend/src/database/programs/metas/meta-hist.ts b/frontend/src/database/programs/metas/meta-hist.ts
deleted file mode 100644
index 8b492e1..0000000
--- a/frontend/src/database/programs/metas/meta-hist.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-
-// import { ConcMetadata, DegreeMetadata } from "@/types/type-program";
-
-// const META_HIST_GLOB: ConcMetadata = {
-// conc_name: "Globalist",
-// stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
-// about: "The History major offers a broad exploration of human experience across time, cultures, and societies. Students gain expertise in archival research, critical analysis, and historical interpretation. The major prepares students to engage with contemporary issues by understanding their historical contexts, whether in politics, economics, or cultural transformations. History students learn to construct arguments based on evidence and develop a strong capacity for analytical reasoning and effective communication.",
-// }
-
-// const META_HIST_SPEC: ConcMetadata = {
-// conc_name: "Specialist",
-// stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
-// about: "The History major offers a broad exploration of human experience across time, cultures, and societies. Students gain expertise in archival research, critical analysis, and historical interpretation. The major prepares students to engage with contemporary issues by understanding their historical contexts, whether in politics, economics, or cultural transformations. History students learn to construct arguments based on evidence and develop a strong capacity for analytical reasoning and effective communication.",
-// }
-
-// export const META_HIST_BA: DegreeMetadata = {
-// name: "History",
-// abbr: "HIST",
-// degreeType: "B.A.",
-
-// concs: [META_HIST_GLOB, META_HIST_SPEC],
-// info: { students: 0, dus: { address: "HQ 211, (203) 432-1366", email: "history@yale.edu", name: "Alan Mikhail" }, wesbiteLink: "https://history.yale.edu", catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/history/" }
-// }
\ No newline at end of file
diff --git a/frontend/src/database/programs/metas/meta-plsc.ts b/frontend/src/database/programs/metas/meta-plsc.ts
deleted file mode 100644
index 9ea7064..0000000
--- a/frontend/src/database/programs/metas/meta-plsc.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-
-// import { ConcMetadata, DegreeMetadata } from "@/types/type-program";
-
-// const META_PLSC: ConcMetadata = {
-// conc_name: "",
-// stats: { courses: 0, rating: 0, type: "Hu", workload: 0 },
-// about: "The Political Science major examines governments, political behavior, and institutional structures at local, national, and global levels. Students engage with the theoretical foundations of politics, quantitative and qualitative methodologies, and policy analysis. The program prepares students for careers in law, public policy, international relations, and academia while offering flexibility to explore subfields such as comparative politics, American politics, and political philosophy.",
-// }
-
-// export const META_PLSC_BA: DegreeMetadata = {
-// name: "Political Science",
-// abbr: "PLSC",
-// degreeType: "B.A.",
-
-// concs: [META_PLSC],
-// info: { students: 0, dus: { address: "Rosenkranz Hall 130, (203) 432-5248", email: "politicalscience@yale.edu", name: "Isabela Mares" }, wesbiteLink: "https://politicalscience.yale.edu", catologLink: "https://catalog.yale.edu/ycps/subjects-of-instruction/history/" }
-// }
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index a18486a..e930036 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -71,3 +71,9 @@ export interface Program {
prog_data: ProgramMetadata;
prog_degs: ProgramDegree[];
}
+
+export interface MajorsIndex {
+ prog: number;
+ deg: number;
+ conc: number;
+}
From 9b9f61b1d8b45d8065fcf13c7b1c6ebd3a98881b Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Tue, 11 Mar 2025 11:51:49 -0700
Subject: [PATCH 18/38] program list
---
frontend/src/app/majors/Majors.module.css | 26 ++++-
.../app/majors/metadata/Metadata.module.css | 16 ++-
frontend/src/app/majors/metadata/Metadata.tsx | 52 ++++++---
.../src/app/majors/metadata/MetadataUtils.tsx | 107 ------------------
frontend/src/app/majors/page.tsx | 48 ++++----
.../app/majors/requirements/Requirements.tsx | 35 +++---
6 files changed, 115 insertions(+), 169 deletions(-)
delete mode 100644 frontend/src/app/majors/metadata/MetadataUtils.tsx
diff --git a/frontend/src/app/majors/Majors.module.css b/frontend/src/app/majors/Majors.module.css
index 0243411..24bbae8 100644
--- a/frontend/src/app/majors/Majors.module.css
+++ b/frontend/src/app/majors/Majors.module.css
@@ -1,19 +1,15 @@
.MajorsPage {
/* border: 1px solid blue; */
-
position: absolute;
top: 75px;
display: flex;
flex-direction: row;
-
justify-content: center;
width: 100%;
height: calc(100vh - 75px);
-
- /* padding-top: 50px; */
}
.Divider {
@@ -26,3 +22,25 @@
width: 1px;
height: calc(100% - 100px);
}
+
+.EditButton {
+ position: fixed;
+
+ top: 95px;
+ left: 20px;
+
+ width: 30px;
+ height: 30px;
+
+ color: white;
+ text-align: center;
+ line-height: 30px;
+ font-size: 20px;
+
+ background-color: #61ADFE;
+ border: none;
+ border-radius: 50%;
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25);
+
+ z-index: 2;
+}
\ No newline at end of file
diff --git a/frontend/src/app/majors/metadata/Metadata.module.css b/frontend/src/app/majors/metadata/Metadata.module.css
index 5293146..56af915 100644
--- a/frontend/src/app/majors/metadata/Metadata.module.css
+++ b/frontend/src/app/majors/metadata/Metadata.module.css
@@ -11,7 +11,6 @@
.MetadataContainer{
/* border: 1px solid red; */
-
margin-top: 75px;
width: 550px;
@@ -99,7 +98,7 @@
background-color: white;
border: none;
cursor: pointer;
- padding: 10px;
+ /* padding: 10px; */
display: inline-block;
}
@@ -107,11 +106,12 @@
display: flex;
flex-direction: row;
- margin-left: 80px;
+ /* margin-left: 80px; */
margin-bottom: 8px;
}
.ToggleOption {
+ font-size: 14px;
padding: 4px 10px;
cursor: pointer;
background-color: white;
@@ -126,4 +126,12 @@
.ToggleOption.active {
background-color: #598ff4;
color: white;
-}
\ No newline at end of file
+}
+
+.ProgramOption {
+ color: gray;
+ font-size: 20px;
+ font-weight: bold;
+ margin-bottom: 4px;
+ cursor: pointer;
+}
diff --git a/frontend/src/app/majors/metadata/Metadata.tsx b/frontend/src/app/majors/metadata/Metadata.tsx
index 2c2904e..d9212c1 100644
--- a/frontend/src/app/majors/metadata/Metadata.tsx
+++ b/frontend/src/app/majors/metadata/Metadata.tsx
@@ -1,12 +1,9 @@
import { useState, useEffect } from "react";
-import Link from 'next/link';
+import Style from "./Metadata.module.css";
-import { User } from "@/types/type-user";
+import Link from 'next/link';
import { MajorsIndex, Program } from "@/types/type-program";
-import { pinProgram, addProgram } from "./MetadataUtils";
-
-import Style from "./Metadata.module.css";
function MetadataTopshelf(props: { program: Program })
{
@@ -80,7 +77,8 @@ function MetadataTopshelf(props: { program: Program })
function MetadataBody(props: { program: Program, index: MajorsIndex }){
return(
-
+ // style={{ marginLeft: "80px" }}
+
{/*
*/}
ABOUT
@@ -147,17 +145,17 @@ function MetadataContent(props: { program: Program, index: MajorsIndex, setIndex
);
}
-function MetadataScrollButton(props: { index: MajorsIndex, setIndex: Function; peekProgram: Function; dir: number })
+function MetadataScrollButton(props: { programs: Program[], index: MajorsIndex, setIndex: Function; dir: number })
{
- return (
+ return(
props.setIndex({ conc: 0, deg: 0, prog: props.index.prog + props.dir })}>
- {props.peekProgram(props.dir).prog_name}
+ {props.programs[(props.index.prog + props.dir + props.programs.length) % props.programs.length].prog_data.prog_name}
- {props.peekProgram(props.dir).prog_abbr}
+ {props.programs[(props.index.prog + props.dir + props.programs.length) % props.programs.length].prog_data.prog_abbr}
@@ -165,14 +163,38 @@ function MetadataScrollButton(props: { index: MajorsIndex, setIndex: Function; p
);
}
+function ProgramContent(props: { programs: Program[], index: MajorsIndex, setIndex: Function }){
+ return(
+
+
+
+
+
+ )
+}
+
+function ProgramList(props: { programs: Program[], setIndex: Function }){
+ return(
+
+ {props.programs.map((program: Program, prog_index: number) => (
+
props.setIndex({ conc: 0, deg: 0, prog: prog_index })}>
+ {program.prog_data.prog_name} {program.prog_data.prog_abbr}
+
+ ))}
+
+ )
+}
-function Metadata(props: { program: Program, index: MajorsIndex, setIndex: Function, peekProgram: Function})
+function Metadata(props: { programs: Program[], index: MajorsIndex, setIndex: Function })
{
- return (
+ return(
-
-
-
+ {props.index.conc == -1 ? (
+
+ ) : (
+
+ )
+ }
);
}
diff --git a/frontend/src/app/majors/metadata/MetadataUtils.tsx b/frontend/src/app/majors/metadata/MetadataUtils.tsx
deleted file mode 100644
index f0ca59c..0000000
--- a/frontend/src/app/majors/metadata/MetadataUtils.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-
-import { User } from "@/types/type-user";
-import { StudentDegree } from "@/types/type-program";
-
-export function pinProgram(
- currProgram: number,
- currDegree: number,
- user: User,
- setUser: Function,
-) {
- // Find if the program is already in degreeDeclarations
- const existingDegree = user.FYP.degreeDeclarations.find(
- (degree) => degree.programIndex === currProgram
- );
-
- if (existingDegree) {
- if (existingDegree.status === "PIN") {
- // Unpin the program (remove it from degreeDeclarations)
- const updatedUser: User = {
- ...user,
- FYP: {
- ...user.FYP,
- degreeDeclarations: user.FYP.degreeDeclarations.filter(
- (degree) => degree.programIndex !== currProgram
- ),
- },
- };
- setUser(updatedUser);
- }
- } else {
- // Pin the program if it's not already pinned or added
- const newStudentDegree: StudentDegree = {
- status: "PIN",
- programIndex: currProgram,
- degreeIndex: currDegree,
- };
-
- const updatedUser: User = {
- ...user,
- FYP: {
- ...user.FYP,
- degreeDeclarations: [...user.FYP.degreeDeclarations, newStudentDegree],
- },
- };
- setUser(updatedUser);
- }
-}
-
-
-// Utility function to add a program
-export function addProgram(
- currProgram: number,
- currDegree: number,
- user: User,
- setUser: Function
-) {
- // Find if the program already exists in degreeDeclarations
- const existingDegree = user.FYP.degreeDeclarations.find(
- (degree) => degree.programIndex === currProgram
- );
-
- if (existingDegree) {
- if (existingDegree.status === "ADD") {
- // Unadd the program (remove it from degreeDeclarations)
- const updatedUser: User = {
- ...user,
- FYP: {
- ...user.FYP,
- degreeDeclarations: user.FYP.degreeDeclarations.filter(
- (degree) => degree.programIndex !== currProgram
- ),
- },
- };
- setUser(updatedUser);
- } else if (existingDegree.status === "PIN") {
- // Change status from "PIN" to "ADD"
- const updatedUser: User = {
- ...user,
- FYP: {
- ...user.FYP,
- degreeDeclarations: user.FYP.degreeDeclarations.map((degree) =>
- degree.programIndex === currProgram
- ? { ...degree, status: "ADD" }
- : degree
- ),
- },
- };
- setUser(updatedUser);
- }
- } else {
- // Add the program if it's not already pinned or added
- const newStudentDegree: StudentDegree = {
- status: "ADD",
- programIndex: currProgram,
- degreeIndex: currDegree,
- };
-
- const updatedUser: User = {
- ...user,
- FYP: {
- ...user.FYP,
- degreeDeclarations: [...user.FYP.degreeDeclarations, newStudentDegree],
- },
- };
- setUser(updatedUser);
- }
-}
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 35e197e..cbd9f16 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -1,42 +1,50 @@
"use client";
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { useAuth } from "../providers";
import { MajorsIndex } from "@/types/type-program";
import Style from "./Majors.module.css";
import NavBar from "@/components/navbar/NavBar";
-import Overhead from "./overhead/Overhead";
+// import Overhead from "./overhead/Overhead";
import Metadata from "./metadata/Metadata";
import Requirements from "./requirements/Requirements";
function Majors()
{
const { user } = useAuth();
+ const [index, setIndex] = useState
({ conc: 0, deg: 0, prog: 0 });
+
+ useEffect(() => {
+ if(typeof window !== "undefined"){
+ const storedIndex = sessionStorage.getItem("majorsIndex");
+ if(storedIndex){
+ setIndex(JSON.parse(storedIndex));
+ }
+ }
+ }, []);
- const [index, setIndex] = useState({ conc: 0, deg: 0, prog: 0});
- const updateIndex: Function = (index: MajorsIndex) => {
- index.prog = index.prog % user.FYP.programs.length;
- setIndex(index);
- };
+ useEffect(() => {
+ if(typeof window !== "undefined"){
+ sessionStorage.setItem("majorsIndex", JSON.stringify(index));
+ }
+ }, [index]);
- const peekProgram = (dir: number) => {
- return user.FYP.programs[(index.prog + dir + user.FYP.programs.length) % user.FYP.programs.length].prog_data;
- };
+ const updateIndex = (newIndex: MajorsIndex) => {
+ if(newIndex.conc === -1){
+ setIndex({ ...newIndex, deg: 0, conc: index.conc === -1 ? 0 : -1 });
+ return;
+ }
+ setIndex({ ...newIndex, prog: (newIndex.prog + user.FYP.programs.length) % user.FYP.programs.length });
+ };
- return(
+ return(
- {/* utility={
} */}
-
+ updateIndex({ ...index, conc: -1 })}/>}/>
);
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 82fce59..9337a83 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -2,17 +2,13 @@
import { useState } from "react";
import Style from "./Requirements.module.css";
-import { useAuth } from "@/app/providers";
-
-import { User, Course } from "@/types/type-user";
+import { Course } from "@/types/type-user";
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
import { CourseIcon } from "@/components/course-icon/CourseIcon";
-function RenderSubrequirementCourse(props: { course: Course | null, subreq: ConcentrationSubrequirement; user: User }){
+function RenderSubrequirementCourse(props: { course: Course | null, subreq: ConcentrationSubrequirement }){
- // TODO
-
if(props.course === null){
return(
@@ -30,7 +26,7 @@ function RenderSubrequirementCourse(props: { course: Course | null, subreq: Conc
)
}
-function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement; user: User }) {
+function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement }) {
const [showAll, setShowAll] = useState(false);
// Separate null and non-null courses
@@ -60,7 +56,7 @@ function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement; user
{displayedCourses.map((course, index) => (
-
+
))}
{/* Toggle Button to Expand / Collapse */}
@@ -148,18 +144,16 @@ function RenderRequirement(props: { req: ConcentrationRequirement }){
{subreqs_required_count
? subreqs_list.slice(0, subreqs_required_count).map((subreq, index) => (
-
+
))
: subreqs_list.map((subreq, index) => (
-
+
))}
);
}
-
-// function RequirementsContent(props: { edit: boolean, programIndex: number, degreeIndex: number, degreeConfiguration: DegreeConfiguration, user: User, setUser: Function })
function RequirementsContent(props: { conc: DegreeConcentration })
{
@@ -172,15 +166,14 @@ function RequirementsContent(props: { conc: DegreeConcentration })
);
}
-// function Requirements(props: { user: User, setUser: Function, programIndex: number, degreeIndex: number, degreeConfiguration: DegreeConfiguration })
-function Requirements(props: { conc: DegreeConcentration })
+function Requirements(props: { conc: DegreeConcentration | null })
{
// const [edit, setEdit] = useState(false);
// const updateEdit = () => {
// setEdit(!edit);
// };
- return(
+ return(
@@ -193,10 +186,14 @@ function Requirements(props: { conc: DegreeConcentration })
-
- {/* */}
-
-
+ {props.conc == null ? (
+
+ ) : (
+
+
+
+ )
+ }
);
}
From d2eb41e44e8c08d88146811851aee773c796aaff Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Tue, 11 Mar 2025 12:23:26 -0700
Subject: [PATCH 19/38] good start
---
frontend/src/app/majors/page.tsx | 32 +++++-----
frontend/src/database/data-courses.ts | 63 ++++++++++---------
frontend/src/database/data-studentcourses.ts | 14 -----
.../src/database/programs/concs/concs-cpsc.ts | 3 +-
.../src/database/programs/concs/concs-econ.ts | 3 +-
5 files changed, 55 insertions(+), 60 deletions(-)
delete mode 100644 frontend/src/database/data-studentcourses.ts
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index cbd9f16..9131031 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -13,30 +13,34 @@ import Requirements from "./requirements/Requirements";
function Majors()
{
const { user } = useAuth();
- const [index, setIndex] = useState({ conc: 0, deg: 0, prog: 0 });
-
- useEffect(() => {
+
+ const [index, setIndex] = useState(null);
+
+ useEffect(() => {
if(typeof window !== "undefined"){
const storedIndex = sessionStorage.getItem("majorsIndex");
- if(storedIndex){
- setIndex(JSON.parse(storedIndex));
- }
+ setIndex(storedIndex ? JSON.parse(storedIndex) : { conc: 0, deg: 0, prog: 0 });
}
}, []);
useEffect(() => {
- if(typeof window !== "undefined"){
+ if(typeof window !== "undefined" && index !== null){
sessionStorage.setItem("majorsIndex", JSON.stringify(index));
}
}, [index]);
- const updateIndex = (newIndex: MajorsIndex) => {
- if(newIndex.conc === -1){
- setIndex({ ...newIndex, deg: 0, conc: index.conc === -1 ? 0 : -1 });
- return;
- }
- setIndex({ ...newIndex, prog: (newIndex.prog + user.FYP.programs.length) % user.FYP.programs.length });
- };
+ const updateIndex = (newIndex: MajorsIndex) => {
+ setIndex((prev) => ({
+ ...prev!,
+ ...newIndex,
+ prog: newIndex.prog !== undefined
+ ? (newIndex.prog + user.FYP.programs.length) % user.FYP.programs.length
+ : prev!.prog,
+ conc: newIndex.conc === -1 ? (prev!.conc === -1 ? 0 : -1) : newIndex.conc,
+ }));
+ };
+
+ if(index === null) return null;
return(
diff --git a/frontend/src/database/data-courses.ts b/frontend/src/database/data-courses.ts
index 5939794..d2deb8d 100644
--- a/frontend/src/database/data-courses.ts
+++ b/frontend/src/database/data-courses.ts
@@ -1,24 +1,25 @@
-import { Course } from "@/types/type-user"
+import { Course, StudentCourse } from "@/types/type-user"
+
+// COURSES
// HSAR PROGRAM
-export const HSAR_401: Course = { codes: ["HSAR 401"], title: "Critical Approaches To Art History", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const HSAR_401: Course = { codes: ["HSAR 401"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
// PLSC PROGRAM
export const PLSC_474: Course = { codes: ["PSLC 474"], title: "", credit: 1, dist: ["So"], seasons: ["Spring"]}
export const PLSC_490: Course = { codes: ["PSLC 490"], title: "", credit: 1, dist: ["So"], seasons: ["Fall", "Spring"]}
export const PLSC_493: Course = { codes: ["PSLC 493"], title: "", credit: 1, dist: ["So"], seasons: ["Fall", "Spring"]}
-
// CPSC PROGRAM
-export const CPSC_201: Course = { codes: ["CPSC 201"], title: "Introduction To Computer Science", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_202: Course = { codes: ["CPSC 202"], title: "Math Tools For Computer Scientists", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const MATH_244: Course = { codes: ["MATH 244"], title: "Discrete Mathematics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_223: Course = { codes: ["CPSC 223"], title: "Data Structures And Programming Techniques", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_323: Course = { codes: ["CPSC 323"], title: "Introduction To Systems Programming", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_365: Course = { codes: ["CPSC 365"], title: "Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_366: Course = { codes: ["CPSC 366"], title: "Intensive Algorithms", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const CPSC_490: Course = { codes: ["CPSC 490"], title: "Senior Project", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_201: Course = { codes: ["CPSC 201"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_202: Course = { codes: ["CPSC 202"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const MATH_244: Course = { codes: ["MATH 244"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_223: Course = { codes: ["CPSC 223"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_323: Course = { codes: ["CPSC 323"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_365: Course = { codes: ["CPSC 365"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_366: Course = { codes: ["CPSC 366"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_490: Course = { codes: ["CPSC 490"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
// ECON PROGRAM
export const MATH_110: Course = { codes: ["MATH 110"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
@@ -29,20 +30,26 @@ export const MATH_116: Course = { codes: ["MATH 116"], title: "", credit: 1, dis
export const ENAS_151: Course = { codes: ["ENAS 151"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const MATH_118: Course = { codes: ["MATH 118"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const MATH_120: Course = { codes: ["MATH 120"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-export const ECON_108: Course = { codes: ["ECON 108"], title: "Introductory Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_110: Course = { codes: ["ECON 110"], title: "Introductory Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_115: Course = { codes: ["ECON 115"], title: "Introductory Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-export const ECON_111: Course = { codes: ["ECON 111"], title: "Introductory Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_116: Course = { codes: ["ECON 116"], title: "Introductory Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-export const ECON_121: Course = { codes: ["ECON 121"], title: "Intermediate Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_125: Course = { codes: ["ECON 125"], title: "Intermediate Microeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-export const ECON_122: Course = { codes: ["ECON 122"], title: "Intermediate Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_126: Course = { codes: ["ECON 126"], title: "Intermediate Macroeconomics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-
-export const ECON_117: Course = { codes: ["ECON 117"], title: "Econometrics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_123: Course = { codes: ["ECON 123"], title: "Econometrics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
-export const ECON_136: Course = { codes: ["ECON 136"], title: "Econometrics", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_108: Course = { codes: ["ECON 108"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_110: Course = { codes: ["ECON 110"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_115: Course = { codes: ["ECON 115"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_111: Course = { codes: ["ECON 111"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_116: Course = { codes: ["ECON 116"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_121: Course = { codes: ["ECON 121"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_125: Course = { codes: ["ECON 125"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_122: Course = { codes: ["ECON 122"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_126: Course = { codes: ["ECON 126"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_117: Course = { codes: ["ECON 117"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_123: Course = { codes: ["ECON 123"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const ECON_136: Course = { codes: ["ECON 136"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+
+// STUDENT COURSES
+
+// CPSC COURSES
+export const SC_CPSC_201: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_201 }
+export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
+export const SC_CPSC_223: StudentCourse = { term: 202501, status: "DA", result: "GRADE_PASS", course: CPSC_223 }
+export const SC_CPSC_323: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_323 }
+
+// ECON COURSES
+export const SC_ECON_110: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: ECON_110 }
diff --git a/frontend/src/database/data-studentcourses.ts b/frontend/src/database/data-studentcourses.ts
deleted file mode 100644
index 54120ca..0000000
--- a/frontend/src/database/data-studentcourses.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-
-import { StudentCourse } from "@/types/type-user"
-import { CPSC_201, CPSC_202, CPSC_223, CPSC_323, ECON_110 } from "./data-courses"
-
-// CPSC COURSES
-export const SC_CPSC_201: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_201 }
-export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
-export const SC_CPSC_223: StudentCourse = { term: 202501, status: "DA", result: "GRADE_PASS", course: CPSC_223 }
-export const SC_CPSC_323: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_323 }
-
-// ECON COURSES
-export const SC_ECON_110: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: ECON_110 }
-
-
diff --git a/frontend/src/database/programs/concs/concs-cpsc.ts b/frontend/src/database/programs/concs/concs-cpsc.ts
index 45651e9..97f3144 100644
--- a/frontend/src/database/programs/concs/concs-cpsc.ts
+++ b/frontend/src/database/programs/concs/concs-cpsc.ts
@@ -1,8 +1,7 @@
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
-import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490 } from "../../data-courses";
-import { SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "../../data-studentcourses";
+import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490, SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "../../data-courses";
// CORE
diff --git a/frontend/src/database/programs/concs/concs-econ.ts b/frontend/src/database/programs/concs/concs-econ.ts
index 7f5df20..f7e89fd 100644
--- a/frontend/src/database/programs/concs/concs-econ.ts
+++ b/frontend/src/database/programs/concs/concs-econ.ts
@@ -1,8 +1,7 @@
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
-import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151 } from "./../../data-courses";
-import { SC_ECON_110 } from "./../../data-studentcourses";
+import { ECON_108, ECON_110, ECON_111, ECON_115, ECON_116, ECON_117, ECON_121, ECON_122, ECON_123, ECON_125, ECON_126, ECON_136, MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151, SC_ECON_110 } from "./../../data-courses";
// INTRO
From 711a1100221a030d7c3be44c6267322947f529e1 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Tue, 11 Mar 2025 13:40:53 -0700
Subject: [PATCH 20/38] user status (meh) and editing
---
frontend/src/app/majors/overhead/Overhead.tsx | 8 +--
.../src/app/majors/overhead/pinned/Pinned.tsx | 37 ++---------
frontend/src/app/majors/page.tsx | 11 ++--
.../requirements/Requirements.module.css | 54 +++++++---------
.../app/majors/requirements/Requirements.tsx | 64 +++++++++----------
frontend/src/database/data-courses.ts | 6 +-
frontend/src/database/data-user.ts | 4 +-
.../src/database/programs/concs/concs-cpsc.ts | 32 +++++-----
.../src/database/programs/concs/concs-econ.ts | 1 +
.../src/database/programs/concs/concs-hist.ts | 2 +
.../src/database/programs/concs/concs-plsc.ts | 2 +
frontend/src/types/type-program.ts | 7 +-
frontend/src/types/type-user.ts | 11 +++-
13 files changed, 109 insertions(+), 130 deletions(-)
diff --git a/frontend/src/app/majors/overhead/Overhead.tsx b/frontend/src/app/majors/overhead/Overhead.tsx
index 8845215..2749dc5 100644
--- a/frontend/src/app/majors/overhead/Overhead.tsx
+++ b/frontend/src/app/majors/overhead/Overhead.tsx
@@ -2,17 +2,17 @@
import Style from "./Overhead.module.css";
import { User } from "@/types/type-user";
-import MajorSearchBar from "./major-search/MajorSearch";
+// import MajorSearchBar from "./major-search/MajorSearch";
import Pinned from "./pinned/Pinned";
-function Overhead(props: { user: User, setProgramIndex: Function }) {
+function Overhead(props: { user: User, setIndex: Function }) {
return (
);
}
diff --git a/frontend/src/app/majors/overhead/pinned/Pinned.tsx b/frontend/src/app/majors/overhead/pinned/Pinned.tsx
index 5ee46c5..08c163c 100644
--- a/frontend/src/app/majors/overhead/pinned/Pinned.tsx
+++ b/frontend/src/app/majors/overhead/pinned/Pinned.tsx
@@ -1,45 +1,22 @@
import Style from "./Pinned.module.css";
-import { User } from "@/types/type-user";
-import { StudentDegree } from "@/types/type-program";
-import { ALL_PROGRAM_METADATAS } from "@/database/programs/metas/meta-econ";
+import { User, StudentConc } from "@/types/type-user";
-function DegreeIcon(props: { studentDegree: StudentDegree, setProgramIndex: Function }) {
- const mark = (status: string) => {
- let mark = "";
- switch (status) {
- case "DA":
- mark = "✓";
- break;
- case "ADD":
- mark = "⚠";
- break;
- case "PIN":
- mark = "📌";
- break;
- default:
- mark = "";
- }
- return (
-
- {mark}
-
- );
- };
+function ConcIcon(props: { user: User, setIndex: Function, studentConc: StudentConc }) {
return(
- props.setProgramIndex(props.studentDegree.programIndex)}>
- {mark(props.studentDegree.status)}{ALL_PROGRAM_METADATAS[props.studentDegree.programIndex][0].abbr}
+
props.setIndex(props.studentConc.majors_index)}>
+ 📌{props.user.FYP.prog_list[props.studentConc.majors_index.prog].prog_data.prog_abbr}
);
}
-function Pinned(props: { user: User, setProgramIndex: Function }) {
+function Pinned(props: { user: User, setIndex: Function }) {
return (
- {props.user.FYP.degreeDeclarations.map((studentDegree, index) => (
-
+ {props.user.FYP.decl_list.map((studentConc, index) => (
+
))}
);
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 9131031..415a612 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -6,7 +6,7 @@ import { MajorsIndex } from "@/types/type-program";
import Style from "./Majors.module.css";
import NavBar from "@/components/navbar/NavBar";
-// import Overhead from "./overhead/Overhead";
+import Overhead from "./overhead/Overhead";
import Metadata from "./metadata/Metadata";
import Requirements from "./requirements/Requirements";
@@ -34,7 +34,7 @@ function Majors()
...prev!,
...newIndex,
prog: newIndex.prog !== undefined
- ? (newIndex.prog + user.FYP.programs.length) % user.FYP.programs.length
+ ? (newIndex.prog + user.FYP.prog_list.length) % user.FYP.prog_list.length
: prev!.prog,
conc: newIndex.conc === -1 ? (prev!.conc === -1 ? 0 : -1) : newIndex.conc,
}));
@@ -44,11 +44,12 @@ function Majors()
return(
-
updateIndex({ ...index, conc: -1 })}/>}/>
+ }/>
-
+ updateIndex({ ...index, conc: -1 })}/>
+
-
+
);
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index ab5aa0b..f7fcb74 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -11,18 +11,9 @@
.RequirementsContainer {
/* border: 1px solid green; */
-
margin-top: 37px;
-
width: 600px;
height: 650px;
-
- /* min-width: 390px; */
-
- /* background-color: white; */
- /* padding: 20px; */
- /* border-radius: 25px; */
- /* box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5); */
}
.ReqsList {
@@ -33,7 +24,8 @@
scrollbar-width: thin;
overflow-y: scroll;
padding-right: 7px;
- overflow-x: hidden; */
+ overflow-x: hidden;
+*/
}
.ReqHeader {
@@ -55,10 +47,8 @@
font-weight: 500;
}
-
.EmptyCourse {
border-radius: 15px;
- /* padding: 2px 2px; e7e7e7c3 */
background-color: #F5F5F5;
transition: filter 0.4s ease;
width: 24px; /* Adjust width to match CourseIcon */
@@ -81,39 +71,21 @@
font-size: 14px;
}
-
-.ButtonRow {
- display: flex;
- flex-direction: row;
-}
-
.resetButton {
margin-right: 10px; /* Add margin to the right of the reset button */
opacity: 0; /* Make it invisible */
pointer-events: none; /* Make it unclickable */
}
-.editButton {
- margin-right: 0; /* Remove margin for the last child */
-}
-
.resetButton.visible {
opacity: 1; /* Make it visible */
pointer-events: auto; /* Make it clickable */
}
-.resetButton:hover, .editButton:hover {
- color: #666; /* Slightly lighter color on hover */
- cursor: pointer; /* Show pointer cursor on hover */
-}
-
.resetButton:active, .editButton:active {
color: #333; /* Darker color on click */
}
-
-
-
.ButtonRow {
display: flex;
gap: 6px;
@@ -134,4 +106,24 @@
.SubreqButton.Selected {
background-color: rgb(100, 178, 238);
-}
\ No newline at end of file
+}
+
+
+
+.RequirementsContainerHeader {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ font-size: 30px;
+ padding: 2px 8px;
+}
+
+.GoldBackground {
+ background-color: rgba(255, 215, 0, 0.3); /* Gold with 40% opacity */
+ border-radius: 2px;
+}
+
+.EditButton:hover {
+ cursor: pointer; /* Show pointer cursor on hover */
+}
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 9337a83..295c9ff 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -7,11 +7,13 @@ import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentrat
import { CourseIcon } from "@/components/course-icon/CourseIcon";
-function RenderSubrequirementCourse(props: { course: Course | null, subreq: ConcentrationSubrequirement }){
+function RenderSubrequirementCourse(props: { edit?: boolean, course: Course | null, subreq: ConcentrationSubrequirement }){
if(props.course === null){
return(
-
+
+ {props.edit ? (
e
) : (
)}
+
);
}
@@ -26,7 +28,7 @@ function RenderSubrequirementCourse(props: { course: Course | null, subreq: Conc
)
}
-function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement }) {
+function RenderSubrequirement(props: { edit: boolean, subreq: ConcentrationSubrequirement }) {
const [showAll, setShowAll] = useState(false);
// Separate null and non-null courses
@@ -56,7 +58,11 @@ function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement }) {
{displayedCourses.map((course, index) => (
-
+
))}
{/* Toggle Button to Expand / Collapse */}
@@ -70,7 +76,7 @@ function RenderSubrequirement(props: { subreq: ConcentrationSubrequirement }) {
);
}
-function RenderRequirement(props: { req: ConcentrationRequirement }){
+function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement }){
// const { user, setUser } = useAuth();
// const { req, programIndex, degreeIndex } = props;
@@ -144,23 +150,22 @@ function RenderRequirement(props: { req: ConcentrationRequirement }){
{subreqs_required_count
? subreqs_list.slice(0, subreqs_required_count).map((subreq, index) => (
-
+
))
: subreqs_list.map((subreq, index) => (
-
+
))}
);
}
-function RequirementsContent(props: { conc: DegreeConcentration })
+function RequirementsContent(props: { edit: boolean, conc: DegreeConcentration })
{
-
return(
{props.conc.conc_reqs.map((req, index) => (
-
+
))}
);
@@ -168,32 +173,27 @@ function RequirementsContent(props: { conc: DegreeConcentration })
function Requirements(props: { conc: DegreeConcentration | null })
{
- // const [edit, setEdit] = useState(false);
- // const updateEdit = () => {
- // setEdit(!edit);
- // };
+ const [edit, setEdit] = useState(false);
- return(
-
-
-
+ if(props.conc == null){
+ return(
+
+
Requirements
-
+ )
+ }
+
+ return(
+
+
+
Requirements
+ {props.conc.user_status == 1 ? (
setEdit(!edit)}>⚙
) : (
)}
- {props.conc == null ? (
-
- ) : (
-
-
-
- )
- }
+
+
+
);
}
diff --git a/frontend/src/database/data-courses.ts b/frontend/src/database/data-courses.ts
index d2deb8d..49f9010 100644
--- a/frontend/src/database/data-courses.ts
+++ b/frontend/src/database/data-courses.ts
@@ -19,6 +19,7 @@ export const CPSC_223: Course = { codes: ["CPSC 223"], title: "", credit: 1, dis
export const CPSC_323: Course = { codes: ["CPSC 323"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const CPSC_365: Course = { codes: ["CPSC 365"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const CPSC_366: Course = { codes: ["CPSC 366"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
+export const CPSC_381: Course = { codes: ["CPSC 381"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
export const CPSC_490: Course = { codes: ["CPSC 490"], title: "", credit: 1, dist: ["QR"], seasons: ["Fall", "Spring"] }
// ECON PROGRAM
@@ -47,9 +48,10 @@ export const ECON_136: Course = { codes: ["ECON 136"], title: "", credit: 1, dis
// CPSC COURSES
export const SC_CPSC_201: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_201 }
-export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
+// export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
export const SC_CPSC_223: StudentCourse = { term: 202501, status: "DA", result: "GRADE_PASS", course: CPSC_223 }
-export const SC_CPSC_323: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_323 }
+export const SC_CPSC_323: StudentCourse = { term: 202503, status: "DA", result: "GRADE_PASS", course: CPSC_323 }
+export const SC_CPSC_381: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_381 }
// ECON COURSES
export const SC_ECON_110: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: ECON_110 }
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index bf2f7f3..6c6438a 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -15,8 +15,8 @@ export const Ryan: User = {
senior: [0, 202703, 202801],
},
languagePlacement: { language: "Spanish", level: 5 },
- programs: [PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC],
- declarations: [],
+ prog_list: [PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC],
+ decl_list: [{ user_status: 1, majors_index: { conc: 0, deg: 0, prog: 0 } }],
}
}
diff --git a/frontend/src/database/programs/concs/concs-cpsc.ts b/frontend/src/database/programs/concs/concs-cpsc.ts
index 97f3144..6b025d6 100644
--- a/frontend/src/database/programs/concs/concs-cpsc.ts
+++ b/frontend/src/database/programs/concs/concs-cpsc.ts
@@ -1,21 +1,21 @@
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
-import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_490, SC_CPSC_201, SC_CPSC_223, SC_CPSC_323 } from "../../data-courses";
+import { CPSC_201, CPSC_202, MATH_244, CPSC_223, CPSC_323, CPSC_365, CPSC_366, CPSC_381, CPSC_490, SC_CPSC_201, SC_CPSC_223, SC_CPSC_323, SC_CPSC_381 } from "../../data-courses";
// CORE
-const CORE_SUB_INTRO: ConcentrationSubrequirement = {
+const CORE_INTRO: ConcentrationSubrequirement = {
subreq_name: "INTRO",
subreq_desc: "",
courses_required: 1,
courses_options: [CPSC_201],
courses_elective_range: null,
courses_any_bool: false,
- student_courses_satisfying: [SC_CPSC_201],
+ student_courses_satisfying: [],
}
-const CORE_SUB_MATH: ConcentrationSubrequirement = {
+const CORE_MATH: ConcentrationSubrequirement = {
subreq_name: "DISCRETE MATH",
subreq_desc: "",
courses_required: 1,
@@ -25,7 +25,7 @@ const CORE_SUB_MATH: ConcentrationSubrequirement = {
student_courses_satisfying: [],
}
-const CORE_SUB_DATA: ConcentrationSubrequirement = {
+const CORE_DATA: ConcentrationSubrequirement = {
subreq_name: "DATA STRUCTURES",
subreq_desc: "",
courses_required: 1,
@@ -35,7 +35,7 @@ const CORE_SUB_DATA: ConcentrationSubrequirement = {
student_courses_satisfying: [SC_CPSC_223],
}
-const CORE_SUB_SYSTEMS: ConcentrationSubrequirement = {
+const CORE_SYS: ConcentrationSubrequirement = {
subreq_name: "SYSTEMS",
subreq_desc: "",
courses_required: 1,
@@ -45,7 +45,7 @@ const CORE_SUB_SYSTEMS: ConcentrationSubrequirement = {
student_courses_satisfying: [SC_CPSC_323],
}
-const CORE_SUB_ALGOS: ConcentrationSubrequirement = {
+const CORE_ALGO: ConcentrationSubrequirement = {
subreq_name: "ALGORITHMS",
subreq_desc: "",
courses_required: 1,
@@ -59,8 +59,8 @@ const CPSC_CORE: ConcentrationRequirement = {
req_name: "CORE",
req_desc: "",
courses_required_count: 5,
- courses_satisfied_count: 3,
- subreqs_list: [CORE_SUB_INTRO, CORE_SUB_MATH, CORE_SUB_DATA, CORE_SUB_SYSTEMS, CORE_SUB_ALGOS]
+ courses_satisfied_count: 2,
+ subreqs_list: [CORE_INTRO, CORE_MATH, CORE_DATA, CORE_SYS, CORE_ALGO]
}
// ELECTIVE
@@ -69,20 +69,20 @@ const ELEC_MULT_BA: ConcentrationSubrequirement = {
subreq_name: "",
subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
courses_required: 3,
- courses_options: [null, null, null],
+ courses_options: [CPSC_381, null, null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: false,
- student_courses_satisfying: []
+ student_courses_satisfying: [SC_CPSC_381]
}
const ELEC_MULT_BS: ConcentrationSubrequirement = {
subreq_name: "",
subreq_desc: "Intermediate or advanced CPSC courses, traditionally numbered 300+.",
courses_required: 5,
- courses_options: [null, null, null, null, null],
+ courses_options: [CPSC_381, null, null, null, null],
courses_elective_range: { dept: "CPSC", min_code: 300, max_code: 999 },
courses_any_bool: false,
- student_courses_satisfying: []
+ student_courses_satisfying: [SC_CPSC_381]
}
const ELEC_SUB: ConcentrationSubrequirement = {
@@ -99,7 +99,7 @@ const CPSC_BA_ELEC: ConcentrationRequirement = {
req_name: "ELECTIVE",
req_desc: "",
courses_required_count: 4,
- courses_satisfied_count: 0,
+ courses_satisfied_count: 1,
subreqs_list: [ELEC_SUB, ELEC_MULT_BA]
}
@@ -107,7 +107,7 @@ const CPSC_BS_ELEC: ConcentrationRequirement = {
req_name: "ELECTIVE",
req_desc: "",
courses_required_count: 6,
- courses_satisfied_count: 0,
+ courses_satisfied_count: 1,
subreqs_list: [ELEC_SUB, ELEC_MULT_BS]
}
@@ -134,12 +134,14 @@ const CPSC_SENIOR: ConcentrationRequirement = {
// EXPORT
export const CONC_CPSC_BA_I: DegreeConcentration = {
+ user_status: 1,
conc_name: "",
conc_desc: "",
conc_reqs: [CPSC_CORE, CPSC_BA_ELEC, CPSC_SENIOR]
}
export const CONC_CPSC_BS_I: DegreeConcentration = {
+ user_status: 0,
conc_name: "",
conc_desc: "",
conc_reqs: [CPSC_CORE, CPSC_BS_ELEC, CPSC_SENIOR]
diff --git a/frontend/src/database/programs/concs/concs-econ.ts b/frontend/src/database/programs/concs/concs-econ.ts
index f7e89fd..ec1ca3e 100644
--- a/frontend/src/database/programs/concs/concs-econ.ts
+++ b/frontend/src/database/programs/concs/concs-econ.ts
@@ -136,6 +136,7 @@ const ECON_SEN: ConcentrationRequirement = {
// // FINAL
export const CONC_ECON_BA_I: DegreeConcentration = {
+ user_status: 0,
conc_name: "",
conc_desc: "",
conc_reqs: [ECON_INTRO, ECON_CORE, ECON_ELECTIVE, ECON_SEN]
diff --git a/frontend/src/database/programs/concs/concs-hist.ts b/frontend/src/database/programs/concs/concs-hist.ts
index 1cfa69a..218b063 100644
--- a/frontend/src/database/programs/concs/concs-hist.ts
+++ b/frontend/src/database/programs/concs/concs-hist.ts
@@ -221,12 +221,14 @@ const HIST_SEN: ConcentrationRequirement = {
// EXPORT
export const CONC_HIST_BA_GLOB: DegreeConcentration = {
+ user_status: 0,
conc_name: "GLOBALIST",
conc_desc: "",
conc_reqs: [HIST_PRE, HIST_GLOB_CORE, HIST_SEM, HIST_GLOB_ELEC, HIST_SEN]
}
export const CONC_HIST_BA_SPEC: DegreeConcentration = {
+ user_status: 0,
conc_name: "SPECIALIST",
conc_desc: "",
conc_reqs: [HIST_PRE, HIST_SPEC_CORE, HIST_SEM, HIST_SPEC_ELEC, HIST_SEN]
diff --git a/frontend/src/database/programs/concs/concs-plsc.ts b/frontend/src/database/programs/concs/concs-plsc.ts
index 422947f..06c0054 100644
--- a/frontend/src/database/programs/concs/concs-plsc.ts
+++ b/frontend/src/database/programs/concs/concs-plsc.ts
@@ -208,12 +208,14 @@ const PLSC_SEN_INTE: ConcentrationRequirement = {
// EXPORT
export const CONC_PLSC_BA_STAN: DegreeConcentration = {
+ user_status: 0,
conc_name: "STANDARD",
conc_desc: "",
conc_reqs: [PLSC_INTRO, PLSC_CORE_STAN, PLSC_SUB, PLSC_SEMINAR, PLSC_SEN_STAN]
}
export const CONC_PLSC_BA_INTE: DegreeConcentration = {
+ user_status: 0,
conc_name: "INTENSIVE",
conc_desc: "",
conc_reqs: [PLSC_INTRO, PLSC_CORE_INTE, PLSC_SUB, PLSC_SEMINAR, PLSC_SEN_INTE]
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index e930036..018981d 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -1,12 +1,6 @@
import { Course, StudentCourse } from "./type-user";
-export interface StudentDegree {
- status: string; // DA | ADD | PIN
- programIndex: number;
- degreeIndex: number;
-}
-
export interface ElectiveRange {
dept: string;
min_code: number;
@@ -42,6 +36,7 @@ export interface ConcentrationRequirement {
}
export interface DegreeConcentration {
+ user_status: number;
conc_name: string;
conc_desc: string;
conc_reqs: ConcentrationRequirement[];
diff --git a/frontend/src/types/type-user.ts b/frontend/src/types/type-user.ts
index 85f4a23..3700ec7 100644
--- a/frontend/src/types/type-user.ts
+++ b/frontend/src/types/type-user.ts
@@ -1,5 +1,5 @@
-import { Program, StudentDegree } from "./type-program";
+import { MajorsIndex, Program } from "./type-program";
export interface LanguagePlacement {
language: string;
@@ -38,12 +38,17 @@ export interface StudentTermArrangement {
senior: number[];
}
+export interface StudentConc {
+ user_status: number;
+ majors_index: MajorsIndex;
+}
+
export interface FYP {
languagePlacement: LanguagePlacement;
studentCourses: StudentCourse[];
studentTermArrangement: StudentTermArrangement;
- programs: Program[];
- declarations: StudentDegree[];
+ prog_list: Program[];
+ decl_list: StudentConc[];
}
export interface User {
From 05d88bff1c0bec283aede37693dcd1de1ba587d5 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Tue, 11 Mar 2025 17:26:54 -0700
Subject: [PATCH 21/38] local majors icons
---
.../courses/years/semester/SemesterBox.tsx | 2 +-
.../years/semester/course/CourseBox.tsx | 2 +-
.../course-icon/MajorsCourseIcon.module.css | 24 +++++
.../majors/course-icon/MajorsCourseIcon.tsx | 88 +++++++++++++++++++
frontend/src/app/majors/page.tsx | 2 +-
.../app/majors/requirements/Requirements.tsx | 7 +-
.../src/components/course-icon/CourseIcon.tsx | 2 +-
frontend/src/database/data-courses.ts | 2 +-
.../src/database/programs/concs/concs-cpsc.ts | 2 +-
frontend/src/types/type-program.ts | 2 +
.../CourseDisplay.module.css | 0
.../{ => course-display}/CourseDisplay.tsx | 0
.../src/utils/preprocessing/BackendAdapt.ts | 1 +
13 files changed, 124 insertions(+), 10 deletions(-)
create mode 100644 frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
create mode 100644 frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
rename frontend/src/utils/{ => course-display}/CourseDisplay.module.css (100%)
rename frontend/src/utils/{ => course-display}/CourseDisplay.tsx (100%)
create mode 100644 frontend/src/utils/preprocessing/BackendAdapt.ts
diff --git a/frontend/src/app/courses/years/semester/SemesterBox.tsx b/frontend/src/app/courses/years/semester/SemesterBox.tsx
index 5cc3625..6823900 100644
--- a/frontend/src/app/courses/years/semester/SemesterBox.tsx
+++ b/frontend/src/app/courses/years/semester/SemesterBox.tsx
@@ -3,7 +3,7 @@ import React, {useState, useEffect} from "react";
import Style from "./SemesterBox.module.css"
import { StudentSemester, User } from "@/types/type-user";
-import { TransformTermNumber, IsTermActive } from "@/utils/CourseDisplay";
+import { TransformTermNumber, IsTermActive } from "@/utils/course-display/CourseDisplay";
import CourseBox from "./course/CourseBox";
import AddCourseButton from "./add-course/AddCourseButton";
diff --git a/frontend/src/app/courses/years/semester/course/CourseBox.tsx b/frontend/src/app/courses/years/semester/course/CourseBox.tsx
index 7c460ec..336dd46 100644
--- a/frontend/src/app/courses/years/semester/course/CourseBox.tsx
+++ b/frontend/src/app/courses/years/semester/course/CourseBox.tsx
@@ -2,7 +2,7 @@
import Style from "./CourseBox.module.css";
import { User, StudentCourse } from "@/types/type-user";
-import { RenderMark, SeasonIcon, GetCourseColor, IsTermActive } from "./../../../../../utils/CourseDisplay";
+import { RenderMark, SeasonIcon, GetCourseColor, IsTermActive } from "../../../../../utils/course-display/CourseDisplay";
import DistributionCircle from "@/components/distribution-circle/DistributionsCircle";
// import { useModal } from "../../../hooks/modalContext";
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
new file mode 100644
index 0000000..a4dac89
--- /dev/null
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
@@ -0,0 +1,24 @@
+
+.CourseIcon {
+ display: flex;
+ flex-direction: row;
+
+ align-items: center;
+
+ border-radius: 15px;
+
+ width: max-content;
+ padding: 2px 4px;
+ min-height: 18px;
+
+ font-size: 14px;
+ font-weight: bold;
+
+ background-color: #F5F5F5;
+ transition: filter 0.4s ease;
+}
+
+.CourseIcon:hover {
+ cursor: pointer;
+ filter: brightness(95%);
+}
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
new file mode 100644
index 0000000..ecb401c
--- /dev/null
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -0,0 +1,88 @@
+
+import React from "react";
+import Style from "./MajorsCourseIcon.module.css"
+
+import { StudentCourse, Course } from "@/types/type-user";
+import { RenderMark, GetCourseColor } from "@/utils/course-display/CourseDisplay";
+
+import DistributionCircle from "@/components/distribution-circle/DistributionsCircle";
+
+
+function CourseSeasonIcon(props: { seasons: Array }) {
+ const seasonImageMap: { [key: string]: string } = {
+ "Fall": "./fall.svg",
+ "Spring": "./spring.svg",
+ };
+
+ return (
+
+ {props.seasons.map((szn, index) => (
+
0 ? "-7.5px" : 0 }}>
+ {seasonImageMap[szn] && (
+
+ )}
+
+ ))}
+
+ );
+}
+
+
+function DistCircDiv(props: { dist: string[] })
+{
+ if(!Array.isArray(props.dist) || props.dist.length === 0){
+ return(
+
+
+
+ );
+ }
+
+ return(
+
+
+
+ );
+}
+
+
+export function StudentCourseIcon(props: { studentCourse: StudentCourse, utilityButton?: React.ReactNode }) {
+
+ const dist = props.studentCourse.course.dist || [];
+
+ // style={{ backgroundColor: GetCourseColor(props.studentCourse.term) }}
+
+ return (
+
+ {props.utilityButton && props.utilityButton}
+ {props.studentCourse.status === ""
+ ?
+ :
+ }
+ {props.studentCourse.course.codes[0]}
+ {/* */}
+
+ );
+}
+
+
+export function CourseIcon(props: { course: Course, studentCourse?: StudentCourse }){
+
+ if(props.studentCourse){
+ return(
+
+ );
+ }
+
+ return(
+
+
+ {props.course.codes[0]}
+
+
+ );
+}
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 415a612..487f486 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -49,7 +49,7 @@ function Majors()
updateIndex({ ...index, conc: -1 })}/>
-
+
);
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 295c9ff..e323fcf 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -4,8 +4,7 @@ import Style from "./Requirements.module.css";
import { Course } from "@/types/type-user";
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
-import { CourseIcon } from "@/components/course-icon/CourseIcon";
-
+import { CourseIcon } from "../course-icon/MajorsCourseIcon";
function RenderSubrequirementCourse(props: { edit?: boolean, course: Course | null, subreq: ConcentrationSubrequirement }){
@@ -160,7 +159,7 @@ function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement
);
}
-function RequirementsContent(props: { edit: boolean, conc: DegreeConcentration })
+function RequirementsList(props: { edit: boolean, conc: DegreeConcentration })
{
return(
@@ -192,7 +191,7 @@ function Requirements(props: { conc: DegreeConcentration | null })
{props.conc.user_status == 1 ? (
setEdit(!edit)}>⚙
) : (
)}
-
+
);
diff --git a/frontend/src/components/course-icon/CourseIcon.tsx b/frontend/src/components/course-icon/CourseIcon.tsx
index 31eb639..fd16aae 100644
--- a/frontend/src/components/course-icon/CourseIcon.tsx
+++ b/frontend/src/components/course-icon/CourseIcon.tsx
@@ -3,7 +3,7 @@ import React from "react";
import styles from "./CourseIcon.module.css";
import { StudentCourse, Course } from "@/types/type-user";
-import { RenderMark, GetCourseColor } from "@/utils/CourseDisplay";
+import { RenderMark, GetCourseColor } from "@/utils/course-display/CourseDisplay";
import DistributionCircle from "../distribution-circle/DistributionsCircle";
diff --git a/frontend/src/database/data-courses.ts b/frontend/src/database/data-courses.ts
index 49f9010..e16787c 100644
--- a/frontend/src/database/data-courses.ts
+++ b/frontend/src/database/data-courses.ts
@@ -51,7 +51,7 @@ export const SC_CPSC_201: StudentCourse = { term: 202403, status: "DA", result:
// export const SC_CPSC_202: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: CPSC_202 }
export const SC_CPSC_223: StudentCourse = { term: 202501, status: "DA", result: "GRADE_PASS", course: CPSC_223 }
export const SC_CPSC_323: StudentCourse = { term: 202503, status: "DA", result: "GRADE_PASS", course: CPSC_323 }
-export const SC_CPSC_381: StudentCourse = { term: 202503, status: "MA", result: "IP", course: CPSC_381 }
+export const SC_CPSC_381: StudentCourse = { term: 202503, status: "DA", result: "GRADE_PASS", course: CPSC_381 }
// ECON COURSES
export const SC_ECON_110: StudentCourse = { term: 202403, status: "DA", result: "GRADE_PASS", course: ECON_110 }
diff --git a/frontend/src/database/programs/concs/concs-cpsc.ts b/frontend/src/database/programs/concs/concs-cpsc.ts
index 6b025d6..7095d2e 100644
--- a/frontend/src/database/programs/concs/concs-cpsc.ts
+++ b/frontend/src/database/programs/concs/concs-cpsc.ts
@@ -145,4 +145,4 @@ export const CONC_CPSC_BS_I: DegreeConcentration = {
conc_name: "",
conc_desc: "",
conc_reqs: [CPSC_CORE, CPSC_BS_ELEC, CPSC_SENIOR]
-}
\ No newline at end of file
+}
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 018981d..62a1b5e 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -16,7 +16,9 @@ export interface ConcentrationSubrequirement {
courses_required: number;
courses_options: (Course | null)[];
courses_elective_range: SubreqElectiveRange;
+
courses_any_bool: boolean;
+ flags?: string[];
student_courses_satisfying: StudentCourse[];
}
diff --git a/frontend/src/utils/CourseDisplay.module.css b/frontend/src/utils/course-display/CourseDisplay.module.css
similarity index 100%
rename from frontend/src/utils/CourseDisplay.module.css
rename to frontend/src/utils/course-display/CourseDisplay.module.css
diff --git a/frontend/src/utils/CourseDisplay.tsx b/frontend/src/utils/course-display/CourseDisplay.tsx
similarity index 100%
rename from frontend/src/utils/CourseDisplay.tsx
rename to frontend/src/utils/course-display/CourseDisplay.tsx
diff --git a/frontend/src/utils/preprocessing/BackendAdapt.ts b/frontend/src/utils/preprocessing/BackendAdapt.ts
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/frontend/src/utils/preprocessing/BackendAdapt.ts
@@ -0,0 +1 @@
+
From d728aadc0066e16b04907a140eb2e7eee2a03225 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Wed, 12 Mar 2025 11:03:39 -0700
Subject: [PATCH 22/38] remove majors icon
---
.../course-icon/MajorsCourseIcon.module.css | 47 ++++++-
.../majors/course-icon/MajorsCourseIcon.tsx | 119 +++++++++++-------
frontend/src/app/majors/page.tsx | 2 +-
.../app/majors/requirements/Requirements.tsx | 112 ++++++++---------
.../majors/requirements/RequirementsUtils.ts | 80 ++++++++++++
.../DistributionsCircle.tsx | 9 +-
.../src/database/programs/concs/concs-econ.ts | 2 +-
7 files changed, 266 insertions(+), 105 deletions(-)
create mode 100644 frontend/src/app/majors/requirements/RequirementsUtils.ts
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
index a4dac89..3529a73 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
@@ -1,5 +1,5 @@
-.CourseIcon {
+.Icon {
display: flex;
flex-direction: row;
@@ -18,7 +18,50 @@
transition: filter 0.4s ease;
}
-.CourseIcon:hover {
+.Icon:hover {
cursor: pointer;
filter: brightness(95%);
}
+
+.CourseIcon {
+ background-color: #F5F5F5;
+}
+
+.StudentCourseIcon {
+ background-color: #E1E9F8;
+}
+
+.EmptyIcon {
+ width: 18px; /* Ensure it's a perfect circle */
+ height: 18px;
+ aspect-ratio: 1 / 1; /* Keeps it circular */
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%; /* Ensures a perfect circle */
+ background-color: #f5f5f5;
+}
+
+.EmptyIcon svg {
+ width: 10px; /* Increase size of "+" */
+ height: 10px;
+}
+
+.RemoveButton {
+ margin-right: 4px;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background-color: white;
+ color: black;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 10px;
+ font-weight: bold;
+ cursor: pointer;
+ /* position: absolute;
+ top: -5px;
+ right: -5px;
+ z-index: 10; */
+}
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
index ecb401c..bbd517a 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -1,9 +1,10 @@
+"use client";
import React from "react";
import Style from "./MajorsCourseIcon.module.css"
+import { ConcentrationSubrequirement } from "@/types/type-program";
import { StudentCourse, Course } from "@/types/type-user";
-import { RenderMark, GetCourseColor } from "@/utils/course-display/CourseDisplay";
import DistributionCircle from "@/components/distribution-circle/DistributionsCircle";
@@ -31,58 +32,92 @@ function CourseSeasonIcon(props: { seasons: Array }) {
);
}
-
-function DistCircDiv(props: { dist: string[] })
-{
- if(!Array.isArray(props.dist) || props.dist.length === 0){
- return(
-
-
-
- );
- }
-
- return(
-
-
+// ✅ Modify `MajorsCourseIcon` to handle remove clicks
+function MajorsCourseIcon(props: {
+ edit: boolean;
+ course: Course;
+ subreq: ConcentrationSubrequirement;
+ onRemoveCourse: Function;
+}) {
+ return (
+
+ {/* ✅ Only show remove button in edit mode */}
+ {props.edit && (
+ props.onRemoveCourse(props.course, props.subreq, false)} />
+ )}
+
+ {props.course.codes[0]}
+
);
}
+// ✅ Modify `MajorsStudentCourseIcon` to handle remove clicks
+function MajorsStudentCourseIcon(props: {
+ edit: boolean;
+ studentCourse: StudentCourse;
+ subreq: ConcentrationSubrequirement;
+ onRemoveCourse: Function;
+}) {
+ return (
+
+ {/* ✅ Only show remove button in edit mode */}
+ {props.edit && (
+ props.onRemoveCourse(props.studentCourse.course, props.subreq, true)} />
+ )}
+ ✓ {props.studentCourse.course.codes[0]}
+
+ );
+}
-export function StudentCourseIcon(props: { studentCourse: StudentCourse, utilityButton?: React.ReactNode }) {
-
- const dist = props.studentCourse.course.dist || [];
-
- // style={{ backgroundColor: GetCourseColor(props.studentCourse.term) }}
-
+// ✅ Modify `RemoveButton` to accept an `onClick` prop
+function RemoveButton({ onClick }: { onClick: () => void }) {
return (
-
- {props.utilityButton && props.utilityButton}
- {props.studentCourse.status === ""
- ?
- :
- }
- {props.studentCourse.course.codes[0]}
- {/*
*/}
+
+ ❌ {/* Placeholder remove icon */}
);
}
+function MajorsEmptyIcon({ edit }: { edit: boolean }) {
+ return (
+
+ {edit && (
+
+
+
+ )}
+
+ );
+}
-export function CourseIcon(props: { course: Course, studentCourse?: StudentCourse }){
-
- if(props.studentCourse){
- return(
-
- );
- }
+export function MajorsIcon(props: {
+ edit: boolean;
+ contentCourse: Course | StudentCourse | null;
+ subreq: ConcentrationSubrequirement;
+ onRemoveCourse: Function;
+}) {
+ // If no course exists, render the "Add" icon
+ if (!props.contentCourse) {
+ return ;
+ }
- return(
-
-
- {props.course.codes[0]}
-
-
+ // ✅ Determine if `contentCourse` is a StudentCourse (i.e., has a `course` field inside)
+ const isStudentCourse = "course" in props.contentCourse;
+
+ return isStudentCourse ? (
+
+ ) : (
+
);
}
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 487f486..5e793ee 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -49,7 +49,7 @@ function Majors()
updateIndex({ ...index, conc: -1 })}/>
-
+
);
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index e323fcf..e9ff9da 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -1,51 +1,42 @@
+"use client";
import { useState } from "react";
+import { useAuth } from "@/app/providers";
import Style from "./Requirements.module.css";
import { Course } from "@/types/type-user";
-import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration } from "@/types/type-program";
-import { CourseIcon } from "../course-icon/MajorsCourseIcon";
+import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration, MajorsIndex } from "@/types/type-program";
-function RenderSubrequirementCourse(props: { edit?: boolean, course: Course | null, subreq: ConcentrationSubrequirement }){
+import { updateCourseInSubreq } from "./RequirementsUtils";
+import { MajorsIcon } from "../course-icon/MajorsCourseIcon";
- if(props.course === null){
- return(
-
- {props.edit ? (
e
) : (
)}
-
- );
- }
-
- const matchingStudentCourse = props.subreq.student_courses_satisfying.find(
+function RenderSubrequirementCourse(props: {
+ edit?: boolean;
+ course: Course | null;
+ subreq: ConcentrationSubrequirement;
+ onRemoveCourse: Function;
+})
+{
+ // Find if this course exists in student_courses_satisfying (meaning it's a StudentCourse)
+ const matchingStudentCourse = props.subreq.student_courses_satisfying.find(
(studentCourse) => studentCourse.course === props.course
);
- return(
-
-
-
- )
+ return (
+
+ {/* ✅ Pass `onRemoveCourse` down to `MajorsIcon`, along with subreq & whether it's a StudentCourse */}
+
+
+ );
}
-function RenderSubrequirement(props: { edit: boolean, subreq: ConcentrationSubrequirement }) {
- const [showAll, setShowAll] = useState(false);
-
- // Separate null and non-null courses
- const nullCourses = props.subreq.courses_options.filter((course) => course === null);
- const nonNullCourses = props.subreq.courses_options.filter((course) => course !== null) as Course[];
- const satisfiedCourses = props.subreq.student_courses_satisfying.map((studentCourse) => studentCourse.course);
-
- // Determine which courses to show
- const isSatisfied = props.subreq.student_courses_satisfying.length === props.subreq.courses_required;
- const displayedNonNullCourses = showAll
- ? nonNullCourses
- : isSatisfied
- ? satisfiedCourses
- : nonNullCourses.slice(0, 4);
-
- // Ensure null courses are always displayed
- const displayedCourses = [...nullCourses, ...displayedNonNullCourses];
-
+function RenderSubrequirement(props: { edit: boolean, subreq: ConcentrationSubrequirement, onRemoveCourse: Function })
+{
return (
@@ -55,27 +46,23 @@ function RenderSubrequirement(props: { edit: boolean, subreq: ConcentrationSubre
{props.subreq.subreq_desc}
- {displayedCourses.map((course, index) => (
-
-
-
+ {props.subreq.courses_options.map((course, index) => (
+
))}
- {/* Toggle Button to Expand / Collapse */}
- {nonNullCourses.length > 4 && (
-
setShowAll(!showAll)}>
- {showAll ? "<<" : ">>"}
-
- )}
);
}
-function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement }){
+function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement, onRemoveCourse: Function })
+{
// const { user, setUser } = useAuth();
// const { req, programIndex, degreeIndex } = props;
@@ -149,31 +136,33 @@ function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement
{subreqs_required_count
? subreqs_list.slice(0, subreqs_required_count).map((subreq, index) => (
-
+
))
: subreqs_list.map((subreq, index) => (
-
+
))}
);
}
-function RequirementsList(props: { edit: boolean, conc: DegreeConcentration })
+function RequirementsList(props: { edit: boolean, conc: DegreeConcentration, onRemoveCourse: Function })
{
return(
{props.conc.conc_reqs.map((req, index) => (
-
+
))}
);
}
-function Requirements(props: { conc: DegreeConcentration | null })
+function Requirements(props: { conc: DegreeConcentration | null, index: MajorsIndex })
{
const [edit, setEdit] = useState(false);
+ const { user, setUser } = useAuth();
+
if(props.conc == null){
return(
@@ -184,6 +173,15 @@ function Requirements(props: { conc: DegreeConcentration | null })
)
}
+ function onRemoveCourse(course: Course | null, subreq: ConcentrationSubrequirement, isStudentCourse: boolean = false) {
+ updateCourseInSubreq(user, setUser, props.index, subreq, course, "remove", isStudentCourse);
+ }
+
+ // ✅ Handles adding a new course
+ // function onAddCourse(course: Course, subreq: ConcentrationSubrequirement) {
+ // updateCourseInSubreq(user, setUser, props.index, subreq, course, "add");
+ // }
+
return(
@@ -191,7 +189,7 @@ function Requirements(props: { conc: DegreeConcentration | null })
{props.conc.user_status == 1 ? (
setEdit(!edit)}>⚙
) : (
)}
-
+
);
diff --git a/frontend/src/app/majors/requirements/RequirementsUtils.ts b/frontend/src/app/majors/requirements/RequirementsUtils.ts
new file mode 100644
index 0000000..01d445a
--- /dev/null
+++ b/frontend/src/app/majors/requirements/RequirementsUtils.ts
@@ -0,0 +1,80 @@
+
+import { ConcentrationSubrequirement, MajorsIndex } from "@/types/type-program";
+import { Course, User } from "@/types/type-user";
+
+export function updateCourseInSubreq(
+ user: User,
+ setUser: Function,
+ majorsIndex: MajorsIndex,
+ subreq: ConcentrationSubrequirement,
+ course: Course | null,
+ action: "add" | "remove",
+ isStudentCourse?: boolean
+) {
+ setUser((prevUser: User) => {
+ const updatedUser = { ...prevUser }; // Clone user object
+
+ // Locate the correct program, degree, and concentration
+ const program = updatedUser.FYP.prog_list[majorsIndex.prog];
+ const degree = program.prog_degs[majorsIndex.deg];
+ const concentration = degree.deg_concs[majorsIndex.conc];
+
+ // Locate the requirement that contains this subrequirement
+ const requirementIndex = concentration.conc_reqs.findIndex((req) =>
+ req.subreqs_list.includes(subreq)
+ );
+
+ if (requirementIndex === -1) return prevUser; // Safety check
+
+ // Create a **new** subrequirement list with modifications
+ const updatedSubreqs = concentration.conc_reqs[requirementIndex].subreqs_list.map((s) => {
+ if (s !== subreq) return s; // Keep other subreqs unchanged
+
+ return {
+ ...s,
+ courses_options: [...s.courses_options].map((c) => (c === course ? null : c)), // Ensure a new array is created
+ student_courses_satisfying: isStudentCourse
+ ? [...s.student_courses_satisfying].filter((sc) => sc.course !== course) // Ensure a new array is created
+ : s.student_courses_satisfying,
+ };
+ });
+
+ // Create a **new** requirement list with the updated subrequirement
+ const updatedConcReqs = concentration.conc_reqs.map((req, idx) =>
+ idx === requirementIndex ? { ...req, subreqs_list: updatedSubreqs } : req
+ );
+
+ // Create a **new** concentration object with updated requirements
+ const updatedConcentration = { ...concentration, conc_reqs: updatedConcReqs };
+
+ // Create a **new** degree object with updated concentrations
+ const updatedDegree = {
+ ...degree,
+ deg_concs: degree.deg_concs.map((conc, idx) =>
+ idx === majorsIndex.conc ? updatedConcentration : conc
+ ),
+ };
+
+ // Create a **new** program object with updated degrees
+ const updatedProgram = {
+ ...program,
+ prog_degs: program.prog_degs.map((deg, idx) =>
+ idx === majorsIndex.deg ? updatedDegree : deg
+ ),
+ };
+
+ // Create a **new** user object with updated programs
+ const updatedUserFinal = {
+ ...updatedUser,
+ FYP: {
+ ...updatedUser.FYP,
+ prog_list: updatedUser.FYP.prog_list.map((prog, idx) =>
+ idx === majorsIndex.prog ? updatedProgram : prog
+ ),
+ },
+ };
+
+ return updatedUserFinal;
+ });
+}
+
diff --git a/frontend/src/components/distribution-circle/DistributionsCircle.tsx b/frontend/src/components/distribution-circle/DistributionsCircle.tsx
index 3824bdc..b7db107 100644
--- a/frontend/src/components/distribution-circle/DistributionsCircle.tsx
+++ b/frontend/src/components/distribution-circle/DistributionsCircle.tsx
@@ -25,7 +25,12 @@ function getData(distributions: string[]) {
const width = 12;
const height = 12;
-export default function DistributionCircle(props: { distributions: string[] }) {
+export default function DistributionCircle(props: { distributions: string[] })
+{
+ if(props.distributions.length == 0){
+ return
;
+ }
+
const radius = Math.min(width, height) / 2;
const data = useMemo(() => getData(props.distributions), [props.distributions]);
@@ -48,7 +53,7 @@ export default function DistributionCircle(props: { distributions: string[] }) {
return (
-
+
{arcs.map((arc: string | null, i: number) =>
arc ? : null
diff --git a/frontend/src/database/programs/concs/concs-econ.ts b/frontend/src/database/programs/concs/concs-econ.ts
index ec1ca3e..91e813f 100644
--- a/frontend/src/database/programs/concs/concs-econ.ts
+++ b/frontend/src/database/programs/concs/concs-econ.ts
@@ -9,7 +9,7 @@ const INTRO_MATH: ConcentrationSubrequirement = {
subreq_name: "MATH",
subreq_desc: "118 or 120 recommended. Any MATH 200+ satisfies.",
courses_required: 1,
- courses_options: [MATH_110, MATH_111, MATH_112, MATH_115, MATH_116, MATH_118, MATH_120, ENAS_151],
+ courses_options: [MATH_118, MATH_120],
courses_elective_range: null,
courses_any_bool: false,
student_courses_satisfying: [],
From bb586e2e3d8435345cbdd2a756892499049e7509 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Thu, 13 Mar 2025 11:42:11 -0700
Subject: [PATCH 23/38] add popup
---
.../course-icon/MajorsCourseIcon.module.css | 68 ++++---
.../majors/course-icon/MajorsCourseIcon.tsx | 65 +++++--
frontend/src/app/majors/page.tsx | 2 +-
.../requirements/Requirements.module.css | 31 +--
.../app/majors/requirements/Requirements.tsx | 141 ++++----------
.../majors/requirements/RequirementsUtils.ts | 178 ++++++++++++------
6 files changed, 254 insertions(+), 231 deletions(-)
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
index 3529a73..c580b22 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
@@ -31,37 +31,61 @@
background-color: #E1E9F8;
}
-.EmptyIcon {
- width: 18px; /* Ensure it's a perfect circle */
- height: 18px;
- aspect-ratio: 1 / 1; /* Keeps it circular */
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 50%; /* Ensures a perfect circle */
- background-color: #f5f5f5;
-}
-
-.EmptyIcon svg {
- width: 10px; /* Increase size of "+" */
- height: 10px;
-}
-
.RemoveButton {
margin-right: 4px;
width: 14px;
height: 14px;
border-radius: 50%;
- background-color: white;
- color: black;
+ background-color: rgb(237, 237, 237);
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: bold;
cursor: pointer;
- /* position: absolute;
- top: -5px;
- right: -5px;
- z-index: 10; */
+}
+
+
+
+
+
+
+
+
+.IconContainer {
+ position: relative;
+ display: inline-block;
+}
+
+.EmptyIcon {
+ width: 20px;
+ height: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ background-color: #f5f5f5;
+ cursor: default;
+}
+
+.EmptyIcon:hover {
+ cursor: pointer;
+ background-color: #e0e0e0;
+}
+
+.AddCoursePopup {
+ position: absolute;
+ top: 22px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: white;
+ border: 1px solid #ddd;
+ padding: 6px;
+ box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ border-radius: 5px;
+ z-index: 10;
+ min-width: 120px;
}
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
index bbd517a..efc7361 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -1,6 +1,5 @@
-"use client";
-import React from "react";
+import { useState, useRef, useEffect } from "react";
import Style from "./MajorsCourseIcon.module.css"
import { ConcentrationSubrequirement } from "@/types/type-program";
@@ -32,7 +31,6 @@ function CourseSeasonIcon(props: { seasons: Array }) {
);
}
-// ✅ Modify `MajorsCourseIcon` to handle remove clicks
function MajorsCourseIcon(props: {
edit: boolean;
course: Course;
@@ -52,7 +50,6 @@ function MajorsCourseIcon(props: {
);
}
-// ✅ Modify `MajorsStudentCourseIcon` to handle remove clicks
function MajorsStudentCourseIcon(props: {
edit: boolean;
studentCourse: StudentCourse;
@@ -70,27 +67,71 @@ function MajorsStudentCourseIcon(props: {
);
}
-// ✅ Modify `RemoveButton` to accept an `onClick` prop
function RemoveButton({ onClick }: { onClick: () => void }) {
return (
- ❌ {/* Placeholder remove icon */}
+
);
}
-function MajorsEmptyIcon({ edit }: { edit: boolean }) {
+function MajorsEmptyIcon(props: { edit: boolean }) {
+ const [isAdding, setIsAdding] = useState(false);
+ const [courseCode, setCourseCode] = useState("");
+ const popupRef = useRef(null);
+ const inputRef = useRef(null);
+
+ // 🔹 Close input box when clicking outside
+ useEffect(() => {
+ function handleClickOutside(event: MouseEvent) {
+ if (popupRef.current && !popupRef.current.contains(event.target as Node)) {
+ setIsAdding(false);
+ }
+ }
+
+ if (isAdding) {
+ document.addEventListener("mousedown", handleClickOutside);
+ }
+
+ return () => {
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, [isAdding]);
+
+ // 🔹 Auto-focus input when it appears
+ useEffect(() => {
+ if (isAdding) {
+ inputRef.current?.focus();
+ }
+ }, [isAdding]);
+
return (
-
- {edit && (
-
-
-
+
{/* ✅ Keeps relative positioning */}
+ {props.edit ? (
+ <>
+
setIsAdding(true)}>+
+
+ {isAdding && (
+
+ setCourseCode(e.target.value)}
+ />
+
+ )}
+ >
+ ) : (
+
// ✅ Non-editable version stays a simple gray circle
)}
);
}
+
+
+
export function MajorsIcon(props: {
edit: boolean;
contentCourse: Course | StudentCourse | null;
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 5e793ee..0def287 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -49,7 +49,7 @@ function Majors()
updateIndex({ ...index, conc: -1 })}/>
-
+
);
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index f7fcb74..b0680e7 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -18,6 +18,7 @@
.ReqsList {
border: 1px solid white;
+ margin-left: 30px;
/*
height: 430px;
scrollbar-color: rgb(131, 131, 131) transparent;
@@ -45,20 +46,7 @@
font-style: italic;
font-size: 12px;
font-weight: 500;
-}
-
-.EmptyCourse {
- border-radius: 15px;
- background-color: #F5F5F5;
- transition: filter 0.4s ease;
- width: 24px; /* Adjust width to match CourseIcon */
- height: 24px; /* Adjust height to match CourseIcon */
- display: inline-block; /* Keeps it inline with other elements */
-}
-
-.EmptyCourse:hover {
- cursor: pointer;
- filter: brightness(95%);
+ margin-bottom: 4px;
}
.ToggleButton {
@@ -71,21 +59,6 @@
font-size: 14px;
}
-.resetButton {
- margin-right: 10px; /* Add margin to the right of the reset button */
- opacity: 0; /* Make it invisible */
- pointer-events: none; /* Make it unclickable */
-}
-
-.resetButton.visible {
- opacity: 1; /* Make it visible */
- pointer-events: auto; /* Make it clickable */
-}
-
-.resetButton:active, .editButton:active {
- color: #333; /* Darker color on click */
-}
-
.ButtonRow {
display: flex;
gap: 6px;
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index e9ff9da..0d45fa7 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -1,30 +1,24 @@
"use client";
-import { useState } from "react";
import { useAuth } from "@/app/providers";
+
+import { useState } from "react";
import Style from "./Requirements.module.css";
import { Course } from "@/types/type-user";
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration, MajorsIndex } from "@/types/type-program";
-import { updateCourseInSubreq } from "./RequirementsUtils";
+import { removeCourseInSubreq } from "./RequirementsUtils";
import { MajorsIcon } from "../course-icon/MajorsCourseIcon";
-function RenderSubrequirementCourse(props: {
- edit?: boolean;
- course: Course | null;
- subreq: ConcentrationSubrequirement;
- onRemoveCourse: Function;
-})
+function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | null; subreq: ConcentrationSubrequirement; onRemoveCourse: Function })
{
- // Find if this course exists in student_courses_satisfying (meaning it's a StudentCourse)
const matchingStudentCourse = props.subreq.student_courses_satisfying.find(
(studentCourse) => studentCourse.course === props.course
);
return (
- {/* ✅ Pass `onRemoveCourse` down to `MajorsIcon`, along with subreq & whether it's a StudentCourse */}
@@ -46,14 +45,14 @@ function RenderSubrequirement(props: { edit: boolean, subreq: ConcentrationSubre
{props.subreq.subreq_desc}
- {props.subreq.courses_options.map((course, index) => (
+ {props.subreq.courses_options.map((course, course_index) => (
))}
@@ -61,52 +60,9 @@ function RenderSubrequirement(props: { edit: boolean, subreq: ConcentrationSubre
);
}
-function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement, onRemoveCourse: Function })
+function RenderRequirement(props: { edit: boolean, majorsIndex: MajorsIndex, reqIndex: number, req: ConcentrationRequirement })
{
-
- // const { user, setUser } = useAuth();
- // const { req, programIndex, degreeIndex } = props;
- const { subreqs_list, subreqs_required_count } = props.req;
-
- // // Get the correct degree configuration (assumes only one degree per program)
- // const degreeConfig = user.FYP.degreeConfigurations[programIndex][0];
-
- // Find the corresponding requirement in `degreeConfig`
- // const requirement = degreeConfig[0].reqs_list.find((r: DegreeRequirement) => r.req_name === req.req_name);
-
- // if (!requirement) return null; // Fail-safe, shouldn't happen
-
- // Move clicked subreq to the front if it's beyond the first `subreqs_required_count`
- // const handleSubreqClick = (subreq: DegreeSubrequirement) => {
- // if (!subreqs_required_count) return; // Ignore clicks if not applicable
-
- // setUser((prevUser: User) => {
- // const newUser = { ...prevUser };
-
- // // Get the degree and requirement again inside state update
- // const updatedDegree = newUser.FYP.degreeConfigurations[programIndex][degreeIndex];
- // const updatedRequirement = updatedDegree[0].reqs_list.find((r) => r.req_name === req.req_name); // FIXXX
-
- // if (!updatedRequirement) return prevUser; // Failsafe
-
- // const updatedSubreqs = [...updatedRequirement.subreqs_list];
- // const index = updatedSubreqs.findIndex((s) => s.subreq_name === subreq.subreq_name);
-
- // if (index >= subreqs_required_count) {
- // // Move it to the front
- // updatedSubreqs.splice(index, 1);
- // updatedSubreqs.unshift(subreq);
- // }
-
- // // Update the requirement's subreqs_list in user state
- // updatedRequirement.subreqs_list = updatedSubreqs;
-
- // return newUser;
- // });
- // };
-
-
- return (
+ return(
@@ -116,53 +72,29 @@ function RenderRequirement(props: { edit: boolean, req: ConcentrationRequirement
{props.req.checkbox !== undefined ? props.req.courses_satisfied_count === props.req.courses_required_count ? "✅" : "❌" : `${props.req.courses_satisfied_count}|${props.req.courses_required_count}`}
-
-
+
{props.req.req_desc}
-
- {/* Subreq Toggle Buttons - Only show if subreqs_required_count exists and < total subreqs */}
- {/* {subreqs_required_count && subreqs_list.length > subreqs_required_count && (
-
- {subreqs_list.map((subreq, index) => (
-
handleSubreqClick(subreq)}>
- {subreq.subreq_name}
-
- ))}
-
- )} */}
-
- {/* Display Selected Subreqs - Enforce subreqs_required_count if present */}
-
- {subreqs_required_count
- ? subreqs_list.slice(0, subreqs_required_count).map((subreq, index) => (
-
- ))
- : subreqs_list.map((subreq, index) => (
-
- ))}
+
+ {props.req.subreqs_list.map((subreq, subreq_index) => (
+
+ ))}
);
}
-function RequirementsList(props: { edit: boolean, conc: DegreeConcentration, onRemoveCourse: Function })
-{
- return(
-
- {props.conc.conc_reqs.map((req, index) => (
-
- ))}
-
- );
-}
-
-function Requirements(props: { conc: DegreeConcentration | null, index: MajorsIndex })
+function Requirements(props: { conc: DegreeConcentration | null, majorsIndex: MajorsIndex })
{
const [edit, setEdit] = useState(false);
- const { user, setUser } = useAuth();
-
if(props.conc == null){
return(
@@ -173,23 +105,16 @@ function Requirements(props: { conc: DegreeConcentration | null, index: MajorsIn
)
}
- function onRemoveCourse(course: Course | null, subreq: ConcentrationSubrequirement, isStudentCourse: boolean = false) {
- updateCourseInSubreq(user, setUser, props.index, subreq, course, "remove", isStudentCourse);
- }
-
- // ✅ Handles adding a new course
- // function onAddCourse(course: Course, subreq: ConcentrationSubrequirement) {
- // updateCourseInSubreq(user, setUser, props.index, subreq, course, "add");
- // }
-
return(
Requirements
- {props.conc.user_status == 1 ? (
setEdit(!edit)}>⚙
) : (
)}
+ {props.conc.user_status == 1 &&
setEdit(!edit)}>⚙
}
-
-
+
+ {props.conc.conc_reqs.map((req, i) => (
+
+ ))}
);
diff --git a/frontend/src/app/majors/requirements/RequirementsUtils.ts b/frontend/src/app/majors/requirements/RequirementsUtils.ts
index 01d445a..54cb564 100644
--- a/frontend/src/app/majors/requirements/RequirementsUtils.ts
+++ b/frontend/src/app/majors/requirements/RequirementsUtils.ts
@@ -1,80 +1,140 @@
-import { ConcentrationSubrequirement, MajorsIndex } from "@/types/type-program";
+import { MajorsIndex } from "@/types/type-program";
import { Course, User } from "@/types/type-user";
+import { ConcentrationSubrequirement } from "@/types/type-program";
-export function updateCourseInSubreq(
- user: User,
- setUser: Function,
+function updateUserWithNewSubreq(
+ prevUser: User,
majorsIndex: MajorsIndex,
- subreq: ConcentrationSubrequirement,
- course: Course | null,
- action: "add" | "remove",
- isStudentCourse?: boolean
-) {
- setUser((prevUser: User) => {
- const updatedUser = { ...prevUser }; // Clone user object
+ reqIndex: number,
+ subreqIndex: number,
+ updatedSubreq: ConcentrationSubrequirement
+): User {
+ const updatedUser = { ...prevUser };
+
+ // Directly access the correct structures using indices
+ const program = updatedUser.FYP.prog_list[majorsIndex.prog];
+ const degree = program.prog_degs[majorsIndex.deg];
+ const concentration = degree.deg_concs[majorsIndex.conc];
+ const requirement = concentration.conc_reqs[reqIndex];
+
+ // ✅ Modify only the affected subrequirement
+ const updatedSubreqs = [...requirement.subreqs_list];
+ updatedSubreqs[subreqIndex] = updatedSubreq;
+
+ // ✅ Modify only the affected requirement
+ const updatedConcReqs = [...concentration.conc_reqs];
+ updatedConcReqs[reqIndex] = { ...requirement, subreqs_list: updatedSubreqs };
+
+ // ✅ Modify only the affected concentration
+ const updatedConcentration = { ...concentration, conc_reqs: updatedConcReqs };
- // Locate the correct program, degree, and concentration
- const program = updatedUser.FYP.prog_list[majorsIndex.prog];
+ // ✅ Modify only the affected degree
+ const updatedDegree = {
+ ...degree,
+ deg_concs: degree.deg_concs.map((conc, idx) =>
+ idx === majorsIndex.conc ? updatedConcentration : conc
+ )
+ };
+
+ // ✅ Modify only the affected program
+ const updatedProgram = {
+ ...program,
+ prog_degs: program.prog_degs.map((deg, idx) =>
+ idx === majorsIndex.deg ? updatedDegree : deg
+ )
+ };
+
+ // ✅ Modify only the affected user object
+ return {
+ ...updatedUser,
+ FYP: {
+ ...updatedUser.FYP,
+ prog_list: updatedUser.FYP.prog_list.map((prog, idx) =>
+ idx === majorsIndex.prog ? updatedProgram : prog
+ )
+ }
+ };
+}
+
+export function addCourseInSubreq(
+ setUser: Function,
+ majorsIndex: MajorsIndex,
+ reqIndex: number,
+ subreqIndex: number,
+ courseCode: string
+): boolean {
+ setUser((prevUser: User) => {
+ const program = prevUser.FYP.prog_list[majorsIndex.prog];
const degree = program.prog_degs[majorsIndex.deg];
const concentration = degree.deg_concs[majorsIndex.conc];
+ const requirement = concentration.conc_reqs[reqIndex];
+ const subreq = requirement.subreqs_list[subreqIndex];
- // Locate the requirement that contains this subrequirement
- const requirementIndex = concentration.conc_reqs.findIndex((req) =>
- req.subreqs_list.includes(subreq)
+ // ✅ Find the StudentCourse that matches the course code
+ const matchingStudentCourse = prevUser.FYP.studentCourses.find((studentCourse) =>
+ studentCourse.course.codes.includes(courseCode)
);
- if (requirementIndex === -1) return prevUser; // Safety check
+ if (!matchingStudentCourse) return prevUser; // 🚨 No update if course doesn't exist
- // Create a **new** subrequirement list with modifications
- const updatedSubreqs = concentration.conc_reqs[requirementIndex].subreqs_list.map((s) => {
- if (s !== subreq) return s; // Keep other subreqs unchanged
+ // ✅ Find the first null spot in courses_options
+ const updatedCoursesOptions = [...subreq.courses_options];
+ const firstNullIndex = updatedCoursesOptions.indexOf(null);
+ if (firstNullIndex === -1) return prevUser; // 🚨 No space available, no update
- return {
- ...s,
- courses_options: [...s.courses_options].map((c) => (c === course ? null : c)), // Ensure a new array is created
- student_courses_satisfying: isStudentCourse
- ? [...s.student_courses_satisfying].filter((sc) => sc.course !== course) // Ensure a new array is created
- : s.student_courses_satisfying,
- };
- });
-
- // Create a **new** requirement list with the updated subrequirement
- const updatedConcReqs = concentration.conc_reqs.map((req, idx) =>
- idx === requirementIndex ? { ...req, subreqs_list: updatedSubreqs } : req
- );
+ updatedCoursesOptions[firstNullIndex] = matchingStudentCourse.course; // Replace null with new course
- // Create a **new** concentration object with updated requirements
- const updatedConcentration = { ...concentration, conc_reqs: updatedConcReqs };
+ // ✅ Add the StudentCourse to `student_courses_satisfying`
+ const updatedStudentCourses = [...subreq.student_courses_satisfying, matchingStudentCourse];
- // Create a **new** degree object with updated concentrations
- const updatedDegree = {
- ...degree,
- deg_concs: degree.deg_concs.map((conc, idx) =>
- idx === majorsIndex.conc ? updatedConcentration : conc
- ),
+ // ✅ Create the updated subrequirement
+ const updatedSubreq = {
+ ...subreq,
+ courses_options: updatedCoursesOptions,
+ student_courses_satisfying: updatedStudentCourses
};
- // Create a **new** program object with updated degrees
- const updatedProgram = {
- ...program,
- prog_degs: program.prog_degs.map((deg, idx) =>
- idx === majorsIndex.deg ? updatedDegree : deg
- ),
- };
+ return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, updatedSubreq);
+ });
+
+ return true; // ✅ Successfully added course
+}
+
+export function removeCourseInSubreq(
+ setUser: Function,
+ majorsIndex: MajorsIndex,
+ reqIndex: number,
+ subreqIndex: number,
+ course: Course | null,
+ isStudentCourse?: boolean
+) {
+ setUser((prevUser: User) => {
+ const program = prevUser.FYP.prog_list[majorsIndex.prog];
+ const degree = program.prog_degs[majorsIndex.deg];
+ const concentration = degree.deg_concs[majorsIndex.conc];
+ const requirement = concentration.conc_reqs[reqIndex];
+ const subreq = requirement.subreqs_list[subreqIndex];
+
+ // ✅ Modify `courses_options` directly
+ const updatedCoursesOptions = [...subreq.courses_options];
+ const courseIndex = updatedCoursesOptions.indexOf(course);
+ if (courseIndex !== -1) {
+ updatedCoursesOptions[courseIndex] = null;
+ }
- // Create a **new** user object with updated programs
- const updatedUserFinal = {
- ...updatedUser,
- FYP: {
- ...updatedUser.FYP,
- prog_list: updatedUser.FYP.prog_list.map((prog, idx) =>
- idx === majorsIndex.prog ? updatedProgram : prog
- ),
- },
+ // ✅ Filter out StudentCourse if necessary
+ const updatedStudentCourses = isStudentCourse
+ ? subreq.student_courses_satisfying.filter((sc) => sc.course !== course)
+ : subreq.student_courses_satisfying;
+
+ // ✅ Create the updated subrequirement
+ const updatedSubreq = {
+ ...subreq,
+ courses_options: updatedCoursesOptions,
+ student_courses_satisfying: updatedStudentCourses
};
- return updatedUserFinal;
+ return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, updatedSubreq);
});
}
-
From 577130e3db6647703b66b50489e8d971b76d6e4f Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Thu, 13 Mar 2025 14:45:13 -0700
Subject: [PATCH 24/38] add majors course func
---
.../course-icon/MajorsCourseIcon.module.css | 17 ++++++-
.../majors/course-icon/MajorsCourseIcon.tsx | 44 +++++++++++--------
.../requirements/Requirements.module.css | 4 +-
.../app/majors/requirements/Requirements.tsx | 13 ++++--
.../majors/requirements/RequirementsUtils.ts | 8 +++-
frontend/src/app/providers.tsx | 5 ++-
frontend/src/database/data-user.ts | 3 +-
7 files changed, 63 insertions(+), 31 deletions(-)
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
index c580b22..d54253f 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
@@ -84,8 +84,21 @@
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
- gap: 5px;
border-radius: 5px;
z-index: 10;
- min-width: 120px;
+ width: fit-content;
+ min-width: 60px;
+}
+
+.AddCoursePopup input {
+ width: 75px;
+ padding: 2px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+.ConfirmButton {
+ cursor: pointer;
+ color: green;
}
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
index efc7361..468bf0e 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -75,21 +75,22 @@ function RemoveButton({ onClick }: { onClick: () => void }) {
);
}
-function MajorsEmptyIcon(props: { edit: boolean }) {
+function MajorsEmptyIcon(props: { edit: boolean, onAddCourse: Function })
+{
const [isAdding, setIsAdding] = useState(false);
const [courseCode, setCourseCode] = useState("");
const popupRef = useRef(null);
const inputRef = useRef(null);
- // 🔹 Close input box when clicking outside
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (popupRef.current && !popupRef.current.contains(event.target as Node)) {
setIsAdding(false);
+ setCourseCode("");
}
}
- if (isAdding) {
+ if(isAdding){
document.addEventListener("mousedown", handleClickOutside);
}
@@ -98,49 +99,54 @@ function MajorsEmptyIcon(props: { edit: boolean }) {
};
}, [isAdding]);
- // 🔹 Auto-focus input when it appears
useEffect(() => {
if (isAdding) {
inputRef.current?.focus();
}
}, [isAdding]);
- return (
+ function handleAddCourse() {
+ const success = props.onAddCourse(courseCode);
+ if(success){
+ setIsAdding(false);
+ setCourseCode("");
+ }
+ }
+
+ return(
{/* ✅ Keeps relative positioning */}
{props.edit ? (
- <>
-
setIsAdding(true)}>+
+
+
setIsAdding(true)}>
+ +
+
{isAdding && (
)}
- >
+
) : (
-
// ✅ Non-editable version stays a simple gray circle
+
+
+
)}
);
}
-
-
-
export function MajorsIcon(props: {
edit: boolean;
contentCourse: Course | StudentCourse | null;
subreq: ConcentrationSubrequirement;
onRemoveCourse: Function;
+ onAddCourse: Function;
}) {
// If no course exists, render the "Add" icon
if (!props.contentCourse) {
- return ;
+ return ;
}
// ✅ Determine if `contentCourse` is a StudentCourse (i.e., has a `course` field inside)
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index b0680e7..2afe981 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -93,8 +93,8 @@
}
.GoldBackground {
- background-color: rgba(255, 215, 0, 0.3); /* Gold with 40% opacity */
- border-radius: 2px;
+ /* background-color: rgba(255, 215, 0, 0.3);
+ border-radius: 2px; */
}
.EditButton:hover {
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 0d45fa7..9329609 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -8,10 +8,10 @@ import Style from "./Requirements.module.css";
import { Course } from "@/types/type-user";
import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration, MajorsIndex } from "@/types/type-program";
-import { removeCourseInSubreq } from "./RequirementsUtils";
+import { removeCourseInSubreq, addCourseInSubreq } from "./RequirementsUtils";
import { MajorsIcon } from "../course-icon/MajorsCourseIcon";
-function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | null; subreq: ConcentrationSubrequirement; onRemoveCourse: Function })
+function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | null; subreq: ConcentrationSubrequirement; onRemoveCourse: Function, onAddCourse: Function })
{
const matchingStudentCourse = props.subreq.student_courses_satisfying.find(
(studentCourse) => studentCourse.course === props.course
@@ -24,6 +24,7 @@ function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | nu
contentCourse={matchingStudentCourse ?? props.course}
subreq={props.subreq}
onRemoveCourse={props.onRemoveCourse}
+ onAddCourse={props.onAddCourse}
/>
);
@@ -32,10 +33,15 @@ function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | nu
function RenderSubrequirement(props: { edit: boolean, majorsIndex: MajorsIndex, reqIndex: number, subreqIndex: number, subreq: ConcentrationSubrequirement })
{
const { setUser } = useAuth();
- function handleRemoveCourse(course: Course | null, isStudentCourse: boolean = false) {
+
+ function handleRemoveCourse(course: Course | null, isStudentCourse: boolean = false){
removeCourseInSubreq(setUser, props.majorsIndex, props.reqIndex, props.subreqIndex, course, isStudentCourse);
}
+ function handleAddCourse(courseCode: string){
+ return addCourseInSubreq(setUser, props.majorsIndex, props.reqIndex, props.subreqIndex, courseCode);
+ }
+
return (
@@ -53,6 +59,7 @@ function RenderSubrequirement(props: { edit: boolean, majorsIndex: MajorsIndex,
edit={props.edit}
// {...(props.subreq.courses_any_bool ? { edit: props.edit } : {})}
onRemoveCourse={handleRemoveCourse}
+ onAddCourse={handleAddCourse}
/>
))}
diff --git a/frontend/src/app/majors/requirements/RequirementsUtils.ts b/frontend/src/app/majors/requirements/RequirementsUtils.ts
index 54cb564..b1b4ca8 100644
--- a/frontend/src/app/majors/requirements/RequirementsUtils.ts
+++ b/frontend/src/app/majors/requirements/RequirementsUtils.ts
@@ -64,6 +64,8 @@ export function addCourseInSubreq(
subreqIndex: number,
courseCode: string
): boolean {
+ let success = false; // ✅ Track success state
+
setUser((prevUser: User) => {
const program = prevUser.FYP.prog_list[majorsIndex.prog];
const degree = program.prog_degs[majorsIndex.deg];
@@ -83,7 +85,7 @@ export function addCourseInSubreq(
const firstNullIndex = updatedCoursesOptions.indexOf(null);
if (firstNullIndex === -1) return prevUser; // 🚨 No space available, no update
- updatedCoursesOptions[firstNullIndex] = matchingStudentCourse.course; // Replace null with new course
+ updatedCoursesOptions[firstNullIndex] = matchingStudentCourse.course; // ✅ Replace null with new course
// ✅ Add the StudentCourse to `student_courses_satisfying`
const updatedStudentCourses = [...subreq.student_courses_satisfying, matchingStudentCourse];
@@ -95,10 +97,12 @@ export function addCourseInSubreq(
student_courses_satisfying: updatedStudentCourses
};
+ // ✅ Update state with new data
+ success = true; // ✅ Mark operation as successful
return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, updatedSubreq);
});
- return true; // ✅ Successfully added course
+ return success; // ✅ Now properly returns success/failure
}
export function removeCourseInSubreq(
diff --git a/frontend/src/app/providers.tsx b/frontend/src/app/providers.tsx
index 020a3cb..a1e9310 100644
--- a/frontend/src/app/providers.tsx
+++ b/frontend/src/app/providers.tsx
@@ -3,11 +3,12 @@
import { createContext, useContext, useState, useEffect } from "react";
import { User } from "@/types/type-user";
-import { NullUser, Ryan } from "@/database/data-user";
+import { Ryan } from "@/database/data-user";
const AuthContext = createContext
(null);
-export function AuthProvider({ children }: { children: React.ReactNode }) {
+export function AuthProvider({ children }: { children: React.ReactNode })
+{
const [auth, setAuth] = useState({ loggedIn: false });
const [user, setUser] = useState(Ryan);
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index 6c6438a..ed59de3 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,13 +1,14 @@
import { User } from "./../types/type-user";
import { PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC } from "./programs/data-program";
+import { SC_CPSC_201 } from "./data-courses";
export const Ryan: User = {
name: "Ryan",
netID: "rgg32",
onboard: false,
FYP: {
- studentCourses: [],
+ studentCourses: [SC_CPSC_201],
studentTermArrangement: {
first_year: [0, 202403, 202501],
sophomore: [0, 202503, 202601],
From 0586b757fb38131ac890b4a1460824f4e2b0f749 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Fri, 14 Mar 2025 14:05:23 -0700
Subject: [PATCH 25/38] program provider
---
frontend/src/app/courses/page.tsx | 2 +-
frontend/src/app/layout.tsx | 7 +-
frontend/src/app/login/page.tsx | 2 +-
frontend/src/app/majors/Majors.module.css | 2 +-
.../course-icon/MajorsCourseIcon.module.css | 28 ++--
.../majors/course-icon/MajorsCourseIcon.tsx | 19 +--
frontend/src/app/majors/metadata/Metadata.tsx | 148 ++++++++++--------
.../src/app/majors/metadata/MetadataUtils.ts | 47 ++++++
.../src/app/majors/overhead/pinned/Pinned.tsx | 4 +-
frontend/src/app/majors/page.tsx | 22 ++-
.../requirements/Requirements.module.css | 15 +-
.../app/majors/requirements/Requirements.tsx | 114 +++++++++-----
.../majors/requirements/RequirementsUtils.ts | 127 ++++++---------
frontend/src/app/not-found.tsx | 2 +-
frontend/src/app/page.tsx | 2 +-
.../AuthProvider.tsx} | 3 +-
frontend/src/context/ProgramProvider.tsx | 27 ++++
frontend/src/database/data-user.ts | 39 ++---
.../src/database/programs/concs/concs-cpsc.ts | 2 +-
.../src/database/programs/data-program.ts | 12 +-
frontend/src/types/type-user.ts | 7 +-
21 files changed, 367 insertions(+), 264 deletions(-)
create mode 100644 frontend/src/app/majors/metadata/MetadataUtils.ts
rename frontend/src/{app/providers.tsx => context/AuthProvider.tsx} (92%)
create mode 100644 frontend/src/context/ProgramProvider.tsx
diff --git a/frontend/src/app/courses/page.tsx b/frontend/src/app/courses/page.tsx
index c237f74..554107c 100644
--- a/frontend/src/app/courses/page.tsx
+++ b/frontend/src/app/courses/page.tsx
@@ -3,7 +3,7 @@
import React, { useState, useEffect } from "react";
import Style from "./Courses.module.css";
-import { useAuth } from "../providers";
+import { useAuth } from "@/context/AuthProvider";
import { StudentYear } from "@/types/type-user";
import { BuildStudentYears } from "./CoursesUtils";
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index ec5a50e..4f0bf4c 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -1,6 +1,7 @@
import "./globals.css";
-import { AuthProvider } from "./providers";
+import { AuthProvider } from "@/context/AuthProvider";
+import { ProgramProvider } from "@/context/ProgramProvider";
export const metadata = {
title: "MajorAudit"
@@ -12,7 +13,9 @@ export default function RootLayout({children}: {children: React.ReactNode})
- {children}
+
+ {children}
+
diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx
index 4eb3ab4..81263e4 100644
--- a/frontend/src/app/login/page.tsx
+++ b/frontend/src/app/login/page.tsx
@@ -3,7 +3,7 @@
import { useRouter } from "next/navigation";
import Style from "./Login.module.css";
-import { useAuth } from "../providers";
+import { useAuth } from "@/context/AuthProvider";
import NavBar from "@/components/navbar/NavBar";
function Login()
diff --git a/frontend/src/app/majors/Majors.module.css b/frontend/src/app/majors/Majors.module.css
index 24bbae8..42209e4 100644
--- a/frontend/src/app/majors/Majors.module.css
+++ b/frontend/src/app/majors/Majors.module.css
@@ -23,7 +23,7 @@
height: calc(100% - 100px);
}
-.EditButton {
+.ListButton {
position: fixed;
top: 95px;
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
index d54253f..13a33a4 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
@@ -1,18 +1,22 @@
+ /* */
+ /* min-height: 18px; */
+
.Icon {
display: flex;
flex-direction: row;
-
+
align-items: center;
+ justify-content: center;
- border-radius: 15px;
+ font-size: 14px;
+ font-weight: bold;
width: max-content;
- padding: 2px 4px;
- min-height: 18px;
+ height: max-content;
- font-size: 14px;
- font-weight: bold;
+ padding: 2px 4px;
+ border-radius: 15px;
background-color: #F5F5F5;
transition: filter 0.4s ease;
@@ -23,20 +27,16 @@
filter: brightness(95%);
}
-.CourseIcon {
- background-color: #F5F5F5;
-}
-
.StudentCourseIcon {
background-color: #E1E9F8;
}
.RemoveButton {
- margin-right: 4px;
- width: 14px;
- height: 14px;
+ margin-right: 3px;
+ width: 15px;
+ height: 15px;
border-radius: 50%;
- background-color: rgb(237, 237, 237);
+ background-color: rgb(255, 255, 255);
display: flex;
align-items: center;
justify-content: center;
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
index 468bf0e..dcff863 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -38,14 +38,13 @@ function MajorsCourseIcon(props: {
onRemoveCourse: Function;
}) {
return (
-
- {/* ✅ Only show remove button in edit mode */}
+
{props.edit && (
props.onRemoveCourse(props.course, props.subreq, false)} />
)}
-
+
{props.course.codes[0]}
-
+
);
}
@@ -114,11 +113,11 @@ function MajorsEmptyIcon(props: { edit: boolean, onAddCourse: Function })
}
return(
-
{/* ✅ Keeps relative positioning */}
+
{props.edit ? (
-
-
setIsAdding(true)}>
- +
+ <>
+
setIsAdding(true)}>
+
{isAdding && (
@@ -127,7 +126,7 @@ function MajorsEmptyIcon(props: { edit: boolean, onAddCourse: Function })
✔
)}
-
+ >
) : (
@@ -144,12 +143,10 @@ export function MajorsIcon(props: {
onRemoveCourse: Function;
onAddCourse: Function;
}) {
- // If no course exists, render the "Add" icon
if (!props.contentCourse) {
return
;
}
- // ✅ Determine if `contentCourse` is a StudentCourse (i.e., has a `course` field inside)
const isStudentCourse = "course" in props.contentCourse;
return isStudentCourse ? (
diff --git a/frontend/src/app/majors/metadata/Metadata.tsx b/frontend/src/app/majors/metadata/Metadata.tsx
index d9212c1..14013f1 100644
--- a/frontend/src/app/majors/metadata/Metadata.tsx
+++ b/frontend/src/app/majors/metadata/Metadata.tsx
@@ -4,19 +4,29 @@ import Style from "./Metadata.module.css";
import Link from 'next/link';
import { MajorsIndex, Program } from "@/types/type-program";
+import { usePrograms } from "@/context/ProgramProvider";
+import { useAuth } from "@/context/AuthProvider";
-function MetadataTopshelf(props: { program: Program })
-{
- return (
+import { toggleConcentrationPin } from "./MetadataUtils";
+
+function MetadataTopshelf(props: {
+ program: Program;
+ index: MajorsIndex;
+}){
+ const { setUser } = useAuth();
+ const { progList } = usePrograms();
+
+ function handlePinClick() {
+ toggleConcentrationPin(setUser, progList, props.index);
+ }
+
+ return(
- {/*
pinProgram(props.programIndex, 0, props.user, props.setUser)}>
-
-
-
addProgram(props.programIndex, 0, props.user, props.setUser)}>
-
-
*/}
+
+ 📌
+
{props.program.prog_data.prog_name}
@@ -74,34 +84,11 @@ function MetadataTopshelf(props: { program: Program })
// );
// }
-function MetadataBody(props: { program: Program, index: MajorsIndex }){
-
- return(
- // style={{ marginLeft: "80px" }}
-
- {/*
*/}
-
- ABOUT
-
-
- {props.program.prog_degs[props.index.deg].deg_concs[props.index.conc].conc_desc}
-
-
- DUS
-
-
- {props.program.prog_data.prog_dus.dus_name}; {props.program.prog_data.prog_dus.dus_email}
-
-
-
MAJOR CATALOG
-
MAJOR WEBSITE
-
-
- );
-}
-
-function MetadataToggle(props: { program: Program, index: MajorsIndex, setIndex: Function })
-{
+function MetadataToggle(props: {
+ program: Program,
+ index: MajorsIndex,
+ setIndex: Function
+}){
return (
@@ -134,19 +121,40 @@ function MetadataToggle(props: { program: Program, index: MajorsIndex, setIndex:
);
}
-function MetadataContent(props: { program: Program, index: MajorsIndex, setIndex: Function })
-{
- return (
-
-
-
-
-
- );
+function MetadataBody(props: {
+ program: Program,
+ index: MajorsIndex
+}){
+ return(
+ // style={{ marginLeft: "80px" }}
+
+ {/*
*/}
+
+ ABOUT
+
+
+ {props.program.prog_degs[props.index.deg].deg_concs[props.index.conc].conc_desc}
+
+
+ DUS
+
+
+ {props.program.prog_data.prog_dus.dus_name}; {props.program.prog_data.prog_dus.dus_email}
+
+
+
MAJOR CATALOG
+
MAJOR WEBSITE
+
+
+ );
}
-function MetadataScrollButton(props: { programs: Program[], index: MajorsIndex, setIndex: Function; dir: number })
-{
+function MetadataScrollButton(props: {
+ programs: Program[],
+ index: MajorsIndex,
+ setIndex: Function;
+ dir: number
+}){
return(
props.setIndex({ conc: 0, deg: 0, prog: props.index.prog + props.dir })}>
@@ -163,36 +171,46 @@ function MetadataScrollButton(props: { programs: Program[], index: MajorsIndex,
);
}
-function ProgramContent(props: { programs: Program[], index: MajorsIndex, setIndex: Function }){
- return(
-
-
-
-
-
- )
-}
-
-function ProgramList(props: { programs: Program[], setIndex: Function }){
+function ProgramList(props: {
+ programs: Program[],
+ setIndex: Function
+}){
return(
{props.programs.map((program: Program, prog_index: number) => (
-
props.setIndex({ conc: 0, deg: 0, prog: prog_index })}>
- {program.prog_data.prog_name} {program.prog_data.prog_abbr}
+
props.setIndex({ conc: 0, deg: 0, prog: prog_index })}
+ >
+ {program.prog_data.prog_name} {program.prog_data.prog_abbr}
))}
)
}
-function Metadata(props: { programs: Program[], index: MajorsIndex, setIndex: Function })
-{
+function Metadata(props: {
+ index: MajorsIndex,
+ setIndex: Function
+}){
+ const { progList } = usePrograms();
+ const currProgram = progList[props.index.prog];
+
return(
{props.index.conc == -1 ? (
-
+
) : (
-
+
)
}
diff --git a/frontend/src/app/majors/metadata/MetadataUtils.ts b/frontend/src/app/majors/metadata/MetadataUtils.ts
new file mode 100644
index 0000000..ca25948
--- /dev/null
+++ b/frontend/src/app/majors/metadata/MetadataUtils.ts
@@ -0,0 +1,47 @@
+
+import { User, StudentConc } from "@/types/type-user";
+import { Program, MajorsIndex } from "@/types/type-program";
+
+export function toggleConcentrationPin(
+ setUser: Function,
+ progList: Program[],
+ majorsIndex: MajorsIndex
+) {
+ setUser((prevUser: User) => {
+ const existingConcIndex = prevUser.FYP.decl_list.findIndex(
+ (sc) =>
+ sc.conc_majors_index.prog === majorsIndex.prog &&
+ sc.conc_majors_index.deg === majorsIndex.deg &&
+ sc.conc_majors_index.conc === majorsIndex.conc
+ );
+
+ // ✅ If already pinned, remove it (unpin)
+ if (existingConcIndex !== -1) {
+ return {
+ ...prevUser,
+ FYP: {
+ ...prevUser.FYP,
+ decl_list: prevUser.FYP.decl_list.filter((_, idx) => idx !== existingConcIndex),
+ },
+ };
+ }
+
+ // ✅ Otherwise, pin it
+ const newConc = progList[majorsIndex.prog].prog_degs[majorsIndex.deg].deg_concs[majorsIndex.conc];
+
+ const newStudentConc: StudentConc = {
+ conc_majors_index: majorsIndex,
+ user_status: 1, // Assume 1 means pinned
+ user_conc: { ...newConc }, // Clone conc so changes don't affect `progList`
+ user_conc_name: newConc.conc_name,
+ };
+
+ return {
+ ...prevUser,
+ FYP: {
+ ...prevUser.FYP,
+ decl_list: [...prevUser.FYP.decl_list, newStudentConc], // Append to `decl_list`
+ },
+ };
+ });
+}
diff --git a/frontend/src/app/majors/overhead/pinned/Pinned.tsx b/frontend/src/app/majors/overhead/pinned/Pinned.tsx
index 08c163c..f5fd67b 100644
--- a/frontend/src/app/majors/overhead/pinned/Pinned.tsx
+++ b/frontend/src/app/majors/overhead/pinned/Pinned.tsx
@@ -6,8 +6,8 @@ import { User, StudentConc } from "@/types/type-user";
function ConcIcon(props: { user: User, setIndex: Function, studentConc: StudentConc }) {
return(
-
props.setIndex(props.studentConc.majors_index)}>
- 📌{props.user.FYP.prog_list[props.studentConc.majors_index.prog].prog_data.prog_abbr}
+
props.setIndex(props.studentConc.conc_majors_index)}>
+ 📌{props.studentConc.user_conc_name}
);
}
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index 0def287..ebcfb27 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -1,10 +1,13 @@
"use client";
+import { useAuth } from "@/context/AuthProvider";
+import { usePrograms } from "@/context/ProgramProvider";
+
import { useState, useEffect } from "react";
-import { useAuth } from "../providers";
+import Style from "./Majors.module.css";
+
import { MajorsIndex } from "@/types/type-program";
-import Style from "./Majors.module.css";
import NavBar from "@/components/navbar/NavBar";
import Overhead from "./overhead/Overhead";
import Metadata from "./metadata/Metadata";
@@ -13,6 +16,7 @@ import Requirements from "./requirements/Requirements";
function Majors()
{
const { user } = useAuth();
+ const { progList } = usePrograms();
const [index, setIndex] = useState
(null);
@@ -30,26 +34,30 @@ function Majors()
}, [index]);
const updateIndex = (newIndex: MajorsIndex) => {
+ console.log("old");
+ console.log(newIndex);
setIndex((prev) => ({
...prev!,
...newIndex,
prog: newIndex.prog !== undefined
- ? (newIndex.prog + user.FYP.prog_list.length) % user.FYP.prog_list.length
+ ? (newIndex.prog + progList.length) % progList.length
: prev!.prog,
conc: newIndex.conc === -1 ? (prev!.conc === -1 ? 0 : -1) : newIndex.conc,
}));
+ console.log("new");
+ console.log(index);
};
if(index === null) return null;
return(
-
}/>
+ }/>
-
updateIndex({ ...index, conc: -1 })}/>
-
+ updateIndex({ ...index, conc: -1 })}/>
+
-
+
);
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index 2afe981..96dbaa7 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -17,16 +17,17 @@
}
.ReqsList {
- border: 1px solid white;
+ /* border-bottom: 1px solid grey; */
margin-left: 30px;
-/*
- height: 430px;
+
+ /* height: 750px;
scrollbar-color: rgb(131, 131, 131) transparent;
scrollbar-width: thin;
- overflow-y: scroll;
- padding-right: 7px;
- overflow-x: hidden;
-*/
+ overflow-y: scroll; */
+}
+
+.SubreqsList {
+ margin-left: 30px;
}
.ReqHeader {
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 9329609..d647a40 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -1,18 +1,24 @@
"use client";
-import { useAuth } from "@/app/providers";
+import { useAuth } from "@/context/AuthProvider";
+import { usePrograms } from "@/context/ProgramProvider";
-import { useState } from "react";
+import { useState, useEffect } from "react";
import Style from "./Requirements.module.css";
-import { Course } from "@/types/type-user";
-import { ConcentrationSubrequirement, ConcentrationRequirement, DegreeConcentration, MajorsIndex } from "@/types/type-program";
+import { Course, StudentConc } from "@/types/type-user";
+import { ConcentrationSubrequirement, ConcentrationRequirement, MajorsIndex } from "@/types/type-program";
import { removeCourseInSubreq, addCourseInSubreq } from "./RequirementsUtils";
import { MajorsIcon } from "../course-icon/MajorsCourseIcon";
-function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | null; subreq: ConcentrationSubrequirement; onRemoveCourse: Function, onAddCourse: Function })
-{
+function RenderSubrequirementCourse(props: {
+ edit?: boolean;
+ course: Course | null;
+ subreq: ConcentrationSubrequirement;
+ onRemoveCourse: Function,
+ onAddCourse: Function
+}){
const matchingStudentCourse = props.subreq.student_courses_satisfying.find(
(studentCourse) => studentCourse.course === props.course
);
@@ -30,8 +36,13 @@ function RenderSubrequirementCourse(props: { edit?: boolean; course: Course | nu
);
}
-function RenderSubrequirement(props: { edit: boolean, majorsIndex: MajorsIndex, reqIndex: number, subreqIndex: number, subreq: ConcentrationSubrequirement })
-{
+function RenderSubrequirement(props: {
+ edit: boolean,
+ majorsIndex: MajorsIndex,
+ reqIndex: number,
+ subreqIndex: number,
+ subreq: ConcentrationSubrequirement
+}){
const { setUser } = useAuth();
function handleRemoveCourse(course: Course | null, isStudentCourse: boolean = false){
@@ -42,7 +53,14 @@ function RenderSubrequirement(props: { edit: boolean, majorsIndex: MajorsIndex,
return addCourseInSubreq(setUser, props.majorsIndex, props.reqIndex, props.subreqIndex, courseCode);
}
- return (
+ const filteredCourses =
+ props.subreq.student_courses_satisfying.length >= props.subreq.courses_required
+ ? props.subreq.courses_options.filter((course) =>
+ props.subreq.student_courses_satisfying.some((sc) => sc.course === course)
+ )
+ : props.subreq.courses_options;
+
+ return(
{props.subreq.student_courses_satisfying.length}|{props.subreq.courses_required} {props.subreq.subreq_name}
@@ -51,13 +69,12 @@ function RenderSubrequirement(props: { edit: boolean, majorsIndex: MajorsIndex,
{props.subreq.subreq_desc}
- {props.subreq.courses_options.map((course, course_index) => (
+ {filteredCourses.map((course, course_index) => (
@@ -67,8 +84,12 @@ function RenderSubrequirement(props: { edit: boolean, majorsIndex: MajorsIndex,
);
}
-function RenderRequirement(props: { edit: boolean, majorsIndex: MajorsIndex, reqIndex: number, req: ConcentrationRequirement })
-{
+function RenderRequirement(props: {
+ edit: boolean,
+ majorsIndex: MajorsIndex,
+ reqIndex: number,
+ req: ConcentrationRequirement
+}){
return(
@@ -82,14 +103,14 @@ function RenderRequirement(props: { edit: boolean, majorsIndex: MajorsIndex, req
{props.req.req_desc}
-
- {props.req.subreqs_list.map((subreq, subreq_index) => (
+
+ {props.req.subreqs_list.map((subreq, i) => (
))}
@@ -98,31 +119,54 @@ function RenderRequirement(props: { edit: boolean, majorsIndex: MajorsIndex, req
);
}
-function Requirements(props: { conc: DegreeConcentration | null, majorsIndex: MajorsIndex })
-{
- const [edit, setEdit] = useState(false);
-
- if(props.conc == null){
+function Requirements(props: {
+ majorsIndex: MajorsIndex | null
+}){
+ if(props.majorsIndex == null){
return(
-
+
)
}
+ const [edit, setEdit] = useState(false);
+ const { user } = useAuth();
+ const { progList } = usePrograms();
+
+ useEffect(() => {
+ setEdit(false);
+ }, [props.majorsIndex]);
+
+ const userConc = user.FYP.decl_list.find((sc: StudentConc) =>
+ sc.conc_majors_index.prog === props.majorsIndex?.prog &&
+ sc.conc_majors_index.deg === props.majorsIndex?.deg &&
+ sc.conc_majors_index.conc === props.majorsIndex?.conc
+ );
+
+ const conc = userConc ? userConc.user_conc : progList[props.majorsIndex.prog].prog_degs[props.majorsIndex.deg].deg_concs[props.majorsIndex.conc];
+
return(
-
-
Requirements
- {props.conc.user_status == 1 &&
setEdit(!edit)}>⚙
}
+
+
+ Requirements
+
+ {userConc &&
+
setEdit(!edit)}>
+ ⚙
+
+ }
- {props.conc.conc_reqs.map((req, i) => (
-
- ))}
-
+ {conc.conc_reqs.map((req: ConcentrationRequirement, reqIndex: number) => (
+
+ ))}
+
);
}
diff --git a/frontend/src/app/majors/requirements/RequirementsUtils.ts b/frontend/src/app/majors/requirements/RequirementsUtils.ts
index b1b4ca8..df9888f 100644
--- a/frontend/src/app/majors/requirements/RequirementsUtils.ts
+++ b/frontend/src/app/majors/requirements/RequirementsUtils.ts
@@ -10,50 +10,29 @@ function updateUserWithNewSubreq(
subreqIndex: number,
updatedSubreq: ConcentrationSubrequirement
): User {
- const updatedUser = { ...prevUser };
-
- // Directly access the correct structures using indices
- const program = updatedUser.FYP.prog_list[majorsIndex.prog];
- const degree = program.prog_degs[majorsIndex.deg];
- const concentration = degree.deg_concs[majorsIndex.conc];
- const requirement = concentration.conc_reqs[reqIndex];
-
- // ✅ Modify only the affected subrequirement
- const updatedSubreqs = [...requirement.subreqs_list];
- updatedSubreqs[subreqIndex] = updatedSubreq;
-
- // ✅ Modify only the affected requirement
- const updatedConcReqs = [...concentration.conc_reqs];
- updatedConcReqs[reqIndex] = { ...requirement, subreqs_list: updatedSubreqs };
-
- // ✅ Modify only the affected concentration
- const updatedConcentration = { ...concentration, conc_reqs: updatedConcReqs };
-
- // ✅ Modify only the affected degree
- const updatedDegree = {
- ...degree,
- deg_concs: degree.deg_concs.map((conc, idx) =>
- idx === majorsIndex.conc ? updatedConcentration : conc
- )
- };
-
- // ✅ Modify only the affected program
- const updatedProgram = {
- ...program,
- prog_degs: program.prog_degs.map((deg, idx) =>
- idx === majorsIndex.deg ? updatedDegree : deg
- )
- };
-
- // ✅ Modify only the affected user object
return {
- ...updatedUser,
+ ...prevUser,
FYP: {
- ...updatedUser.FYP,
- prog_list: updatedUser.FYP.prog_list.map((prog, idx) =>
- idx === majorsIndex.prog ? updatedProgram : prog
- )
- }
+ ...prevUser.FYP,
+ decl_list: prevUser.FYP.decl_list.map((studentConc) => {
+ if(
+ studentConc.conc_majors_index.prog === majorsIndex.prog &&
+ studentConc.conc_majors_index.deg === majorsIndex.deg &&
+ studentConc.conc_majors_index.conc === majorsIndex.conc
+ ){
+ const updatedConcReqs = studentConc.user_conc.conc_reqs.map((req, idx) =>
+ idx === reqIndex
+ ? { ...req, subreqs_list: req.subreqs_list.map((subreq, sidx) =>
+ sidx === subreqIndex ? updatedSubreq : subreq
+ ) }
+ : req
+ );
+
+ return { ...studentConc, user_conc: { ...studentConc.user_conc, conc_reqs: updatedConcReqs } };
+ }
+ return studentConc;
+ }),
+ },
};
}
@@ -63,46 +42,39 @@ export function addCourseInSubreq(
reqIndex: number,
subreqIndex: number,
courseCode: string
-): boolean {
- let success = false; // ✅ Track success state
-
+) {
setUser((prevUser: User) => {
- const program = prevUser.FYP.prog_list[majorsIndex.prog];
- const degree = program.prog_degs[majorsIndex.deg];
- const concentration = degree.deg_concs[majorsIndex.conc];
- const requirement = concentration.conc_reqs[reqIndex];
+ const userConc = prevUser.FYP.decl_list.find(
+ (sc) => sc.conc_majors_index.prog === majorsIndex.prog &&
+ sc.conc_majors_index.deg === majorsIndex.deg &&
+ sc.conc_majors_index.conc === majorsIndex.conc
+ );
+
+ if (!userConc) return prevUser;
+
+ const requirement = userConc.user_conc.conc_reqs[reqIndex];
const subreq = requirement.subreqs_list[subreqIndex];
- // ✅ Find the StudentCourse that matches the course code
- const matchingStudentCourse = prevUser.FYP.studentCourses.find((studentCourse) =>
- studentCourse.course.codes.includes(courseCode)
+ const matchingStudentCourse = prevUser.FYP.studentCourses.find((sc) =>
+ sc.course.codes.includes(courseCode)
);
- if (!matchingStudentCourse) return prevUser; // 🚨 No update if course doesn't exist
+ if (!matchingStudentCourse) return prevUser;
- // ✅ Find the first null spot in courses_options
const updatedCoursesOptions = [...subreq.courses_options];
const firstNullIndex = updatedCoursesOptions.indexOf(null);
- if (firstNullIndex === -1) return prevUser; // 🚨 No space available, no update
-
- updatedCoursesOptions[firstNullIndex] = matchingStudentCourse.course; // ✅ Replace null with new course
+ if (firstNullIndex === -1) return prevUser;
- // ✅ Add the StudentCourse to `student_courses_satisfying`
- const updatedStudentCourses = [...subreq.student_courses_satisfying, matchingStudentCourse];
+ updatedCoursesOptions[firstNullIndex] = matchingStudentCourse.course;
- // ✅ Create the updated subrequirement
const updatedSubreq = {
...subreq,
courses_options: updatedCoursesOptions,
- student_courses_satisfying: updatedStudentCourses
+ student_courses_satisfying: [...subreq.student_courses_satisfying, matchingStudentCourse],
};
- // ✅ Update state with new data
- success = true; // ✅ Mark operation as successful
return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, updatedSubreq);
});
-
- return success; // ✅ Now properly returns success/failure
}
export function removeCourseInSubreq(
@@ -114,25 +86,26 @@ export function removeCourseInSubreq(
isStudentCourse?: boolean
) {
setUser((prevUser: User) => {
- const program = prevUser.FYP.prog_list[majorsIndex.prog];
- const degree = program.prog_degs[majorsIndex.deg];
- const concentration = degree.deg_concs[majorsIndex.conc];
- const requirement = concentration.conc_reqs[reqIndex];
+ const userConc = prevUser.FYP.decl_list.find(
+ (sc) => sc.conc_majors_index.prog === majorsIndex.prog &&
+ sc.conc_majors_index.deg === majorsIndex.deg &&
+ sc.conc_majors_index.conc === majorsIndex.conc
+ );
+
+ if (!userConc) return prevUser; // 🚨 Safety check
+
+ const requirement = userConc.user_conc.conc_reqs[reqIndex];
const subreq = requirement.subreqs_list[subreqIndex];
- // ✅ Modify `courses_options` directly
- const updatedCoursesOptions = [...subreq.courses_options];
- const courseIndex = updatedCoursesOptions.indexOf(course);
- if (courseIndex !== -1) {
- updatedCoursesOptions[courseIndex] = null;
- }
+ // ✅ Modify `courses_options`
+ const updatedCoursesOptions = subreq.courses_options.map((c) => (c === course ? null : c));
- // ✅ Filter out StudentCourse if necessary
+ // ✅ Modify `student_courses_satisfying`
const updatedStudentCourses = isStudentCourse
? subreq.student_courses_satisfying.filter((sc) => sc.course !== course)
: subreq.student_courses_satisfying;
- // ✅ Create the updated subrequirement
+ // ✅ Create updated subrequirement
const updatedSubreq = {
...subreq,
courses_options: updatedCoursesOptions,
diff --git a/frontend/src/app/not-found.tsx b/frontend/src/app/not-found.tsx
index 0b7ddd6..f8da259 100644
--- a/frontend/src/app/not-found.tsx
+++ b/frontend/src/app/not-found.tsx
@@ -2,7 +2,7 @@
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
-import { useAuth } from "@/app/providers";
+import { useAuth } from "@/context/AuthProvider";
export default function NotFoundPage() {
const { auth } = useAuth();
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 839aa68..b58e4b4 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -2,7 +2,7 @@
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
-import { useAuth } from "./providers";
+import { useAuth } from "@/context/AuthProvider";
export default function MajorAudit()
{
diff --git a/frontend/src/app/providers.tsx b/frontend/src/context/AuthProvider.tsx
similarity index 92%
rename from frontend/src/app/providers.tsx
rename to frontend/src/context/AuthProvider.tsx
index a1e9310..18c0e5a 100644
--- a/frontend/src/app/providers.tsx
+++ b/frontend/src/context/AuthProvider.tsx
@@ -12,7 +12,6 @@ export function AuthProvider({ children }: { children: React.ReactNode })
const [auth, setAuth] = useState({ loggedIn: false });
const [user, setUser] = useState
(Ryan);
- // uh this isnt right
useEffect(() => {
setUser(Ryan);
}, []);
@@ -24,6 +23,6 @@ export function AuthProvider({ children }: { children: React.ReactNode })
);
}
-export function useAuth() {
+export function useAuth(){
return useContext(AuthContext);
}
diff --git a/frontend/src/context/ProgramProvider.tsx b/frontend/src/context/ProgramProvider.tsx
new file mode 100644
index 0000000..fc19e32
--- /dev/null
+++ b/frontend/src/context/ProgramProvider.tsx
@@ -0,0 +1,27 @@
+
+"use client";
+import { createContext, useContext, useState, useEffect } from "react";
+import { Program } from "@/types/type-program";
+
+import { PROG_LIST } from "@/database/programs/data-program";
+
+const ProgramContext = createContext<{ progList: Program[] }>({ progList: [] });
+
+export function ProgramProvider({ children }: { children: React.ReactNode }) {
+
+ const [progList, setProgList] = useState([]);
+
+ useEffect(() => {
+ setProgList(PROG_LIST)
+ }, []);
+
+ return(
+
+ {children}
+
+ );
+}
+
+export function usePrograms() {
+ return useContext(ProgramContext);
+}
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index ed59de3..0b56db5 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -1,8 +1,9 @@
import { User } from "./../types/type-user";
-import { PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC } from "./programs/data-program";
import { SC_CPSC_201 } from "./data-courses";
+import { CONC_CPSC_BS_I } from "./programs/concs/concs-cpsc";
+
export const Ryan: User = {
name: "Ryan",
netID: "rgg32",
@@ -16,33 +17,13 @@ export const Ryan: User = {
senior: [0, 202703, 202801],
},
languagePlacement: { language: "Spanish", level: 5 },
- prog_list: [PROG_CPSC, PROG_ECON, PROG_HIST, PROG_PLSC],
- decl_list: [{ user_status: 1, majors_index: { conc: 0, deg: 0, prog: 0 } }],
+ decl_list: [
+ {
+ conc_majors_index: { conc: 0, deg: 1, prog: 0 }, // check
+ user_status: 1,
+ user_conc: CONC_CPSC_BS_I,
+ user_conc_name: "cpsc bs",
+ }
+ ],
}
}
-
-// export const NullUser: User = {
-// name: "",
-// netID: "",
-// onboard: false,
-// FYP: {
-// studentCourses: [],
-// studentTermArrangement: {
-// first_year: [],
-// sophomore: [],
-// junior: [],
-// senior: [],
-// },
-// languagePlacement: { language: "", level: 0 },
-// degreeDeclarations: [],
-// degreeConfigurations: [
-// [],
-// [],
-// [],
-// []
-// ],
-// }
-// }
-
-
-
diff --git a/frontend/src/database/programs/concs/concs-cpsc.ts b/frontend/src/database/programs/concs/concs-cpsc.ts
index 7095d2e..fafb5bd 100644
--- a/frontend/src/database/programs/concs/concs-cpsc.ts
+++ b/frontend/src/database/programs/concs/concs-cpsc.ts
@@ -11,7 +11,7 @@ const CORE_INTRO: ConcentrationSubrequirement = {
courses_required: 1,
courses_options: [CPSC_201],
courses_elective_range: null,
- courses_any_bool: false,
+ courses_any_bool: true,
student_courses_satisfying: [],
}
diff --git a/frontend/src/database/programs/data-program.ts b/frontend/src/database/programs/data-program.ts
index d56d96b..f590c22 100644
--- a/frontend/src/database/programs/data-program.ts
+++ b/frontend/src/database/programs/data-program.ts
@@ -5,7 +5,7 @@ import { CONC_ECON_BA_I } from "./concs/concs-econ";
import { CONC_HIST_BA_GLOB, CONC_HIST_BA_SPEC } from "./concs/concs-hist";
import { CONC_PLSC_BA_INTE, CONC_PLSC_BA_STAN } from "./concs/concs-plsc";
-export const PROG_CPSC: Program = {
+const PROG_CPSC: Program = {
prog_data: {
prog_name: "Computer Science",
prog_abbr: "CPSC",
@@ -20,7 +20,7 @@ export const PROG_CPSC: Program = {
]
}
-export const PROG_ECON: Program = {
+const PROG_ECON: Program = {
prog_data: {
prog_name: "Economics",
prog_abbr: "ECON",
@@ -34,7 +34,7 @@ export const PROG_ECON: Program = {
]
}
-export const PROG_PLSC: Program = {
+const PROG_PLSC: Program = {
prog_data: {
prog_name: "Political Science",
prog_abbr: "PLSC",
@@ -48,7 +48,7 @@ export const PROG_PLSC: Program = {
]
}
-export const PROG_HIST: Program = {
+const PROG_HIST: Program = {
prog_data: {
prog_name: "History",
prog_abbr: "HIST",
@@ -64,3 +64,7 @@ export const PROG_HIST: Program = {
}
]
}
+
+export const PROG_LIST: Program[] = [
+ PROG_CPSC, PROG_ECON, PROG_PLSC, PROG_HIST
+]
diff --git a/frontend/src/types/type-user.ts b/frontend/src/types/type-user.ts
index 3700ec7..a0549a0 100644
--- a/frontend/src/types/type-user.ts
+++ b/frontend/src/types/type-user.ts
@@ -1,5 +1,5 @@
-import { MajorsIndex, Program } from "./type-program";
+import { DegreeConcentration, MajorsIndex, Program } from "./type-program";
export interface LanguagePlacement {
language: string;
@@ -39,15 +39,16 @@ export interface StudentTermArrangement {
}
export interface StudentConc {
+ conc_majors_index: MajorsIndex;
user_status: number;
- majors_index: MajorsIndex;
+ user_conc: DegreeConcentration;
+ user_conc_name: string;
}
export interface FYP {
languagePlacement: LanguagePlacement;
studentCourses: StudentCourse[];
studentTermArrangement: StudentTermArrangement;
- prog_list: Program[];
decl_list: StudentConc[];
}
From 9c6eb92d6daf314ffc386fb6d74906178037a096 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Fri, 14 Mar 2025 15:21:06 -0700
Subject: [PATCH 26/38] subreq selection
---
.../majors/course-icon/MajorsCourseIcon.tsx | 2 +-
.../src/app/majors/metadata/MetadataUtils.ts | 3 +-
frontend/src/app/majors/page.tsx | 4 -
.../requirements/Requirements.module.css | 42 ++++-
.../app/majors/requirements/Requirements.tsx | 37 ++++-
.../majors/requirements/RequirementsUtils.ts | 154 ++++++++++++------
frontend/src/database/data-user.ts | 11 +-
.../src/database/programs/concs/concs-cpsc.ts | 4 +-
.../src/database/programs/concs/concs-hist.ts | 2 +-
frontend/src/types/type-program.ts | 2 +
frontend/src/types/type-user.ts | 1 +
11 files changed, 190 insertions(+), 72 deletions(-)
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
index dcff863..e0b7b45 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -116,7 +116,7 @@ function MajorsEmptyIcon(props: { edit: boolean, onAddCourse: Function })
{props.edit ? (
<>
-
setIsAdding(true)}>
+
setIsAdding(true)}>
diff --git a/frontend/src/app/majors/metadata/MetadataUtils.ts b/frontend/src/app/majors/metadata/MetadataUtils.ts
index ca25948..290f7fb 100644
--- a/frontend/src/app/majors/metadata/MetadataUtils.ts
+++ b/frontend/src/app/majors/metadata/MetadataUtils.ts
@@ -32,8 +32,9 @@ export function toggleConcentrationPin(
const newStudentConc: StudentConc = {
conc_majors_index: majorsIndex,
user_status: 1, // Assume 1 means pinned
- user_conc: { ...newConc }, // Clone conc so changes don't affect `progList`
+ user_conc: { ...newConc },
user_conc_name: newConc.conc_name,
+ selected_subreqs: {},
};
return {
diff --git a/frontend/src/app/majors/page.tsx b/frontend/src/app/majors/page.tsx
index ebcfb27..6feb588 100644
--- a/frontend/src/app/majors/page.tsx
+++ b/frontend/src/app/majors/page.tsx
@@ -34,8 +34,6 @@ function Majors()
}, [index]);
const updateIndex = (newIndex: MajorsIndex) => {
- console.log("old");
- console.log(newIndex);
setIndex((prev) => ({
...prev!,
...newIndex,
@@ -44,8 +42,6 @@ function Majors()
: prev!.prog,
conc: newIndex.conc === -1 ? (prev!.conc === -1 ? 0 : -1) : newIndex.conc,
}));
- console.log("new");
- console.log(index);
};
if(index === null) return null;
diff --git a/frontend/src/app/majors/requirements/Requirements.module.css b/frontend/src/app/majors/requirements/Requirements.module.css
index 96dbaa7..62c7ced 100644
--- a/frontend/src/app/majors/requirements/Requirements.module.css
+++ b/frontend/src/app/majors/requirements/Requirements.module.css
@@ -50,6 +50,18 @@
margin-bottom: 4px;
}
+
+
+
+
+
+
+
+
+
+
+
+
.ToggleButton {
margin-top: 3px;
@@ -66,7 +78,17 @@
margin-bottom: 2px;
}
-.SubreqButton {
+
+
+
+.SubreqSelectionRow {
+ display: flex;
+ gap: 5px;
+ margin-bottom: 8px;
+ flex-wrap: wrap;
+}
+
+.SubreqOption {
font-size: 10px;
padding: 3px;
@@ -78,12 +100,28 @@
transition: background-color 0.3s ease;
}
-.SubreqButton.Selected {
+.SubreqOption.Selected {
background-color: rgb(100, 178, 238);
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
.RequirementsContainerHeader {
display: flex;
flex-direction: row;
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index d647a40..5118c09 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -9,7 +9,7 @@ import Style from "./Requirements.module.css";
import { Course, StudentConc } from "@/types/type-user";
import { ConcentrationSubrequirement, ConcentrationRequirement, MajorsIndex } from "@/types/type-program";
-import { removeCourseInSubreq, addCourseInSubreq } from "./RequirementsUtils";
+import { getStudentConcentration, removeCourseInSubreq, addCourseInSubreq, toggleSubreqSelection } from "./RequirementsUtils";
import { MajorsIcon } from "../course-icon/MajorsCourseIcon";
function RenderSubrequirementCourse(props: {
@@ -90,6 +90,20 @@ function RenderRequirement(props: {
reqIndex: number,
req: ConcentrationRequirement
}){
+ const { user, setUser } = useAuth();
+ const userConc = getStudentConcentration(user, props.majorsIndex);
+ const selectedSubreqs = userConc?.selected_subreqs[props.reqIndex] ?? [];
+
+ const visibleSubreqs = selectedSubreqs.length > 0
+ ? props.req.subreqs_list.filter((_, i) => selectedSubreqs.includes(i))
+ : props.req.subreqs_list;
+
+ function handleToggleSubreq(subreqIndex: number) {
+ if(userConc){
+ toggleSubreqSelection(setUser, props.majorsIndex, props.reqIndex, subreqIndex, props.req.subreqs_required_count ?? props.req.subreqs_list.length);
+ }
+ }
+
return(
@@ -103,14 +117,29 @@ function RenderRequirement(props: {
{props.req.req_desc}
+
+ {(props.req.subreqs_required_count !== undefined && props.req.subreqs_required_count < props.req.subreqs_list.length) && (
+
+ {props.req.subreqs_list.map((subreq, i) => (
+
handleToggleSubreq(i)}
+ >
+ {subreq.subreq_name}
+
+ ))}
+
+ )}
+
- {props.req.subreqs_list.map((subreq, i) => (
+ {visibleSubreqs.map((subreq, subreqIndex) => (
))}
diff --git a/frontend/src/app/majors/requirements/RequirementsUtils.ts b/frontend/src/app/majors/requirements/RequirementsUtils.ts
index df9888f..4eeb2be 100644
--- a/frontend/src/app/majors/requirements/RequirementsUtils.ts
+++ b/frontend/src/app/majors/requirements/RequirementsUtils.ts
@@ -1,8 +1,20 @@
import { MajorsIndex } from "@/types/type-program";
-import { Course, User } from "@/types/type-user";
+import { Course, User, StudentConc } from "@/types/type-user";
import { ConcentrationSubrequirement } from "@/types/type-program";
+export function getStudentConcentration(
+ user: User,
+ majorsIndex: MajorsIndex
+): StudentConc | undefined {
+ return user.FYP.decl_list.find(
+ (sc) =>
+ sc.conc_majors_index.prog === majorsIndex.prog &&
+ sc.conc_majors_index.deg === majorsIndex.deg &&
+ sc.conc_majors_index.conc === majorsIndex.conc
+ );
+}
+
function updateUserWithNewSubreq(
prevUser: User,
majorsIndex: MajorsIndex,
@@ -10,28 +22,33 @@ function updateUserWithNewSubreq(
subreqIndex: number,
updatedSubreq: ConcentrationSubrequirement
): User {
+ const matchingConc = getStudentConcentration(prevUser, majorsIndex);
+ if (!matchingConc) return prevUser;
+
return {
...prevUser,
FYP: {
...prevUser.FYP,
- decl_list: prevUser.FYP.decl_list.map((studentConc) => {
- if(
- studentConc.conc_majors_index.prog === majorsIndex.prog &&
- studentConc.conc_majors_index.deg === majorsIndex.deg &&
- studentConc.conc_majors_index.conc === majorsIndex.conc
- ){
- const updatedConcReqs = studentConc.user_conc.conc_reqs.map((req, idx) =>
- idx === reqIndex
- ? { ...req, subreqs_list: req.subreqs_list.map((subreq, sidx) =>
- sidx === subreqIndex ? updatedSubreq : subreq
- ) }
- : req
- );
-
- return { ...studentConc, user_conc: { ...studentConc.user_conc, conc_reqs: updatedConcReqs } };
- }
- return studentConc;
- }),
+ decl_list: prevUser.FYP.decl_list.map((studentConc) =>
+ studentConc === matchingConc
+ ? {
+ ...studentConc,
+ user_conc: {
+ ...studentConc.user_conc,
+ conc_reqs: studentConc.user_conc.conc_reqs.map((req, idx) =>
+ idx === reqIndex
+ ? {
+ ...req,
+ subreqs_list: req.subreqs_list.map((subreq, sidx) =>
+ sidx === subreqIndex ? updatedSubreq : subreq
+ ),
+ }
+ : req
+ ),
+ },
+ }
+ : studentConc
+ ),
},
};
}
@@ -42,14 +59,9 @@ export function addCourseInSubreq(
reqIndex: number,
subreqIndex: number,
courseCode: string
-) {
+){
setUser((prevUser: User) => {
- const userConc = prevUser.FYP.decl_list.find(
- (sc) => sc.conc_majors_index.prog === majorsIndex.prog &&
- sc.conc_majors_index.deg === majorsIndex.deg &&
- sc.conc_majors_index.conc === majorsIndex.conc
- );
-
+ const userConc = getStudentConcentration(prevUser, majorsIndex);
if (!userConc) return prevUser;
const requirement = userConc.user_conc.conc_reqs[reqIndex];
@@ -67,13 +79,11 @@ export function addCourseInSubreq(
updatedCoursesOptions[firstNullIndex] = matchingStudentCourse.course;
- const updatedSubreq = {
+ return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, {
...subreq,
courses_options: updatedCoursesOptions,
student_courses_satisfying: [...subreq.student_courses_satisfying, matchingStudentCourse],
- };
-
- return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, updatedSubreq);
+ });
});
}
@@ -84,34 +94,84 @@ export function removeCourseInSubreq(
subreqIndex: number,
course: Course | null,
isStudentCourse?: boolean
-) {
+){
setUser((prevUser: User) => {
- const userConc = prevUser.FYP.decl_list.find(
- (sc) => sc.conc_majors_index.prog === majorsIndex.prog &&
- sc.conc_majors_index.deg === majorsIndex.deg &&
- sc.conc_majors_index.conc === majorsIndex.conc
- );
-
- if (!userConc) return prevUser; // 🚨 Safety check
+ const userConc = getStudentConcentration(prevUser, majorsIndex);
+ if (!userConc) return prevUser;
const requirement = userConc.user_conc.conc_reqs[reqIndex];
const subreq = requirement.subreqs_list[subreqIndex];
- // ✅ Modify `courses_options`
- const updatedCoursesOptions = subreq.courses_options.map((c) => (c === course ? null : c));
-
- // ✅ Modify `student_courses_satisfying`
+ // ✅ Remove student course
const updatedStudentCourses = isStudentCourse
? subreq.student_courses_satisfying.filter((sc) => sc.course !== course)
: subreq.student_courses_satisfying;
- // ✅ Create updated subrequirement
- const updatedSubreq = {
+ // ✅ Remove the course & ensure nulls don't exceed `courses_required`
+ let updatedCoursesOptions = subreq.courses_options.map((c) => (c === course ? null : c));
+ const nullCount = updatedCoursesOptions.filter((c) => c === null).length;
+
+ if (nullCount > subreq.courses_required) {
+ updatedCoursesOptions = updatedCoursesOptions.filter((c) => c !== null);
+ updatedCoursesOptions = [...updatedCoursesOptions, ...Array(subreq.courses_required).fill(null)];
+ }
+
+ return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, {
...subreq,
courses_options: updatedCoursesOptions,
- student_courses_satisfying: updatedStudentCourses
- };
+ student_courses_satisfying: updatedStudentCourses,
+ });
+ });
+}
+
+export function toggleSubreqSelection(
+ setUser: Function,
+ majorsIndex: MajorsIndex,
+ reqIndex: number,
+ subreqIndex: number,
+ maxSelected: number
+) {
+ setUser((prevUser: User) => {
+ // ✅ Find the matching concentration
+ const userConc = getStudentConcentration(prevUser, majorsIndex);
+ if (!userConc) return prevUser; // 🚨 Safety check
+
+ // ✅ Create a fresh copy of selected_subreqs
+ const updatedSelectedSubreqs = { ...userConc.selected_subreqs };
- return updateUserWithNewSubreq(prevUser, majorsIndex, reqIndex, subreqIndex, updatedSubreq);
+ // ✅ Get currently selected subreqs or default to an empty array
+ const currentSelected = updatedSelectedSubreqs[reqIndex] ?? [];
+
+ let newSelected = [...currentSelected];
+
+ if (newSelected.includes(subreqIndex)) {
+ // ✅ Remove if already selected
+ newSelected = newSelected.filter((i) => i !== subreqIndex);
+ } else if (newSelected.length < maxSelected) {
+ // ✅ Add if under max limit
+ newSelected.push(subreqIndex);
+ }
+
+ // ✅ Ensure `selected_subreqs` is always properly structured
+ updatedSelectedSubreqs[reqIndex] = newSelected.length > 0 ? newSelected : [];
+
+ // ✅ Return a fully **new** user object with updates applied
+ return {
+ ...prevUser,
+ FYP: {
+ ...prevUser.FYP,
+ decl_list: prevUser.FYP.decl_list.map((studentConc) =>
+ studentConc.conc_majors_index.prog === majorsIndex.prog &&
+ studentConc.conc_majors_index.deg === majorsIndex.deg &&
+ studentConc.conc_majors_index.conc === majorsIndex.conc
+ ? {
+ ...studentConc,
+ selected_subreqs: updatedSelectedSubreqs, // ✅ Fully replace with new object
+ }
+ : studentConc
+ ),
+ },
+ };
});
}
+
diff --git a/frontend/src/database/data-user.ts b/frontend/src/database/data-user.ts
index 0b56db5..ddd65f6 100644
--- a/frontend/src/database/data-user.ts
+++ b/frontend/src/database/data-user.ts
@@ -2,8 +2,6 @@
import { User } from "./../types/type-user";
import { SC_CPSC_201 } from "./data-courses";
-import { CONC_CPSC_BS_I } from "./programs/concs/concs-cpsc";
-
export const Ryan: User = {
name: "Ryan",
netID: "rgg32",
@@ -17,13 +15,6 @@ export const Ryan: User = {
senior: [0, 202703, 202801],
},
languagePlacement: { language: "Spanish", level: 5 },
- decl_list: [
- {
- conc_majors_index: { conc: 0, deg: 1, prog: 0 }, // check
- user_status: 1,
- user_conc: CONC_CPSC_BS_I,
- user_conc_name: "cpsc bs",
- }
- ],
+ decl_list: [],
}
}
diff --git a/frontend/src/database/programs/concs/concs-cpsc.ts b/frontend/src/database/programs/concs/concs-cpsc.ts
index fafb5bd..16f8c85 100644
--- a/frontend/src/database/programs/concs/concs-cpsc.ts
+++ b/frontend/src/database/programs/concs/concs-cpsc.ts
@@ -21,7 +21,7 @@ const CORE_MATH: ConcentrationSubrequirement = {
courses_required: 1,
courses_options: [CPSC_202, MATH_244],
courses_elective_range: null,
- courses_any_bool: false,
+ courses_any_bool: true,
student_courses_satisfying: [],
}
@@ -31,7 +31,7 @@ const CORE_DATA: ConcentrationSubrequirement = {
courses_required: 1,
courses_options: [CPSC_223],
courses_elective_range: null,
- courses_any_bool: false,
+ courses_any_bool: true,
student_courses_satisfying: [SC_CPSC_223],
}
diff --git a/frontend/src/database/programs/concs/concs-hist.ts b/frontend/src/database/programs/concs/concs-hist.ts
index 218b063..2d8700a 100644
--- a/frontend/src/database/programs/concs/concs-hist.ts
+++ b/frontend/src/database/programs/concs/concs-hist.ts
@@ -8,7 +8,7 @@ const PRE_REQ: ConcentrationSubrequirement = {
courses_required: 2,
courses_options: [null, null],
courses_elective_range: null,
- courses_any_bool: false,
+ courses_any_bool: true,
student_courses_satisfying: [],
}
diff --git a/frontend/src/types/type-program.ts b/frontend/src/types/type-program.ts
index 62a1b5e..e42cd81 100644
--- a/frontend/src/types/type-program.ts
+++ b/frontend/src/types/type-program.ts
@@ -21,6 +21,8 @@ export interface ConcentrationSubrequirement {
flags?: string[];
student_courses_satisfying: StudentCourse[];
+
+ // selected?: boolean;
}
export interface ConcentrationRequirement {
diff --git a/frontend/src/types/type-user.ts b/frontend/src/types/type-user.ts
index a0549a0..cdd89ac 100644
--- a/frontend/src/types/type-user.ts
+++ b/frontend/src/types/type-user.ts
@@ -43,6 +43,7 @@ export interface StudentConc {
user_status: number;
user_conc: DegreeConcentration;
user_conc_name: string;
+ selected_subreqs: Record
;
}
export interface FYP {
From c1ee832b71867d85ebb59d5a5ca6ebbe7509bf5e Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Fri, 14 Mar 2025 15:57:19 -0700
Subject: [PATCH 27/38] dyn req count
---
frontend/src/app/majors/Majors.module.css | 24 +++++++++++++++++++
.../app/majors/requirements/Requirements.tsx | 14 +++++++++--
.../src/database/programs/concs/concs-hist.ts | 2 +-
.../src/database/programs/concs/concs-plsc.ts | 2 +-
4 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/frontend/src/app/majors/Majors.module.css b/frontend/src/app/majors/Majors.module.css
index 42209e4..28296f4 100644
--- a/frontend/src/app/majors/Majors.module.css
+++ b/frontend/src/app/majors/Majors.module.css
@@ -25,6 +25,7 @@
.ListButton {
position: fixed;
+ cursor: pointer;
top: 95px;
left: 20px;
@@ -42,5 +43,28 @@
border-radius: 50%;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25);
+ z-index: 2;
+}
+
+.FilterButton {
+ position: fixed;
+ cursor: pointer;
+
+ top: 140px;
+ left: 20px;
+
+ width: 30px;
+ height: 30px;
+
+ color: white;
+ text-align: center;
+ line-height: 30px;
+ font-size: 20px;
+
+ background-color: #61fe73;
+ border: none;
+ border-radius: 50%;
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25);
+
z-index: 2;
}
\ No newline at end of file
diff --git a/frontend/src/app/majors/requirements/Requirements.tsx b/frontend/src/app/majors/requirements/Requirements.tsx
index 5118c09..01e6fce 100644
--- a/frontend/src/app/majors/requirements/Requirements.tsx
+++ b/frontend/src/app/majors/requirements/Requirements.tsx
@@ -104,6 +104,13 @@ function RenderRequirement(props: {
}
}
+ let dynamicRequiredCount: number | string = props.req.courses_required_count;
+ if (props.req.courses_required_count === -1) {
+ dynamicRequiredCount = selectedSubreqs.length > 0
+ ? selectedSubreqs.reduce((sum, idx) => sum + props.req.subreqs_list[idx].courses_required, 0)
+ : "~";
+ }
+
return(
@@ -111,8 +118,11 @@ function RenderRequirement(props: {
{props.req.req_name}
- {props.req.checkbox !== undefined ? props.req.courses_satisfied_count === props.req.courses_required_count ? "✅" : "❌" : `${props.req.courses_satisfied_count}|${props.req.courses_required_count}`}
-
+ {props.req.checkbox !== undefined
+ ? props.req.courses_satisfied_count === props.req.courses_required_count ? "✅" : "❌"
+ : `${props.req.courses_satisfied_count}|${dynamicRequiredCount}`
+ }
+
{props.req.req_desc}
diff --git a/frontend/src/database/programs/concs/concs-hist.ts b/frontend/src/database/programs/concs/concs-hist.ts
index 2d8700a..39ce192 100644
--- a/frontend/src/database/programs/concs/concs-hist.ts
+++ b/frontend/src/database/programs/concs/concs-hist.ts
@@ -211,7 +211,7 @@ const SEN_TWO: ConcentrationSubrequirement = {
const HIST_SEN: ConcentrationRequirement = {
req_name: "SENIOR",
req_desc: "",
- courses_required_count: 0,
+ courses_required_count: -1,
courses_satisfied_count: 0,
subreqs_required_count: 1,
subreqs_satisfied_count: 0,
diff --git a/frontend/src/database/programs/concs/concs-plsc.ts b/frontend/src/database/programs/concs/concs-plsc.ts
index 06c0054..e3bee47 100644
--- a/frontend/src/database/programs/concs/concs-plsc.ts
+++ b/frontend/src/database/programs/concs/concs-plsc.ts
@@ -178,7 +178,7 @@ const SEN_STAN_TWO: ConcentrationSubrequirement = {
const PLSC_SEN_STAN: ConcentrationRequirement = {
req_name: "SENIOR",
req_desc: "",
- courses_required_count: 0,
+ courses_required_count: -1,
courses_satisfied_count: 0,
subreqs_required_count: 1,
subreqs_satisfied_count: 0,
From 5fb1cf3131c92f62ce1377a091a5fc007fddbc41 Mon Sep 17 00:00:00 2001
From: RyanGumlia
Date: Fri, 14 Mar 2025 17:50:34 -0700
Subject: [PATCH 28/38] addable course back
---
.../course-icon/MajorsCourseIcon.module.css | 87 ++++++--------
.../majors/course-icon/MajorsCourseIcon.tsx | 113 ++++++++++--------
.../src/database/programs/concs/concs-econ.ts | 4 +-
3 files changed, 106 insertions(+), 98 deletions(-)
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
index 13a33a4..c6ffe4e 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.module.css
@@ -1,7 +1,4 @@
- /* */
- /* min-height: 18px; */
-
.Icon {
display: flex;
flex-direction: row;
@@ -12,14 +9,15 @@
font-size: 14px;
font-weight: bold;
- width: max-content;
- height: max-content;
-
padding: 2px 4px;
border-radius: 15px;
+ width: max-content;
+ min-width: 14px;
+ height: 18px;
+
background-color: #F5F5F5;
- transition: filter 0.4s ease;
+ transition: filter 0.3s ease;
}
.Icon:hover {
@@ -48,57 +46,48 @@
-
-
-
-
-.IconContainer {
- position: relative;
- display: inline-block;
-}
-
-.EmptyIcon {
- width: 20px;
- height: 20px;
+.AddButton {
display: flex;
align-items: center;
justify-content: center;
- border-radius: 50%;
- background-color: #f5f5f5;
- cursor: default;
-}
-.EmptyIcon:hover {
+ width: 22px;
+ height: 22px;
+
+ font-size: 12px;
+ font-weight: bold;
+
+ border-radius: 50%;
+ background-color: #F5F5F5;
+
cursor: pointer;
- background-color: #e0e0e0;
+ overflow: hidden;
}
-.AddCoursePopup {
- position: absolute;
- top: 22px;
- left: 50%;
- transform: translateX(-50%);
- background: white;
- border: 1px solid #ddd;
- padding: 6px;
- box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
+.AddCanvas {
display: flex;
+ flex-direction: row;
align-items: center;
- border-radius: 5px;
- z-index: 10;
- width: fit-content;
- min-width: 60px;
-}
-.AddCoursePopup input {
- width: 75px;
- padding: 2px;
- border: 1px solid #ccc;
- border-radius: 4px;
- font-size: 12px;
-}
+ height: 20px;
+ width: 90px;
-.ConfirmButton {
- cursor: pointer;
- color: green;
+ background-color: #F5F5F5;
+ border-radius: 15px;
+ padding: 1px 4px;
}
+
+.CodeSearch {
+ height: 14px;
+ width: 70px;
+
+ font-size: 12px; /* Matching font size */
+ padding: 1px;
+
+ border: none;
+ outline: none;
+ background-color: white;
+ color: black;
+
+ border-radius: 3px; /* Makes it a circle */
+}
\ No newline at end of file
diff --git a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
index e0b7b45..2c82f80 100644
--- a/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
+++ b/frontend/src/app/majors/course-icon/MajorsCourseIcon.tsx
@@ -2,16 +2,18 @@
import { useState, useRef, useEffect } from "react";
import Style from "./MajorsCourseIcon.module.css"
+import Image from "next/image";
+
import { ConcentrationSubrequirement } from "@/types/type-program";
import { StudentCourse, Course } from "@/types/type-user";
import DistributionCircle from "@/components/distribution-circle/DistributionsCircle";
-
-function CourseSeasonIcon(props: { seasons: Array }) {
+function SeasonComp(props: { seasons: string[] })
+{
const seasonImageMap: { [key: string]: string } = {
- "Fall": "./fall.svg",
- "Spring": "./spring.svg",
+ "Fall": "/fall.svg",
+ "Spring": "/spring.svg",
};
return (
@@ -19,10 +21,11 @@ function CourseSeasonIcon(props: { seasons: Array }) {
{props.seasons.map((szn, index) => (
0 ? "-7.5px" : 0 }}>
{seasonImageMap[szn] && (
-
)}
@@ -31,25 +34,27 @@ function CourseSeasonIcon(props: { seasons: Array }) {
);
}
-function MajorsCourseIcon(props: {
+function CourseIcon(props: {
edit: boolean;
course: Course;
subreq: ConcentrationSubrequirement;
onRemoveCourse: Function;
-}) {
+}){
return (
{props.edit && (
props.onRemoveCourse(props.course, props.subreq, false)} />
)}
-
+
{props.course.codes[0]}
-
+