From 18326e40cd1abddd802337491f07208fb3c88a4b Mon Sep 17 00:00:00 2001 From: mahathiryali Date: Sun, 3 Nov 2024 13:14:01 -0800 Subject: [PATCH] semesters based on start and grad year populate --- package-lock.json | 41 +++++++- package.json | 3 +- src/App.css | 26 ++++- src/App.tsx | 14 ++- src/SemesterHome.tsx | 42 +++++++++ src/components/AddClass/AddClass.tsx | 94 +++++++++++++++++++ src/components/AddClass/SearchBar.tsx | 51 ++++++++++ src/components/AddClass/addclass.css | 67 +++++++++++++ src/components/SemesterBlock/index.tsx | 63 +++++++++---- .../SemesterBlock/semesterblock.css | 88 +++++++++++++++-- src/components/SetUpPage/index.tsx | 44 +++++++-- src/components/SetUpPage/setup.css | 20 +++- src/components/SetUpPage/year-dropdown.tsx | 47 +++++----- src/components/classes.json | 9 ++ src/index.css | 1 + 15 files changed, 541 insertions(+), 69 deletions(-) create mode 100644 src/SemesterHome.tsx create mode 100644 src/components/AddClass/AddClass.tsx create mode 100644 src/components/AddClass/SearchBar.tsx create mode 100644 src/components/AddClass/addclass.css create mode 100644 src/components/classes.json diff --git a/package-lock.json b/package-lock.json index 5df4593..efd4569 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/themes": "^3.1.4", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.27.0" }, "devDependencies": { "@eslint/js": "^9.9.0", @@ -2203,6 +2204,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", + "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.22.5", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", @@ -4032,6 +4041,36 @@ } } }, + "node_modules/react-router": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", + "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==", + "dependencies": { + "@remix-run/router": "1.20.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", + "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", + "dependencies": { + "@remix-run/router": "1.20.0", + "react-router": "6.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", diff --git a/package.json b/package.json index e144658..fdefd81 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/themes": "^3.1.4", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.27.0" }, "devDependencies": { "@eslint/js": "^9.9.0", diff --git a/src/App.css b/src/App.css index b9d355d..69f6818 100644 --- a/src/App.css +++ b/src/App.css @@ -1,16 +1,16 @@ #root { - max-width: 1280px; + /* max-width: 1280px; */ margin: 0 auto; - padding: 2rem; + /* padding: 2rem; */ text-align: center; } -.logo { +/* .logo { height: 6em; padding: 1.5em; will-change: filter; transition: filter 300ms; -} +} */ .logo:hover { filter: drop-shadow(0 0 2em #646cffaa); } @@ -40,3 +40,21 @@ .read-the-docs { color: #888; } + +.semester-layout { + margin-left: 32px; + margin-right: 32px; +} + +.semester-title { + color: var(--Primary-Text, #000); +/* Web UI/Heading/Heading Large */ +font-family: "Inter Variable"; +font-size: 28px; +font-style: normal; +font-weight: 580; +line-height: 36px; /* 128.571% */ +letter-spacing: -0.28px; +text-align: left; +margin-left: 32px; +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 259169d..75559f4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,15 +1,19 @@ import React, { useState } from 'react'; import "./App.css"; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import SetUpPage from "./components/SetUpPage" -import SemesterBlock from "./components/SemesterBlock" +import SemesterHome from './SemesterHome'; +// import SemesterBlock from "./components/SemesterBlock" function App() { const [selectedYear, setSelectedYear] = useState(null); return ( - <> - {/* */} - - + + + } /> + } /> + + ); } diff --git a/src/SemesterHome.tsx b/src/SemesterHome.tsx new file mode 100644 index 0000000..5c86de2 --- /dev/null +++ b/src/SemesterHome.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { useLocation } from 'react-router-dom'; +import SemesterBlock from "./components/SemesterBlock" +import { Flex } from '@radix-ui/themes'; +import "./App.css" + + +function SemesterHome() { + const location = useLocation(); + const { startYear, gradYear, summerCheck } = location.state || {}; + + const numStartYear = parseInt(startYear, 10); + const numGradYear = parseInt(gradYear, 10); + const yearCount = numGradYear - numStartYear + 1; + const years = Array.from( + { length: yearCount }, + (_, i) => numStartYear + i + ); + + return ( + +

Semesters

+ + {/* + */} + + {years.map((year) => ( + + {/* Replace with the element you want to render */} + + + {summerCheck && + + } + + ))} + +
+ ); +} + +export default SemesterHome; \ No newline at end of file diff --git a/src/components/AddClass/AddClass.tsx b/src/components/AddClass/AddClass.tsx new file mode 100644 index 0000000..9c3e3e6 --- /dev/null +++ b/src/components/AddClass/AddClass.tsx @@ -0,0 +1,94 @@ +import "./addclass.css" +import { Text, Button } from "@radix-ui/themes"; +import React, { useState } from 'react'; +import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; +import { DotsHorizontalIcon } from '@radix-ui/react-icons'; +import * as Dialog from '@radix-ui/react-dialog'; +import classesData from './../classes.json'; +import SearchBar from "./SearchBar"; + + +interface AddClassProps { + // name: string; + // onEdit: () => void; + // onDelete: (name: string) => void; + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + addClass: (cls: ClassType) => void; +}; + +type ClassType = { + id: number; + name: string; + units: number; + }; + + +function AddClass({ isOpen, setIsOpen, addClass }: AddClassProps) { + const [showMenu, setShowMenu] = useState(false); + + const [searchTerm, setSearchTerm] = useState(''); + const [filteredClasses, setFilteredClasses] = useState([]); + const [units, setUnits] = useState(null); + + const handleSearch = (event: React.ChangeEvent) => { + const term = event.target.value; + setSearchTerm(term); + const filtered = classesData.filter((cls) => + cls.name.toLowerCase().includes(term.toLowerCase()) + ); + setFilteredClasses(filtered); + }; + + const handleSelectClass = (cls: ClassType) => { + addClass(cls); // Update parent state + setFilteredClasses([]); // Hide suggestions + setSearchTerm(''); // Clear search field + setIsOpen(false); // Close dialog after selection + }; + + return ( +
setShowMenu(true)} + // onMouseLeave={() => setShowMenu(false)} + > + {showMenu && + + + + + + {/* Dropdown Menu Content */} + + + Edit Course Details + + onDelete(name)} + > + Delete Class + + + + } + + + + +
+ ) +} + +export default AddClass; \ No newline at end of file diff --git a/src/components/AddClass/SearchBar.tsx b/src/components/AddClass/SearchBar.tsx new file mode 100644 index 0000000..7362921 --- /dev/null +++ b/src/components/AddClass/SearchBar.tsx @@ -0,0 +1,51 @@ +import * as Dialog from '@radix-ui/react-dialog'; +import "./addclass.css" + +interface SearchBarProps { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + searchTerm: string; + handleSearch: (event: React.ChangeEvent) => void; + filteredClasses: ClassType[]; + handleSelectClass: (cls: ClassType) => void; + +}; + +type ClassType = { + id: number; + name: string; + units: number; + }; + +function SearchBar({isOpen, setIsOpen, searchTerm, handleSearch, filteredClasses, handleSelectClass}: SearchBarProps) { + return ( + + + + + {/* Dropdown for suggestions */} + {filteredClasses.length > 0 && ( +
    + {filteredClasses.map((cls) => ( +
  • handleSelectClass(cls)} + className="suggestion-item" + > + {cls.name} - {cls.units} units +
  • + ))} +
+ )} +
+
+ ) +} + +export default SearchBar; \ No newline at end of file diff --git a/src/components/AddClass/addclass.css b/src/components/AddClass/addclass.css new file mode 100644 index 0000000..efc84b0 --- /dev/null +++ b/src/components/AddClass/addclass.css @@ -0,0 +1,67 @@ +@media (max-width: 600px) { + /* .container { + width: 100%; + } */ +} + +body { + background-color: white; +} + + .dropDownBtn { + color: black !important; + background-color: white !important; + } + + /* .searchContent { + background-color: white; + color: black; +} */ + +.searchBar { + background-color: white; + color: black; + position: relative; + margin-top: 0.5rem; + padding: 0.5rem; + /* width: 100%; */ + width: 210px; + padding: 16px; + /* maxheight: 92px; */ + min-height: 92px; + border: 1px solid transparent; + border-radius: 0.25rem; + vertical-align: top; + +} + +.suggestion-list { + max-height: 5rem; + overflow-y: scroll; + list-style-type: none; + padding: 0; + scrollbar-color: #cbd5e0 #f3f4f6; + scrollbar-width: thin; + background-color: white; +} + +.suggestions-list::-webkit-scrollbar-thumb { + background-color: #8A8A8A; /* Light gray scrollbar handle */ + border-radius: 4px; + } + + + .suggestions-list::-webkit-scrollbar-track { + background-color: #8A8A8A; /* Lighter gray track */ + } + +.suggestion-item { + cursor: pointer; + padding: 0.5rem; + text-align: left; +} + +.suggestion-item:hover { + background-color: #bfdbfe; /* Light blue for hover */ + } + diff --git a/src/components/SemesterBlock/index.tsx b/src/components/SemesterBlock/index.tsx index 5cc495a..344be42 100644 --- a/src/components/SemesterBlock/index.tsx +++ b/src/components/SemesterBlock/index.tsx @@ -1,34 +1,65 @@ import { Box } from "@radix-ui/themes"; import React, { useState } from 'react'; -import { Button } from "@radix-ui/themes"; +import { Button } from "@radix-ui/themes"; import "./semesterblock.css" +import AddClass from "../AddClass/AddClass"; interface SemesterYearProps { selectedYear: number | string; + selectedSemester: string; }; -function SemesterBlock({ selectedYear }: SemesterYearProps) { + type ClassType = { + id: number; + name: string; + units: number; + }; + +function SemesterBlock({ selectedYear, selectedSemester }: SemesterYearProps) { const [classList, setClassList] = useState([]); - const handleAddClass = () => { - setClassList([...classList, `Class ${classList.length + 1}`]); + const [isAddClassOpen, setIsAddClassOpen] = useState(false); + const [selectedClasses, setSelectedClasses] = useState([]); + const [totalUnits, setTotalUnits] = useState(0); + + const handleDeleteClass = (name: string) => { + setClassList(classList.filter((className) => className !== name)); + }; + const handleEditClass = () => {}; + const addClass = (cls: ClassType) => { + setSelectedClasses((prevClasses) => [...prevClasses, cls]); + setTotalUnits((prevTotal) => prevTotal + cls.units); // Update total units }; + return ( -
-

Fall {selectedYear}

{classList.length}

- -
- {classList.map((className, index) => ( -
- {className} -
- ))} +
+
+
+

{selectedSemester} {selectedYear}

+

{totalUnits}

+
+ + {/* Display selected classes outside the dialog */} + {/*
*/} + {selectedClasses.map((cls, index) => ( +
+

{cls.name}

+

{cls.units} Units

+
+ ))} + {/*
*/} + + {/* Dialog Component */} + + +
- +
+ ) } diff --git a/src/components/SemesterBlock/semesterblock.css b/src/components/SemesterBlock/semesterblock.css index 81b1ac0..e485cc1 100644 --- a/src/components/SemesterBlock/semesterblock.css +++ b/src/components/SemesterBlock/semesterblock.css @@ -4,21 +4,95 @@ } } -body { - background-color: white; -} .container { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; - background-color: #F8F8F8; + background-color: #F8F8F8 !important; border-radius: 8px; - width: 300px; + width: 226px; margin: 20px auto; } - .counter { - background-color: #E7E7E7; + .classContainer { + display: flex; + flex-direction: column; + /* justify-content: space-between; */ + padding: 8px; + width: 100%; + background-color: #ffffff; + border-radius: 8px; + margin: 8px; + text-align: left; + min-height: 92px; + + } + + .classTitle { + color: var(--Primary-Text, #000); + align-items: flex-start; + /* height: 92px; */ + width: 100%; + /* min-width: 110px; */ + font-family: "Inter Variable"; + font-size: 12px; + margin: 0; + padding-left: 16px; + padding-top: 16px; + font-style: normal; + font-weight: 500; + } + + .units { + color: var(--Secondary-Text, #8A8A8A); + font-family: "Inter Variable"; + font-size: 12px; + font-style: normal; + font-weight: 400; + margin: 0; + padding-left: 16px; + padding-top: 2px; } + +.counter { + background-color: #E7E7E7; + color: var(--Primary-Text, #000); + text-align: center; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 16px; /* 133.333% */ +} + +.semesterCount { + display: flex; + align-items: baseline; + gap: var(--XS, 8px); +} + +.title { + color: var(--Primary-Text, #000); + text-align: center; + + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 20px; + letter-spacing: -0.1px; +} + +.add-button { + font-size: 14px; + background-color: #F8F8F8 !important; + color: black !important; +} + +.semesters { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; +} + diff --git a/src/components/SetUpPage/index.tsx b/src/components/SetUpPage/index.tsx index 5692cca..d202351 100644 --- a/src/components/SetUpPage/index.tsx +++ b/src/components/SetUpPage/index.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import {useNavigate} from 'react-router-dom'; import "@radix-ui/themes/styles.css"; import "./setup.css" import { Flex, Text, Button, Checkbox } from "@radix-ui/themes"; @@ -6,32 +7,55 @@ import YearDropdown from "./year-dropdown"; function SetUpPage() { + const navigate = useNavigate(); + const [startYear, setStartYear] = useState(''); + const [gradYear, setGradYear] = useState(''); + const [summerCheck, setSummerCheck] = useState(false); + + const handleSelectYear = (id: string, year: string) => { + if (id === 'startYear') { + setStartYear(year); + } else if (id === 'gradYear') { + setGradYear(year); + } + }; + + const handleNextClick = () => { + navigate('/next', { state: { startYear, gradYear, summerCheck } }); + }; + + + const handleSummerCheck = (checked: boolean) => { + setSummerCheck(checked); + } return ( - - Set Up - Enter your start year and graduation year + + + Set Up + Enter your start year and graduation year + - + Start Year - + - + Graduation Year - + - + - + Include Summer Semesters? - + ); } diff --git a/src/components/SetUpPage/setup.css b/src/components/SetUpPage/setup.css index 58524e0..39e7483 100644 --- a/src/components/SetUpPage/setup.css +++ b/src/components/SetUpPage/setup.css @@ -1,7 +1,8 @@ -.container { +.setup-container { width: 500px; - flex-direction: column; - gap: var(--L, 32px); + /* flex-direction: column; + gap: var(--L, 32px); */ + background-color: white !important; } @media (max-width: 600px) { .container { @@ -39,6 +40,7 @@ body { background-color: white; border: 1px solid var(--Gray-2, #C7C7C7); color: black; + text-align: left; } .yearOptions { @@ -52,7 +54,17 @@ body { } .yearContainer { - justify-content: "space-between"; width: 100%; align-items: center; + text-align: left; + +} + +.next-btn { + width: 100%; + height: 44px +} + +.summer-sem-check { + text-align: left; } \ No newline at end of file diff --git a/src/components/SetUpPage/year-dropdown.tsx b/src/components/SetUpPage/year-dropdown.tsx index 055cf5c..1cd6021 100644 --- a/src/components/SetUpPage/year-dropdown.tsx +++ b/src/components/SetUpPage/year-dropdown.tsx @@ -6,36 +6,41 @@ import { ChevronDownIcon } from '@radix-ui/react-icons'; import YearsData from './years.json'; -function YearDropdown() { +interface YearDropdownProps { + id: string; + onSelectYear: (id: string, year: string) => void; +}; + +function YearDropdown({id, onSelectYear}: YearDropdownProps) { const [gradYear, setGradYear] = useState(null); const { years } = YearsData; const handleGradSelect = (year: string) => { setGradYear(year); + onSelectYear(id, year) }; return ( - - - {gradYear ? gradYear : 'Select year'} - - + + + {gradYear ? gradYear : 'Select year'} + + - - - - {years.map((year) => ( - handleGradSelect(year)} - className="yearOptions" - > - {year} - - ))} - - - + + + {years.map((year) => ( + handleGradSelect(year)} + className="yearOptions" + > + {year} + + ))} + + + ) } diff --git a/src/components/classes.json b/src/components/classes.json new file mode 100644 index 0000000..9a48e15 --- /dev/null +++ b/src/components/classes.json @@ -0,0 +1,9 @@ +[ + { "id": 1, "name": "COLWRIT R4B", "units": 4 }, + { "id": 2, "name": "HISTORY 7A", "units": 4 }, + { "id": 3, "name": "CS 61A", "units": 4 }, + { "id": 4, "name": "MATH 51", "units": 4 }, + { "id": 5, "name": "MATH 53", "units": 4 }, + { "id": 6, "name": "MATH 54", "units": 4 }, + { "id": 7, "name": "MATH 1A", "units": 4 } + ] \ No newline at end of file diff --git a/src/index.css b/src/index.css index 6119ad9..a99eb32 100644 --- a/src/index.css +++ b/src/index.css @@ -66,3 +66,4 @@ button:focus-visible { background-color: #f9f9f9; } } +