From 1be1031c79d455d5f6fd64994fd2f42b7dfbf0b3 Mon Sep 17 00:00:00 2001 From: midhun-sadanand <128321084+midhun-sadanand@users.noreply.github.com> Date: Sun, 28 Jul 2024 18:50:17 +0100 Subject: [PATCH 1/4] Temporary commit with initial Onboard UI edits --- backend/main.py | 8 +- firebase.json | 2 +- frontend/src/pages/Onboard/Onboard.module.css | 112 +++++-- frontend/src/pages/Onboard/Onboard.tsx | 285 +++++++++--------- 4 files changed, 247 insertions(+), 160 deletions(-) diff --git a/backend/main.py b/backend/main.py index 563f15b..287809a 100644 --- a/backend/main.py +++ b/backend/main.py @@ -31,12 +31,12 @@ # Ryan from course import * -cred = credentials.Certificate(r'secrets/majoraudit-firebase-adminsdk-bc6kc-6e9544580c.json') +cred = credentials.Certificate(r'secrets/majoraudit-firebase-adminsdk-bc6kc-2898e677ae.json') app = firebase_admin.initialize_app(cred) db = firestore.client() -allowed_CORS_origins=['http://127.0.0.1:3000', 'http://127.0.0.1:3000/graduation', 'http://127.0.0.1:3000/courses', 'http://127.0.0.1:3000/onboard', 'http://127.0.0.1:5000'] +allowed_CORS_origins=['http://127.0.0.1:5000', 'http://127.0.0.1:5000/graduation', 'http://127.0.0.1:5000/login', 'http://127.0.0.1:5000/courses', 'http://127.0.0.1:5000/onboard', 'http://127.0.0.1:5000'] class User: def __init__(self, netID, onboard, name, degrees, studentCourses, language): @@ -60,7 +60,7 @@ def login(): cookies={} if 'NETID' in session: - redirect_url = 'http://127.0.0.1:3000' + redirect_url = 'http://127.0.0.1:5000' current_app.logger.info(f'Redirecting: {redirect_url}') resp = make_response(redirect(redirect_url)) @@ -96,7 +96,7 @@ def login(): ) db.collection("Users").document(netID).set(new_user.__dict__) - redirect_url = 'http://127.0.0.1:3000' + redirect_url = 'http://127.0.0.1:5000' else: token=session['CAS_TOKEN'] diff --git a/firebase.json b/firebase.json index 2817460..8b088da 100644 --- a/firebase.json +++ b/firebase.json @@ -47,7 +47,7 @@ "port": 9000 }, "hosting": { - "port": 3000 + "port": 5000 }, "pubsub": { "port": 8085 diff --git a/frontend/src/pages/Onboard/Onboard.module.css b/frontend/src/pages/Onboard/Onboard.module.css index e970dfe..c0f01ef 100644 --- a/frontend/src/pages/Onboard/Onboard.module.css +++ b/frontend/src/pages/Onboard/Onboard.module.css @@ -1,26 +1,104 @@ +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap'); - -.Row { - display: flex; - flex-direction: row; +/* UTIL */ +.row { + display: flex; + flex-direction: row; + gap: 20px; + margin-top: 20px; } -.Column { - display: flex; - flex-direction: column; +.column { + display: flex; + flex-direction: column; } +/* CONTAIN */ .OnboardContainer { - position: absolute; - top: 75px; - - display: flex; - flex-direction: column; + position: absolute; + top: 75px; + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + padding-top: 50px; + padding-bottom: 500px; + background-color: #f0f0f0; + font-family: 'Open Sans', sans-serif; +} - align-items: center; +.CourseDisplayBox { + border: 1px solid green; + padding: 10px; + background-color: white; + border-radius: 8px; + height: 400px; + overflow-y: scroll; +} - width: 100%; +.courseBox { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 425px; + height: 36px; + border-radius: 16px; + margin-bottom: 5px; + padding-left: 10px; + padding-right: 10px; + background-color: #F5F5F5; + transition: filter 0.4s ease; +} - padding-top: 50px; - padding-bottom: 500px; -} \ No newline at end of file +.courseBox:hover { + cursor: pointer; + filter: brightness(95%); +} + +.courseCode, +.courseCredits, +.courseStatus { + flex: 1; +} + +.YearHeader { + font-weight: 600; + font-size: 25px; + margin-bottom: 10px; +} + +.TabButtons { + display: flex; + gap: 10px; + margin-bottom: 10px; +} + +.TabButton { + background: none; + border: none; + cursor: pointer; + padding: 5px; +} + +.TabContent { + border: 1px solid black; + border-radius: 8px; + padding: 10px; + background-color: white; + width: 450px; + height: 400px; + overflow-y: auto; +} + +.ResultsContainer { + border: 1px solid green; + padding: 10px; + background-color: white; + border-radius: 8px; + width: 500px; + height: 500px; + display: flex; + flex-direction: column; + align-items: flex-start; +} diff --git a/frontend/src/pages/Onboard/Onboard.tsx b/frontend/src/pages/Onboard/Onboard.tsx index 350d58e..4f57bb5 100644 --- a/frontend/src/pages/Onboard/Onboard.tsx +++ b/frontend/src/pages/Onboard/Onboard.tsx @@ -1,4 +1,3 @@ - import { useState } from "react"; import { syncData } from "../../api/api"; @@ -7,175 +6,185 @@ import LogoMA from "./../../commons/images/ma_logo.png"; import Style from "./Onboard.module.css"; - type DACourse = { - code: string; - credits: string; - term: string; - status: string; + code: string; + credits: string; + term: string; + status: string; }; -function NavBar(){ - return( +function NavBar() { + return (
- +
); } -function OptionOne(props: { checkAuth: Function }){ +function OptionOne(props: { handleParsedData: Function }) { + const [inputText, setInputText] = useState(''); + const [parsedData, setParsedData] = useState({}); - const [inputText, setInputText] = useState(''); - const [parsedData, setParsedData] = useState({}); + const handleChange = (event: React.ChangeEvent) => { + setInputText(event.target.value); + }; - const handleChange = (event: React.ChangeEvent) => { - setInputText(event.target.value); - }; + const handleClick = () => { + const data = parseData(inputText); + setParsedData(data); + props.handleParsedData(data); + }; - const handleClick = () => { - const data = parseData(inputText); - setParsedData(data); - }; + const parseData = (input: string) => { + const nameMatch = input.match(/Name\s*\n\s*([^\n]+)/); + const courses = parseCourses(input); - const parseData = (input: string) => { - const nameMatch = input.match(/Name\s*\n\s*([^\n]+)/); - const courses = parseCourses(input); + const degreeMatch = input.match(/Degree\s*\n\s*([^\n]+)/); + const majorMatch = input.match(/Major\s*(.*?)\s*Cohort/); - const degreeMatch = input.match(/Degree\s*\n\s*([^\n]+)/); - const majorMatch = input.match(/Major\s*(.*?)\s*Cohort/); + const placementLanguageMatch = input.match(/Placement Language\s*([^,]+,[^,]+)/); - const placementLanguageMatch = input.match(/Placement Language\s*([^,]+,[^,]+)/); + let degreeList: Array = []; + if (degreeMatch && majorMatch) { + degreeList = [`${degreeMatch[1].trim()} ${majorMatch[1].trim()}`]; + } - let degreeList: Array = []; - if(degreeMatch && majorMatch){ - degreeList = [`${degreeMatch[1].trim()} ${majorMatch[1].trim()}`]; - } - - return { - name: nameMatch ? nameMatch[1].split(',')[1].trim() : '', - degrees: degreeList, - courses: courses, - language: placementLanguageMatch ? placementLanguageMatch[1].trim() : '', - }; - }; + return { + name: nameMatch ? nameMatch[1].split(',')[1].trim() : '', + degrees: degreeList, + courses: groupCoursesByYear(courses), + language: placementLanguageMatch ? placementLanguageMatch[1].trim() : '', + }; + }; - const parseCourses = (input: string) => { + const parseCourses = (input: string) => { const coursePattern = /([A-Z&]{3,4}\s\d{3}J?)\s+[^\n]+\s+([A-F][+-]?|IP)\s+\(?(\d)\)?\s+([^\n]+)/g; const courses = []; const courseSet = new Set(); let match: RegExpExecArray | null; while ((match = coursePattern.exec(input)) !== null) { - const courseCode = match[1].trim(); - const status = match[2].trim() === 'IP' ? 'IP' : 'COMPLETE'; - if (!courseSet.has(courseCode)) { - const course = { - code: courseCode, - credits: match[3].trim(), - term: match[4].trim(), - status: status, - }; - courses.push(course); - courseSet.add(courseCode); - } + const courseCode = match[1].trim(); + const status = match[2].trim() === 'IP' ? 'IP' : 'COMPLETE'; + if (!courseSet.has(courseCode)) { + const course = { + code: courseCode, + credits: match[3].trim(), + term: match[4].trim(), + status: status, + }; + courses.push(course); + courseSet.add(courseCode); + } } return courses; -}; - - -// u can use this for better data rendering, although I rly dont fuck w the dynamic DACourse typing, deprecate that shit - // const groupCourses = (courses: DACourse[]): { [term: string]: DACourse[] } => { - // // Group courses by term - // const groupedCourses = courses.reduce((acc, course) => { - // (acc[course.term] = acc[course.term] || []).push(course); - // return acc; - // }, {} as { [term: string]: DACourse[] }); - - // // Sort terms in chronological order - // const sortedTerms = Object.keys(groupedCourses).sort((a, b) => { - // const [termA, yearA] = a.split(' '); - // const [termB, yearB] = b.split(' '); - - // if (yearA !== yearB) { - // return parseInt(yearA) - parseInt(yearB); - // } - - // const termOrder = ['Spring', 'Fall']; - // return termOrder.indexOf(termA) - termOrder.indexOf(termB); - // }); - - // // Reorder groupedCourses according to sortedTerms - // const sortedGroupedCourses = sortedTerms.reduce((acc, term) => { - // acc[term] = groupedCourses[term]; - // return acc; - // }, {} as { [term: string]: DACourse[] }); - - // return sortedGroupedCourses; - // }; - - + }; + + const groupCoursesByYear = (courses: DACourse[]) => { + const groupedCourses: { [year: string]: DACourse[] } = {}; + courses.forEach((course) => { + const year = course.term.split(' ')[1]; + const term = course.term.split(' ')[0]; + if (!groupedCourses[year]) { + groupedCourses[year] = []; + } + groupedCourses[year].push({ ...course, term }); + }); + return groupedCourses; + }; + + return ( +
+
+