From 1ab7cbdded4d96020f0165ceb559a305842eebbf Mon Sep 17 00:00:00 2001
From: Hanna Pitino <100425382+hpitino11@users.noreply.github.com>
Date: Tue, 23 Jul 2024 04:17:49 +0000
Subject: [PATCH 1/9] added set for the courseID
---
web/src/components/Dashboard.jsx | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx
index 6c247468..0ef8a3f2 100644
--- a/web/src/components/Dashboard.jsx
+++ b/web/src/components/Dashboard.jsx
@@ -18,6 +18,7 @@ const Dashboard = () => {
const [professorsData, setProfessorsData] = useState([]);
const [headersVisible, setHeadersVisible] = useState(true);
const [showSuggestions, setShowSuggestions] = useState(true);
+ const [courseId, setCourseId] = useState('');
const preventClose = (e) => {
e.stopPropagation();
@@ -98,6 +99,7 @@ const Dashboard = () => {
const fetchProfessors = async (courseId, year, semester) => {
const token = localStorage.getItem('token');
+ localStorage.setItem('course_id', courseId);
if (token) {
try {
@@ -106,6 +108,7 @@ const Dashboard = () => {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
+
});
if (response.ok) {
@@ -128,6 +131,7 @@ const Dashboard = () => {
}
};
+
const fetchCourses = async (schoolId, year, semester, query) => {
const token = localStorage.getItem('token');
@@ -168,7 +172,7 @@ const Dashboard = () => {
if (token) {
try {
- const response = await fetch(`http://localhost:8080/professors/${professorId}/rating?topKPercentage=${topKPercentage}`, {
+ const response = await fetch(`${API_URL}/professors/${professorId}/rating?topKPercentage=${topKPercentage}`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
@@ -198,7 +202,7 @@ const Dashboard = () => {
if (token) {
try {
- const response = await fetch(`http://localhost:8080/professors/${professorId}/analysis`, {
+ const response = await fetch(`${API_URL}{professorId}/analysis`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
@@ -381,10 +385,11 @@ const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnaly
}));
};
- const handleAddClick = async (event, professorId, courseId) => {
+ const handleAddClick = async (event, professorId) => {
event.stopPropagation(); // Prevent the event from propagating to the row click
const token = localStorage.getItem('token');
const userId = localStorage.getItem('user_id');
+ const courseId = localStorage.getItem('course_id')
if (token && userId) {
try {
From a9559fe6e8daa59d7feda4e18679c60b7f584eae Mon Sep 17 00:00:00 2001
From: Hanna Pitino <100425382+hpitino11@users.noreply.github.com>
Date: Tue, 23 Jul 2024 05:27:06 +0000
Subject: [PATCH 2/9] updated the find my professor header
---
web/public/index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/web/public/index.html b/web/public/index.html
index dfa28bd0..1b685ca4 100644
--- a/web/public/index.html
+++ b/web/public/index.html
@@ -33,7 +33,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
-
MDBReact5 Template App
+ Find My Professors
From 2164e7aaaa603bae781325778e8a2034cccd7f2b Mon Sep 17 00:00:00 2001
From: Zachary Cary
Date: Tue, 23 Jul 2024 10:10:33 -0400
Subject: [PATCH 3/9] accessibility
---
package-lock.json | 6 ++++++
web/src/components/Dashboard.jsx | 6 +++++-
web/src/components/DashboardHeader.jsx | 4 +++-
web/src/components/Header.jsx | 4 +++-
web/src/components/Home.jsx | 2 +-
web/src/components/SearchBar.jsx | 6 +++++-
6 files changed, 23 insertions(+), 5 deletions(-)
create mode 100644 package-lock.json
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..0436f8ec
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "findmyprofessors",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}
diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx
index aba25f44..80604981 100644
--- a/web/src/components/Dashboard.jsx
+++ b/web/src/components/Dashboard.jsx
@@ -314,11 +314,15 @@ const Dashboard = () => {
labelClass="text-black"
style={{ backgroundColor: '#FFFFFF', color: 'black', boxShadow: '3px 3px 12px rgba(0, 0, 0, 0.75)' }}
contrast
+ aria-label="Search Courses"
label="Search Courses"
value={query}
onChange={(e) => setFilters({ ...filters, query: e.target.value })}
/>
-
+
diff --git a/web/src/components/DashboardHeader.jsx b/web/src/components/DashboardHeader.jsx
index 0f99dc8e..b169adc3 100644
--- a/web/src/components/DashboardHeader.jsx
+++ b/web/src/components/DashboardHeader.jsx
@@ -139,7 +139,9 @@ const DashboardHeader = ({ onSearch }) => {
- Cart
+ Cart
diff --git a/web/src/components/Header.jsx b/web/src/components/Header.jsx
index e3518e36..9d4dda3b 100644
--- a/web/src/components/Header.jsx
+++ b/web/src/components/Header.jsx
@@ -108,13 +108,15 @@ function Header()
+ href='./Cart'
+ style={{ color: '#FFFFFF' }}>
Cart
diff --git a/web/src/components/SearchBar.jsx b/web/src/components/SearchBar.jsx
index d34ba143..397bc0dc 100644
--- a/web/src/components/SearchBar.jsx
+++ b/web/src/components/SearchBar.jsx
@@ -184,11 +184,15 @@ const SearchBar = ({ onSearch, filters, setFilters, preventClose, getYearText, g
labelClass="text-black"
style={{ backgroundColor: '#3f3f3f', boxShadow: '3px 3px 12px rgba(0, 0, 0, 0.75)' }}
contrast
+ aria-label="Search Courses"
label="Search Courses"
value={query}
onChange={(e) => setFilters({ ...filters, query: e.target.value })}/>
-
+
From 638960898474093e50d89c1745039ab228546f7c Mon Sep 17 00:00:00 2001
From: Hanna Pitino <100425382+hpitino11@users.noreply.github.com>
Date: Tue, 23 Jul 2024 14:20:22 +0000
Subject: [PATCH 4/9] added cart and works. just needs delete (next update)
---
web/src/components/Dashboard.jsx | 93 ++++++++++++++++++++++++++++----
1 file changed, 82 insertions(+), 11 deletions(-)
diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx
index aba25f44..7e0a500b 100644
--- a/web/src/components/Dashboard.jsx
+++ b/web/src/components/Dashboard.jsx
@@ -19,6 +19,8 @@ const Dashboard = () => {
const [headersVisible, setHeadersVisible] = useState(true);
const [showSuggestions, setShowSuggestions] = useState(true);
const [courseId, setCourseId] = useState('');
+ const [cartVisible, setCartVisible] = useState(false);
+ const [cartItems, setCartItems] = useState([]);
const preventClose = (e) => {
e.stopPropagation();
@@ -252,6 +254,39 @@ const Dashboard = () => {
}
};
+ const handleCartClick = async () => {
+ setCartVisible(!cartVisible);
+ if (!cartVisible) {
+ const userId = localStorage.getItem('user_id');
+ if (userId) {
+ try {
+ const response = await fetch(`${API_URL}/users/${userId}/cart`, {
+ headers: {
+ 'Authorization': `Bearer ${localStorage.getItem('token')}`,
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ if (response.ok) {
+ const data = await response.json();
+ setCartItems(data.entries.map(entry => ({
+ firstName: entry.professor.first_name,
+ lastName: entry.professor.last_name,
+ code: entry.course.code,
+ courseName: entry.course.name,
+ })));
+ } else {
+ console.error('Failed to fetch cart data:', response.statusText);
+ }
+ } catch (error) {
+ console.error('Error fetching cart data:', error);
+ }
+ } else {
+ console.error('No user ID found');
+ }
+ }
+ };
+
return (
<>
@@ -259,7 +294,6 @@ const Dashboard = () => {
-
{headersVisible && (
@@ -293,9 +327,8 @@ const Dashboard = () => {
2024 {year === 2024 && }
handleDropdownClick('year', 2025)}>
- 2025 {year === 2025 && }
-
-
+ 2025 {year === 2025 && }
+
@@ -335,12 +368,25 @@ const Dashboard = () => {
- {!headersVisible && professorsData.length > 0 && (
+
+ Cart
+
+
+ {cartVisible && (
)}
+ {!headersVisible && professorsData.length > 0 && (
+
+ )}
>
@@ -385,22 +431,22 @@ const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnaly
}));
};
- const handleAddClick = async (event, professorId) => {
+ const handleAddClick = async (event, professor) => {
event.stopPropagation(); // Prevent the event from propagating to the row click
const token = localStorage.getItem('token');
const userId = localStorage.getItem('user_id');
- const courseId = localStorage.getItem('course_id')
+ const courseId = localStorage.getItem('course_id');
if (token && userId) {
try {
- console.log('Sending request with data:', { professorId, courseId }); // Debugging log
+ console.log('Sending request with data:', { professorId: professor.id, courseId }); // Debugging log
const response = await fetch(`${API_URL}/users/${userId}/cart`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
- body: JSON.stringify({ professor_id: professorId, course_id: courseId})
+ body: JSON.stringify({ professor_id: professor.id, course_id: courseId })
});
if (response.ok) {
@@ -452,7 +498,7 @@ const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnaly
{ratingsData[professor.id] ? roundToTenth(ratingsData[professor.id].totalQualityAverage) : '-'} |
{ratingsData[professor.id]?.ratingAmount || '-'} |
- handleAddClick(event, professor.id)}>Add
+ handleAddClick(event, professor)}>Add
|
{selectedProfessor === professor && (
@@ -489,6 +535,31 @@ const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnaly
);
};
+const CartTable = ({ cartItems }) => {
+ return (
+
+
+
+ First Name |
+ Last Name |
+ Code |
+ Course Name |
+
+
+
+ {cartItems.map((item, index) => (
+
+ {item.firstName} |
+ {item.lastName} |
+ {item.code} |
+ {item.courseName} |
+
+ ))}
+
+
+ );
+};
+
const ProfessorDetails = ({ professor, analysisData }) => {
const lineData = {
labels: analysisData ? analysisData.averageRatingValues.map(item => `${item.month} ${item.year}`) : [],
From 89606a7d7d6466bd964dc42f34a1b3462713e1bd Mon Sep 17 00:00:00 2001
From: Zachary Cary
Date: Tue, 23 Jul 2024 10:20:27 -0400
Subject: [PATCH 5/9] accessibility
---
web/src/components/EmailConfirmation.jsx | 4 ----
web/src/components/ForgotPassword.jsx | 4 ----
web/src/components/Home.jsx | 2 +-
web/src/components/Login.jsx | 20 ++++----------------
web/src/components/Register.jsx | 6 +-----
web/src/components/ResetPassword.jsx | 4 ----
web/src/components/VerifyEmail.jsx | 16 ----------------
7 files changed, 6 insertions(+), 50 deletions(-)
diff --git a/web/src/components/EmailConfirmation.jsx b/web/src/components/EmailConfirmation.jsx
index b5105738..707de3ef 100644
--- a/web/src/components/EmailConfirmation.jsx
+++ b/web/src/components/EmailConfirmation.jsx
@@ -59,10 +59,6 @@ const EmailConfirmation = () => {
Your email has been confirmed. Redirecting to login ...
-
diff --git a/web/src/components/ForgotPassword.jsx b/web/src/components/ForgotPassword.jsx
index 87a099c8..e5f2cfb0 100644
--- a/web/src/components/ForgotPassword.jsx
+++ b/web/src/components/ForgotPassword.jsx
@@ -97,10 +97,6 @@ const ForgotPassword = () => {
Send Reset Link
-
diff --git a/web/src/components/Home.jsx b/web/src/components/Home.jsx
index b2840fce..3fcc13a8 100644
--- a/web/src/components/Home.jsx
+++ b/web/src/components/Home.jsx
@@ -56,7 +56,7 @@ const containerStyle = {
<>
-
+
diff --git a/web/src/components/Login.jsx b/web/src/components/Login.jsx
index a96f8186..0a938a6e 100644
--- a/web/src/components/Login.jsx
+++ b/web/src/components/Login.jsx
@@ -77,7 +77,7 @@ const Login = () => {
<>
-
+
@@ -169,24 +169,12 @@ const Login = () => {
- Don't have an account? Register
+ style={{ color: 'white' }}>
+ Don't have an account? Register
-
+
diff --git a/web/src/components/Register.jsx b/web/src/components/Register.jsx
index e92c1f8f..d889ec93 100644
--- a/web/src/components/Register.jsx
+++ b/web/src/components/Register.jsx
@@ -211,14 +211,10 @@ const Register = () => {
+ style={{ color: 'white' }}>
Already have an account? Login
-
diff --git a/web/src/components/ResetPassword.jsx b/web/src/components/ResetPassword.jsx
index 92e4a8bf..855fc64b 100644
--- a/web/src/components/ResetPassword.jsx
+++ b/web/src/components/ResetPassword.jsx
@@ -140,10 +140,6 @@ const ResetPassword = () => {
Reset Password
-
diff --git a/web/src/components/VerifyEmail.jsx b/web/src/components/VerifyEmail.jsx
index 2a0a5a1b..fa32e5e4 100644
--- a/web/src/components/VerifyEmail.jsx
+++ b/web/src/components/VerifyEmail.jsx
@@ -75,22 +75,6 @@ const VerifyEmail = () => {
-
From a0aab1e6b7e3d382231906395bc2b0fc0a276bdc Mon Sep 17 00:00:00 2001
From: Hanna Pitino <100425382+hpitino11@users.noreply.github.com>
Date: Tue, 23 Jul 2024 14:25:22 +0000
Subject: [PATCH 6/9] dashboard cart with delete working
---
web/src/components/Dashboard.jsx | 46 +++++++++++++++++++++++++++-----
1 file changed, 39 insertions(+), 7 deletions(-)
diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx
index 5a678a21..cbcfbe65 100644
--- a/web/src/components/Dashboard.jsx
+++ b/web/src/components/Dashboard.jsx
@@ -274,6 +274,8 @@ const Dashboard = () => {
lastName: entry.professor.last_name,
code: entry.course.code,
courseName: entry.course.name,
+ professorId: entry.professor.id,
+ courseId: entry.course.id
})));
} else {
console.error('Failed to fetch cart data:', response.statusText);
@@ -287,6 +289,34 @@ const Dashboard = () => {
}
};
+ const handleDeleteClick = async (professorId, courseId) => {
+ const userId = localStorage.getItem('user_id');
+ const token = localStorage.getItem('token');
+
+ if (userId && token) {
+ try {
+ const response = await fetch(`${API_URL}/users/${userId}/cart`, {
+ method: 'DELETE',
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ professor_id: professorId, course_id: courseId })
+ });
+
+ if (response.ok) {
+ setCartItems((prevItems) => prevItems.filter(item => !(item.professorId === professorId && item.courseId === courseId)));
+ } else {
+ console.error('Failed to delete item from cart:', response.statusText);
+ }
+ } catch (error) {
+ console.error('Error deleting item from cart:', error);
+ }
+ } else {
+ console.error('No user ID or token found');
+ }
+ };
+
return (
<>
@@ -347,15 +377,11 @@ const Dashboard = () => {
labelClass="text-black"
style={{ backgroundColor: '#FFFFFF', color: 'black', boxShadow: '3px 3px 12px rgba(0, 0, 0, 0.75)' }}
contrast
- aria-label="Search Courses"
label="Search Courses"
value={query}
onChange={(e) => setFilters({ ...filters, query: e.target.value })}
/>
-
+
@@ -378,7 +404,7 @@ const Dashboard = () => {
{cartVisible && (
-
+
)}
@@ -539,7 +565,7 @@ const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnaly
);
};
-const CartTable = ({ cartItems }) => {
+const CartTable = ({ cartItems, handleDeleteClick }) => {
return (
@@ -548,6 +574,7 @@ const CartTable = ({ cartItems }) => {
Last Name |
Code |
Course Name |
+ Delete |
@@ -557,6 +584,11 @@ const CartTable = ({ cartItems }) => {
{item.lastName} |
{item.code} |
{item.courseName} |
+
+ handleDeleteClick(item.professorId, item.courseId)}>
+ Delete
+
+ |
))}
From 8f11682e943e8bfd61c4c415ea10e29277d9b53b Mon Sep 17 00:00:00 2001
From: Zachary Cary
Date: Tue, 23 Jul 2024 10:31:29 -0400
Subject: [PATCH 7/9] logout functionality
---
web/src/components/Header.jsx | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/web/src/components/Header.jsx b/web/src/components/Header.jsx
index 9d4dda3b..372ed03c 100644
--- a/web/src/components/Header.jsx
+++ b/web/src/components/Header.jsx
@@ -41,7 +41,11 @@ function Header()
const navigate = useNavigate();
+ const userId = localStorage.getItem('user_id');
+
const handleLogout = () => {
+ localStorage.removeItem('user_id');
+ console.log("userID is now " + userId);
toggleOpen();
navigate('/Login');
};
From 3e73ead2eeb1a342d8be4723ed3ce87499bbbad0 Mon Sep 17 00:00:00 2001
From: Hanna Pitino <100425382+hpitino11@users.noreply.github.com>
Date: Tue, 23 Jul 2024 14:56:21 +0000
Subject: [PATCH 8/9] added new delete and add popups and text to confirm. cart
button now next to search. hides professor table when in cart.
---
web/src/components/Dashboard.jsx | 64 +++++++++++++++++++-------------
1 file changed, 39 insertions(+), 25 deletions(-)
diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx
index cbcfbe65..735c7a85 100644
--- a/web/src/components/Dashboard.jsx
+++ b/web/src/components/Dashboard.jsx
@@ -21,6 +21,7 @@ const Dashboard = () => {
const [courseId, setCourseId] = useState('');
const [cartVisible, setCartVisible] = useState(false);
const [cartItems, setCartItems] = useState([]);
+ const [addClassMessage, setAddClassMessage] = useState('');
const preventClose = (e) => {
e.stopPropagation();
@@ -290,30 +291,32 @@ const Dashboard = () => {
};
const handleDeleteClick = async (professorId, courseId) => {
- const userId = localStorage.getItem('user_id');
- const token = localStorage.getItem('token');
+ if (window.confirm('Are you sure you want to delete this entry?')) {
+ const userId = localStorage.getItem('user_id');
+ const token = localStorage.getItem('token');
- if (userId && token) {
- try {
- const response = await fetch(`${API_URL}/users/${userId}/cart`, {
- method: 'DELETE',
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({ professor_id: professorId, course_id: courseId })
- });
+ if (userId && token) {
+ try {
+ const response = await fetch(`${API_URL}/users/${userId}/cart`, {
+ method: 'DELETE',
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ professor_id: professorId, course_id: courseId })
+ });
- if (response.ok) {
- setCartItems((prevItems) => prevItems.filter(item => !(item.professorId === professorId && item.courseId === courseId)));
- } else {
- console.error('Failed to delete item from cart:', response.statusText);
+ if (response.ok) {
+ setCartItems((prevItems) => prevItems.filter(item => !(item.professorId === professorId && item.courseId === courseId)));
+ } else {
+ console.error('Failed to delete item from cart:', response.statusText);
+ }
+ } catch (error) {
+ console.error('Error deleting item from cart:', error);
}
- } catch (error) {
- console.error('Error deleting item from cart:', error);
+ } else {
+ console.error('No user ID or token found');
}
- } else {
- console.error('No user ID or token found');
}
};
@@ -384,6 +387,9 @@ const Dashboard = () => {
+
+ Cart
+
{showSuggestions && searchResults.length > 0 && (
@@ -398,22 +404,28 @@ const Dashboard = () => {
-
- Cart
-
+ {addClassMessage && (
+
+ {addClassMessage}
+
+ )}
{cartVisible && (
+ setCartVisible(false)}>
+ Go Back to Professors
+
)}
- {!headersVisible && professorsData.length > 0 && (
+ {!headersVisible && professorsData.length > 0 && !cartVisible && (
)}
@@ -423,7 +435,7 @@ const Dashboard = () => {
);
};
-const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnalysis }) => {
+const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnalysis, setAddClassMessage }) => {
const [searchTerm, setSearchTerm] = useState('');
const [currentPage, setCurrentPage] = useState(1);
const [selectedProfessor, setSelectedProfessor] = useState(null);
@@ -480,6 +492,8 @@ const ProfessorTable = ({ professors, fetchProfessorRatings, fetchProfessorAnaly
});
if (response.ok) {
+ setAddClassMessage(`Class added: ${professor.first_name} ${professor.last_name}`);
+ setTimeout(() => setAddClassMessage(''), 3000);
console.log('Professor added to cart successfully');
} else {
console.error('Failed to add professor to cart:', response.statusText);
From 676c906936428eccef212f234695b23f198a302f Mon Sep 17 00:00:00 2001
From: Hanna Pitino <100425382+hpitino11@users.noreply.github.com>
Date: Tue, 23 Jul 2024 15:03:29 +0000
Subject: [PATCH 9/9] reversed order of data points in line chart
---
web/src/components/Dashboard.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx
index 735c7a85..17537e13 100644
--- a/web/src/components/Dashboard.jsx
+++ b/web/src/components/Dashboard.jsx
@@ -612,11 +612,11 @@ const CartTable = ({ cartItems, handleDeleteClick }) => {
const ProfessorDetails = ({ professor, analysisData }) => {
const lineData = {
- labels: analysisData ? analysisData.averageRatingValues.map(item => `${item.month} ${item.year}`) : [],
+ labels: analysisData ? analysisData.averageRatingValues.map(item => `${item.month} ${item.year}`).reverse() : [],
datasets: [
{
label: 'Rating Over Time',
- data: analysisData ? analysisData.averageRatingValues.map(item => item.value) : [],
+ data: analysisData ? analysisData.averageRatingValues.map(item => item.value).reverse() : [],
fill: false,
backgroundColor: 'rgb(75, 192, 192)',
borderColor: 'rgba(75, 192, 192, 0.2)',