diff --git a/public/assets/icons/info.png b/public/assets/icons/info.png
new file mode 100644
index 0000000..e0626be
Binary files /dev/null and b/public/assets/icons/info.png differ
diff --git a/src/App.tsx b/src/App.tsx
index c0ba75c..6f070c2 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -27,6 +27,7 @@ import Questionnaire from "pages/EditQuestionnaire/Questionnaire";
import Courses from "pages/Courses/Course";
import CourseEditor from "pages/Courses/CourseEditor";
import { loadCourseInstructorDataAndInstitutions } from "pages/Courses/CourseUtil";
+import StudentTasks from "./pages/StudentTasks/StudentTasks";
import TA from "pages/TA/TA";
import TAEditor from "pages/TA/TAEditor";
import { loadTAs } from "pages/TA/TAUtil";
@@ -47,6 +48,10 @@ function App() {
{ path: "login", element: },
{ path: "logout", element: } /> },
{ path: "edit-questionnaire", element: } /> },
+ {
+ path: "student_tasks",
+ element: } leastPrivilegeRole={ROLE.STUDENT} />,
+ },
{
path: "assignments/edit/:id/createteams",
element: ,
@@ -274,4 +279,4 @@ function App() {
return ;
}
-export default App;
+export default App;
\ No newline at end of file
diff --git a/src/pages/StudentTasks/StudentTaskDetail.tsx b/src/pages/StudentTasks/StudentTaskDetail.tsx
new file mode 100644
index 0000000..aff3053
--- /dev/null
+++ b/src/pages/StudentTasks/StudentTaskDetail.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { useParams } from 'react-router-dom';
+
+const StudentTaskDetail: React.FC = () => {
+ const { id } = useParams(); // To grab the ID from the URL
+
+ return (
+
+
Assignment Title: {id}
+ {/* Details about the assignment could be fetched and displayed here */}
+
+ );
+};
+
+export default StudentTaskDetail;
\ No newline at end of file
diff --git a/src/pages/StudentTasks/StudentTasks.module.css b/src/pages/StudentTasks/StudentTasks.module.css
new file mode 100644
index 0000000..165eb27
--- /dev/null
+++ b/src/pages/StudentTasks/StudentTasks.module.css
@@ -0,0 +1,210 @@
+/* Base container styling */
+.container {
+ font-family: Arial, sans-serif;
+ margin: 20px;
+}
+
+/* Header 1 styling */
+h1 {
+ text-align: left;
+ padding-top: 5px;
+ padding-left: 15px;
+ margin-bottom: 0px;
+ padding-bottom: 0px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 1.428571429;
+ color: #333333;
+}
+
+/* Table base styling */
+table {
+ width: 100%;
+ border-collapse: collapse;
+ margin-top: 20px;
+}
+
+/* Table, th, and td shared border styling */
+table,
+th,
+td {
+ border: 1px solid #ddd;
+}
+
+/* Table header styling */
+th {
+ background-color: #f8f8f8;
+ color: #333;
+ text-align: left;
+ padding: 8px;
+}
+
+/* Table data cell styling */
+td {
+ padding: 8px;
+ text-align: left;
+}
+
+/* First child of th and td border styling */
+th:first-child,
+td:first-child {
+ border-left: none;
+}
+
+/* Last child of th and td border styling */
+th:last-child,
+td:last-child {
+ border-right: none;
+}
+
+/* Table row striping for even rows */
+tr:nth-child(even) {
+ background-color: #f2f2f2;
+}
+
+/* Badge info icon and publishing rights checkbox styling */
+.badge-info-icon,
+.publishing-rights-checkbox {
+ cursor: pointer;
+ margin-left: 5px;
+}
+
+/* Checked state styling for publishing rights checkbox */
+.publishing-rights-checkbox:checked {
+ accent-color: #009688;
+}
+
+/* Table header row font styling */
+thead tr {
+ font-weight: bold;
+}
+
+/* Status indicator icons styling */
+.status-indicator {
+ color: #009688;
+ margin-left: 5px;
+}
+
+/* Disabled state styling for checkboxes */
+input[type="checkbox"][disabled] {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+/* Information icon styling in table */
+.info-icon {
+ font-style: normal;
+ color: #017bff;
+ cursor: help;
+}
+
+/* Side information section styling */
+.side-info {
+ color: #333;
+ padding: 10px 0;
+}
+
+/* Number styling in side information section */
+.side-info .number {
+ font-weight: bold;
+ color: #d9534f; /* Red color for the number badge */
+}
+
+/* New styles for the links based on the uploaded image */
+table td {
+ padding: 8px; /* Padding specified in your screenshot */
+ max-width: 100px; /* Adjust the width as needed for your design */
+ white-space: normal;
+ padding: 8px;
+ line-height: 1.428571429;
+ vertical-align: top;
+ border-top: 1px solid #ddd;
+}
+
+/* Table data cell link styling */
+table td a {
+ color: #986633;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ padding: 0px 1px 2px;
+ display: block;
+ margin: 10px 0;
+ text-decoration: none;
+ font-weight: bold;
+ border-radius: 4px;
+ transition: box-shadow 0.2s ease-in-out, background-color 0.3s;
+}
+
+/* Table data cell link hover and focus styling */
+table td a:hover, table td a:focus {
+ color: #337ab7;
+ text-decoration: underline;
+}
+
+/* Page layout styling */
+.pageLayout {
+ display: flex;
+ margin: 16px;
+}
+
+/* Sidebar styling */
+.sidebar {
+ width: 250px;
+ margin-right: 20px;
+ padding-top: 20px;
+}
+
+/* Main content area styling */
+.mainContent {
+ flex-grow: 1;
+ overflow: hidden;
+}
+
+/* Header below pageLayout styling */
+.header {
+ margin-bottom: 20px;
+}
+
+/* Tasks table styling */
+.tasksTable {
+ width: 100%;
+}
+
+/* Page assignments styling */
+.assignments-page {
+ font-family: 'Arial', sans-serif;
+}
+
+/* Title in assignments page styling */
+.assignments-title {
+ color: #333;
+ text-align: left;
+ padding: 20px;
+ font-size: 24px;
+}
+
+/* Footer section styling */
+.footer {
+ display: flex;
+ justify-content: center;
+ padding: 20px 0;
+}
+
+/* Footer link styling */
+.footerLink {
+ margin: 0 10px;
+ color: #986633;
+ text-decoration: none;
+}
+
+/* Footer link hover styling */
+.footerLink:hover {
+ color: #000000;
+ text-decoration: underline;
+}
+
+/* Center checkbox in table data cell styling */
+.centerCheckbox {
+ text-align: center;
+ vertical-align: middle;
+}
diff --git a/src/pages/StudentTasks/StudentTasks.tsx b/src/pages/StudentTasks/StudentTasks.tsx
new file mode 100644
index 0000000..38f9336
--- /dev/null
+++ b/src/pages/StudentTasks/StudentTasks.tsx
@@ -0,0 +1,142 @@
+import React, { useState, useEffect, useCallback } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import { useNavigate, Link } from 'react-router-dom';
+import { RootState } from '../../store/store';
+import useAPI from 'hooks/useAPI';
+import styles from './StudentTasks.module.css';
+import StudentTasksBox from './StudentTasksBox';
+import testData from './testData.json';
+
+// Define the types for a single task and the associated course
+type Task = {
+ id: number;
+ assignment: string;
+ course: string;
+ topic: string;
+ currentStage: string;
+ reviewGrade: string | { comment: string };
+ badges: string | boolean;
+ stageDeadline: string;
+ publishingRights: boolean;
+};
+
+// Empty props for FC as no props are needed currently
+type Props = {};
+
+// Main functional component for Student Tasks
+const StudentTasks: React.FC = () => {
+ // State and hooks initialization
+ const participantTasks = testData.participantTasks;
+ const currentUserId = testData.current_user_id;
+ const auth = useSelector((state: RootState) => state.authentication);
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+
+ // State to hold tasks
+ const [tasks, setTasks] = useState([]);
+ const exampleDuties = testData.dueTasks;
+ const taskRevisions = testData.revisions;
+ const studentsTeamedWith = testData.studentsTeamedWith;
+
+ // Effect to process tasks on component mount or update
+ useEffect(() => {
+ if (participantTasks) {
+ const filteredParticipantTasks = participantTasks.filter(task => task.participant_id === currentUserId);
+
+ const mergedTasks = filteredParticipantTasks.map(task => {
+ return {
+ id: task.id,
+ assignment: task.assignment,
+ course: task.course,
+ topic: task.topic || '-',
+ currentStage: task.current_stage || 'Pending',
+ reviewGrade: task.review_grade || 'N/A',
+ badges: task.badges || '',
+ stageDeadline: task.stage_deadline || 'No deadline',
+ publishingRights: task.publishing_rights || false
+ };
+ });
+ setTasks(mergedTasks);
+ }
+ }, [participantTasks]);
+
+ // Callback to toggle publishing rights
+ const togglePublishingRights = useCallback((id: number) => {
+ setTasks(prevTasks => prevTasks.map(task =>
+ task.id === id ? {...task, publishingRights: !task.publishingRights} : task
+ ));
+ }, []);
+
+ const showBadges = tasks.some(task => task.badges);
+
+ // Component render method
+ return (
+
+
Assignments
+
+
+ {/* Footer section */}
+
+ Help
+ Papers on Expertiza
+
+
+ );
+};
+
+// Export the component for use in other parts of the application
+export default StudentTasks;
diff --git a/src/pages/StudentTasks/StudentTasksBox.module.css b/src/pages/StudentTasks/StudentTasksBox.module.css
new file mode 100644
index 0000000..3db98a7
--- /dev/null
+++ b/src/pages/StudentTasks/StudentTasksBox.module.css
@@ -0,0 +1,120 @@
+/* Stripes for odd rows in a table within .student-tasks */
+.student-tasks .table-striped>tbody>tr:nth-of-type(odd)>td,
+.student-tasks .table-striped>tbody>tr:nth-of-type(odd)>th {
+ background-color: #ffffff;
+ --bs-table-bg-type: none
+}
+
+/* Stripes for even rows in a table within .student-tasks */
+.student-tasks .table-striped>tbody>tr:nth-of-type(even)>td,
+.student-tasks .table-striped>tbody>tr:nth-of-type(even)>th {
+ background-color: #f2f2f2;
+ --bs-table-bg-type: none;
+}
+
+/* Styling for task boxes */
+.taskbox {
+ padding: 5px;
+ margin-bottom: 39px;
+ border: 1px dashed #999999;
+ float: left;
+ font-size: 12px;
+ background: none repeat scroll 0pt 0pt #fafaea;
+ width: 100%;
+}
+
+/* Styling for the task number indicator */
+.tasknum {
+ color: #FFFFFF;
+ background-color: #B73204;
+}
+
+/* Styling for the revision number indicator */
+.revnum {
+ color: #FFFFFF;
+ background-color: #999999;
+}
+
+/* Styling for notification links */
+.notification a {
+ color:#0066CC
+}
+
+/* Layout for the page containing the student tasks */
+.pageLayout {
+ display: flex;
+ margin: 16px;
+}
+
+/* Fixed-width sidebar styling */
+.sidebar {
+ width: 200px; /* Width of the sidebar */
+ margin-right: 20px; /* Spacing between sidebar and main content */
+}
+
+/* Main content area that grows to fill the space */
+.mainContent {
+ flex-grow: 1;
+ overflow: hidden; /* In case the content is too wide */
+}
+
+/* Styling for the page header */
+.header {
+ margin-bottom: 20px; /* Space below the header */
+}
+
+/* Full-width table styling */
+.tasksTable {
+ width: 100%; /* Full width of the main content area */
+ /* Add more styling for your table */
+}
+
+/* Margin styling for sections */
+.section {
+ margin-bottom: 20px; /* Space between sections */
+}
+
+/* Header styling within sections */
+.section-header {
+ font-size: 18px; /* Larger font size for visibility */
+ font-weight: bold; /* Bold text for section headers */
+ color: #333; /* Darker text for better readability */
+ margin-bottom: 10px; /* Space below section header */
+}
+
+/* Styling for individual items within a section */
+.section-item {
+ margin-left: 20px; /* Indent for items in the list */
+ margin-bottom: 5px; /* Space between items */
+ color: #555; /* Slightly lighter text for items */
+}
+
+/* Standard badge styling */
+.badge {
+ display: inline-block;
+ padding: 0.25em 0.4em;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: 0;
+ padding: 1;
+ background-color: #a52a2a;
+ color: white;
+}
+
+/* Grey badge variant */
+.greyBadge{
+ padding: 0.25em 0.4em;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: 0;
+ background-color: rgb(159, 156, 156);
+ color: white;
+}
diff --git a/src/pages/StudentTasks/StudentTasksBox.tsx b/src/pages/StudentTasks/StudentTasksBox.tsx
new file mode 100644
index 0000000..6da727f
--- /dev/null
+++ b/src/pages/StudentTasks/StudentTasksBox.tsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import styles from './StudentTasksBox.module.css';
+
+ type DueTask = {
+
+ };
+
+ type Revision = {
+ name: string;
+ dueDate: string;
+ };
+
+ //Students teamed with data structure
+ type StudentsTeamedWith = {
+ [semester: string]: string[];
+ };
+
+ // interface for Student task box data
+ interface StudentTasksBoxProps {
+ dueTasks: DueTask[];
+ revisions: Revision[];
+ studentsTeamedWith: StudentsTeamedWith;
+ }
+
+ const StudentTasksBox: React.FC = ({ dueTasks, revisions, studentsTeamedWith }) => {
+
+ let totalStudents = 0;
+ for (const semester in studentsTeamedWith) {
+ totalStudents += studentsTeamedWith[semester].length;
+ }
+
+ // Function to calculate the number of days left until the due date
+ const calculateDaysLeft = (dueDate: string) => {
+ const today = new Date();
+ const due = new Date(dueDate);
+ const timeDiff = due.getTime() - today.getTime();
+ const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
+ return daysDiff > 0 ? daysDiff : 0;
+ };
+
+ // Find the revisions that have not done yet based on the due date
+ const revisedTasks = revisions.filter(revisions => calculateDaysLeft(revisions.dueDate) > 0);
+
+// HTML for student task box
+ return (
+
+
+ 0
+ Tasks not yet started
+
+
+ {/* Revisions section (remains empty since revisions array is empty) */}
+
+
{revisedTasks.length}
+
Revisions
+ {revisedTasks.map((task, index) => {
+ const daysLeft = calculateDaysLeft(task.dueDate);
+ return (
+
+ » {task.name} ({daysLeft} day{daysLeft !== 1 ? 's' : ''} left)
+
+ );
+ })}
+
+
+
+ {/* Students who have teamed with you section */}
+
+ {totalStudents}
+ Students who have teamed with you
+
+ {Object.entries(studentsTeamedWith).map(([semester, students], index) => (
+
+
{semester}
+
{students.length}
+ {students.map((student, studentIndex) => (
+
+ » {student}
+
+ ))}
+
+ ))}
+
+ );
+};
+
+// Exporting the component for use in other parts of the application
+export default StudentTasksBox;
diff --git a/src/pages/StudentTasks/testData.json b/src/pages/StudentTasks/testData.json
new file mode 100644
index 0000000..d068855
--- /dev/null
+++ b/src/pages/StudentTasks/testData.json
@@ -0,0 +1,170 @@
+
+{
+ "participantTasks": [
+ {
+ "id": 1,
+ "assignment": "Program 1",
+ "course": "CSC 517",
+ "topic": "Ruby",
+ "current_stage": "In progress",
+ "review_grade": {
+ "comment": "40/40"
+ },
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": true,
+ "participant_id": 1
+ },
+ {
+ "id": 2,
+ "assignment": "Program 2",
+ "course": "CSC 517",
+ "topic": "Rails",
+ "current_stage": "In progress",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": false,
+ "participant_id": 2
+ },
+ {
+ "id": 3,
+ "assignment": "Program 3",
+ "course": "CSC 517",
+ "topic": "Git",
+ "current_stage": "In progress",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": false,
+ "participant_id": 1
+ },
+ {
+ "id": 4,
+ "assignment": "Program 4",
+ "course": "CSC 517",
+ "topic": "Reimplementation Backend",
+ "current_stage": "In progress",
+ "review_grade": "120/120",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": true,
+ "participant_id": 1
+ },
+ {
+ "id": 5,
+ "assignment": "Program 5",
+ "course": "CSC 517",
+ "topic": "Reimplementation Frontend",
+ "current_stage": "Finished",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": false,
+ "participant_id": 1
+ },
+ {
+ "id": 6,
+ "assignment": "OSS Program 1",
+ "course": "CSC 517",
+ "topic": "Reimplementation Frontend",
+ "current_stage": "Finished",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": false,
+ "participant_id": 1
+ },
+ {
+ "id": 7,
+ "assignment": "OSS Program 2",
+ "course": "CSC 517",
+ "topic": "Reimplementation Frontend",
+ "current_stage": "Finished",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": false,
+ "participant_id": 1
+ },
+ {
+ "id": 8,
+ "assignment": "Program 5",
+ "course": "CSC 517",
+ "topic": "Reimplementation Frontend",
+ "current_stage": "Finished",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": true,
+ "participant_id": 1
+ },
+ {
+ "id": 9,
+ "assignment": "Program 5",
+ "course": "CSC 517",
+ "topic": "Reimplementation Frontend",
+ "current_stage": "Finished",
+ "review_grade": "N/A",
+ "badges": false,
+ "stage_deadline": "2024-02-26 12:00:00 -0500",
+ "publishing_rights": true,
+ "participant_id": 1
+ }
+ ],
+ "courses": [
+ {
+ "id": 1,
+ "name": "Course3",
+ "directory_path": "/path/to/course_files",
+ "info": null,
+ "private": false,
+ "created_at": "2024-04-21T23:46:38.633Z",
+ "updated_at": "2024-04-21T23:46:38.633Z",
+ "instructor_id": 2,
+ "institution_id": 1
+ },
+ {
+ "id": 4,
+ "name": "Course4",
+ "directory_path": "/path/to/course_files",
+ "info": null,
+ "private": false,
+ "created_at": "2024-04-21T23:46:38.633Z",
+ "updated_at": "2024-04-21T23:46:38.633Z",
+ "instructor_id": 2,
+ "institution_id": 1
+ }
+
+ ],
+
+ "dueTasks": [
+
+ ],
+ "revisions": [
+ {
+ "name": "Program 1",
+ "dueDate": "2024-03-18"
+ },
+ {
+ "name": "Program 2",
+ "dueDate": "2024-03-18"
+ },
+ {
+ "name": "OSS project",
+ "dueDate": "2024-03-18"
+ },
+ {
+ "name": "OSS project 2",
+ "dueDate": "2024-03-25"
+ },
+ {
+ "name": "OSS project 3",
+ "dueDate": "2024-04-28"
+ }
+ ],
+ "studentsTeamedWith": {
+ "CSC/ECE 517, Fall 2024": ["teammate one", "teammate two", "teammate three", "teammate four","teammate five", "teammate six", "teammate seven"]
+ },
+ "current_user_id": 1
+}
\ No newline at end of file