diff --git a/devU-client/src/components/pages/gradebook/gradebookPage.scss b/devU-client/src/components/pages/gradebook/gradebookPage.scss index 7297b2d5..d4bd9e4a 100644 --- a/devU-client/src/components/pages/gradebook/gradebookPage.scss +++ b/devU-client/src/components/pages/gradebook/gradebookPage.scss @@ -1,11 +1,12 @@ @import 'variables'; - +// Category Styling .categoryName { color: $text-color; font-size: 1.25rem; } +// Table Wrapper for layout consistency .tableWrapper { padding: 0 100px; } @@ -16,12 +17,11 @@ } table { - border-radius: 20px; - // margin: 15px auto; - border-collapse: collapse; width: 100%; + border-collapse: collapse; } +// Alternating Row Colors tr.evenRow { background-color: $table-row-even; } @@ -30,18 +30,19 @@ tr.oddRow { background-color: $table-row-odd; } +// Table Header & Cell Styling th { - background-color: $primary; - color: #FFF; - font-weight: 600; + background-color: #5a3d8a; + color: white; } -td, -th { +th, td { padding: 10px; - text-align: center; + border-bottom: 1px solid #ccc; + text-align: left; } +// Table Borders & Rounded Corners th:first-of-type { border-top-left-radius: 10px; } @@ -58,12 +59,20 @@ tr:last-of-type td:last-of-type { border-bottom-right-radius: 10px; } +// Table Options Section .tableOptions { display: flex; justify-content: space-between; align-items: center; } +.topSection { + display: flex; + justify-content: space-between; + align-items: center; +} + +// Text Colors for Status Indicators .tableOptions span:first-child, span.yellow { color: $yellowText; @@ -74,37 +83,153 @@ span.red { color: $redText; } -// STUDENT GRADEBOOK STYLING - -// .header { -// color: $text-color; -// display: flex; -// align-items: center; -// justify-content: center; -// // margin-bottom: 20px; -// } - +// Student Gradebook Styling .assignmentName { text-align: left; } -.gradebook-container { +.gradebookContainer { display: flex; + flex-direction: column; gap: 20px; - flex-wrap: wrap; } -.category { - width: calc(100%/3 - 14px); +// Section Styling +.section { + background-color: white; + padding: -3px; + border-radius: 10px; + border: 2px solid #5a3d8a; +} + +.categoryRow { + font-weight: bold; } +.categoryValue { + text-align: right; + padding-right: 10px; // 🟒 Fix: Align value to the left +} + +.categoryText { + text-align: left; + padding-left: 10px; // 🟒 Fix: Align "Category Average" text to the right +} + +// Assignment Link Styling +.assignmentLink { + color: blue; + text-decoration: underline; +} + +// Category Average Styling (Adjusted for spacing) +.categoryAverage { + font-size: 14px; + text-align: right; + padding: 10px; + font-weight: bold; + margin-top: 10px; // 🟒 FIX: Added spacing so it doesn’t overlap +} + +// Page Wrapper & Title +.pageWrapper { + padding: 20px; +} + +.gradebookTitle { + text-align: center; + font-size: 2rem; + font-weight: bold; +} + +// 🟒 FIX: "Back to Course" Button Alignment +.backToCourseButton { + background-color: #5a3d8a; + color: white; + padding: 8px 15px; + border-radius: 30px; + border: none; + cursor: pointer; + position: absolute; + top: 137px; + right: 30px; +} + +// Section Headers (Purple Background) +.sectionHeader { + background-color: #5a3d8a; + color: white; + padding: 12px 20px; + border-radius: 8px 8px 0 0; + font-weight: bold; + display: flex; + justify-content: space-between; // 🟒 FIX: Ensures Late Days & Score are in the same row + align-items: center; +} + +.headerRight { + display: flex; + gap: 20px; // 🟒 FIX: Adds spacing between Late Days and Score +} + +// Gradebook Layout (Using Grid) +.gradebookGrid { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 20px; + width: 100%; // 🟒 FIX: Ensures the grid container spans full width +} + +// 🟒 FIX: Project Section Width Adjusted +.sectionLeft { + grid-column: 1; +} + +.sectionRight { + grid-column: 2; +} + +.sectionFull { + grid-column: 1 / span 1; // 🟒 FIX: Project is same width as Homeworks +} + +// Empty Assignments Text +.noAssignments { + text-align: center; + padding: 10px; + font-style: italic; +} + +// Course Average Box Styling +.courseAverage { + border: 2px solid #5a3d8a; + padding: 14px; + display: flex; + justify-content: space-between; // 🟒 FIX: Pushes the value to the rightmost side + font-weight: bold; + width: 99.01%; + grid-column: span 2; + margin-top: 20px; + border-radius: 13px; +} + +// 🟒 FIX: Mobile Responsive Adjustments @media (max-width: 650px) { .pageWrapper { padding: 0 20px; } .category { - width: calc(100%/2 - 14px); + width: calc(100% / 2 - 14px); + } + + .gradebookGrid { + display: flex; + flex-direction: column; + } + + .section { + width: 100%; } } @@ -112,4 +237,9 @@ span.red { .category { width: 100%; } + + .backToCourseButton { + position: relative; // 🟒 FIX: Prevents it from overlapping content on small screens + margin-top: 10px; + } } \ No newline at end of file diff --git a/devU-client/src/components/pages/gradebook/gradebookStudentPage.tsx b/devU-client/src/components/pages/gradebook/gradebookStudentPage.tsx index c7c4c2e6..75f090c0 100644 --- a/devU-client/src/components/pages/gradebook/gradebookStudentPage.tsx +++ b/devU-client/src/components/pages/gradebook/gradebookStudentPage.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { useHistory, useParams } from 'react-router-dom'; import { useAppSelector } from 'redux/hooks'; -import { Assignment, AssignmentScore } from 'devu-shared-modules'; +import { Assignment, AssignmentScore, Course } from 'devu-shared-modules'; import PageWrapper from 'components/shared/layouts/pageWrapper'; import LoadingOverlay from 'components/shared/loaders/loadingOverlay'; @@ -21,7 +21,7 @@ const GradebookStudentPage = () => { const { courseId } = useParams<{ courseId: string }>(); const userId = useAppSelector((store) => store.user.id); const history = useHistory(); - + const [courseName, setCourseName] = useState(""); useEffect(() => { fetchData(); @@ -34,7 +34,10 @@ const GradebookStudentPage = () => { const assignmentScores = await RequestService.get(`/api/course/${courseId}/assignment-scores/user/${userId}`); setAssignmentScores(assignmentScores); - + + const courseData = await RequestService.get(`/api/courses/${courseId}`); + setCourseName(courseData.name); + } catch (error: any) { setError(error); } finally { @@ -45,50 +48,125 @@ const GradebookStudentPage = () => { if (loading) return ; if (error) return ; - const categories = [...new Set(assignments.map(a => a.categoryName))]; + // Categorize assignments + const homeworks = assignments.filter(a => a.categoryName === "Homework"); + const lectureQuestions = assignments.filter(a => a.categoryName === "Lecture Questions"); + const projects = assignments.filter(a => a.categoryName === "Project"); + + const calculateAverage = () => { + if (assignmentScores.length === 0) return 0.0; + const total = assignmentScores.reduce((sum, a) => sum + (a.score || 0), 0); + return (total / assignmentScores.length).toFixed(1); + }; + + const calculateHomeworkAverage = () => { + if (homeworks.length === 0) return "N/A"; + const totalScore = homeworks.reduce((sum, assignment) => sum + (assignmentScores.find(a => a.assignmentId === assignment.id)?.score || 0), 0); + return (totalScore / homeworks.length).toFixed(1); + }; return ( -
-

Student Gradebook

+ {/* Top Section with Back to Course Button */} +
+

{courseName} Gradebook

{role.isInstructor() && ( - )}
-
- {categories.map(category => ( -
-

{category}

- {/* Add table class */} -
- - {/* Add class for purple header */} - - - {/* */} - + +
+ {/* Homework - Left Column */} +
+
+ Homeworks + + Late Days + Score + +
+
AssignmentScore
+ + {homeworks.length > 0 ? ( + homeworks.map((assignment) => ( + + + + + + )) + ) : ( + + + + )} + + + + + +
{assignment.name}0{assignmentScores.find(a => a.assignmentId === assignment.id)?.score ?? 'N/A'}
No assignments yet
Category Average{calculateHomeworkAverage()}
+
+ + {/* Lecture Questions Section */} +
+
+ Lecture Questions + + Late Days + Score + +
+ {lectureQuestions.length > 0 ? ( + - {assignments.filter(a => a.categoryName === category).map((assignment, index) => ( - - - + {lectureQuestions.map((assignment) => ( + + + + ))}
-
- {assignment.name} -
-
- {/*
*/} - {assignmentScores.find(aScore => aScore.assignmentId === assignment.id)?.score ?? 'N/A'} - {/*
*/} -
{assignment.name}0{assignmentScores.find(a => a.assignmentId === assignment.id)?.score ?? 'N/A'}
+ ) : ( +
No assignments yet
+ )} +
+ + {/* Project Section */} +
+
+ Project + + Late Days + Score +
- ))} + {projects.length > 0 ? ( + + + {projects.map((assignment) => ( + + + + + + ))} + +
{assignment.name}0{assignmentScores.find(a => a.assignmentId === assignment.id)?.score ?? 'N/A'}
+ ) : ( +
No assignments yet
+ )} +
+ + {/* Course Average Section */} +
+ Course Average + {calculateAverage()} +
);