+ );
};
-export default Signup;
\ No newline at end of file
+export default Signup;
diff --git a/src/pages/courses/CourseCard.jsx b/src/pages/courses/CourseCard.jsx
index bc4451e..ae32e58 100644
--- a/src/pages/courses/CourseCard.jsx
+++ b/src/pages/courses/CourseCard.jsx
@@ -1,49 +1,53 @@
import { BookOpen } from "lucide-react";
import { useNavigate } from "react-router-dom";
-import { useSelector } from 'react-redux';
-import { themeConfig } from '../../themeConfig';
-import {iconColors} from "../../utils/styles.js";
+import { useSelector } from "react-redux";
+import { themeConfig } from "../../themeConfig";
+import { iconColors } from "../../utils/styles.js";
import React from "react";
const CourseCard = ({ id, title, department, credits }) => {
- const navigate = useNavigate();
- const { theme } = useSelector((state) => state.theme);
- const { bg, text, border, hoverBg } = themeConfig[theme];
-
- const handleCourseClick = () => navigate(`/course/${id}`);
-
- const handleCourseClick2 = () => navigate(`/courses/${id}/CourseEdit`);
-
- return (
-
+ );
};
-export default CourseCard;
\ No newline at end of file
+export default CourseCard;
diff --git a/src/pages/courses/CourseGrid.jsx b/src/pages/courses/CourseGrid.jsx
index efc93e6..dfe2661 100644
--- a/src/pages/courses/CourseGrid.jsx
+++ b/src/pages/courses/CourseGrid.jsx
@@ -1,97 +1,88 @@
import CourseCard from "./CourseCard.jsx";
import React from "react";
import axios from "axios";
-import {useSelector} from 'react-redux';
-import {themeConfig} from '../../themeConfig';
-import {useNavigate} from "react-router-dom";
+import { useSelector } from "react-redux";
+import { themeConfig } from "../../themeConfig";
+import { useNavigate } from "react-router-dom";
const CourseGrid = () => {
- const [courses, setCourses] = React.useState([]);
- const [loading, setLoading] = React.useState(true);
- const [error, setError] = React.useState(null);
- const user = JSON.parse(localStorage.getItem('user'));
- //const studentId = user?.id;
- const userId = user?.id;
- const userRole = user?.role;
- const {theme} = useSelector((state) => state.theme);
- const {bg, text} = themeConfig[theme];
- const navigate = useNavigate();
-
- React.useEffect(() => {
- if (!userId) {
- setError("No user ID found");
- setLoading(false);
- return;
- }
- let endpoint;
-
- if (userRole === 'STUDENT') {
- endpoint = `http://localhost:8080/api/courses/student/${userId}/summary`;
- } else if (userRole === 'INSTRUCTOR') {
- endpoint = `http://localhost:8080/api/courses/instructor/${userId}/summary`;
- } else {
- setError("Invalid user role");
- setLoading(false);
- return;
- }
-
-
- axios.get(endpoint)
- .then((response) => {
- setCourses(response.data);
- setLoading(false);
- })
- .catch(err => {
- console.error('Error fetching courses:', err);
- setError('Error fetching courses');
- setLoading(false);
- });
- }, [userId, userRole]);
-
-
- if (loading) return
Loading...
-
-
+ const [courses, setCourses] = React.useState([]);
+ const [loading, setLoading] = React.useState(true);
+ const [error, setError] = React.useState(null);
+ const user = JSON.parse(localStorage.getItem("user"));
+ const userId = user?.id;
+ const userRole = user?.role;
+ const { theme } = useSelector((state) => state.theme);
+ const { bg, text, accentBg } = themeConfig[theme];
+ const navigate = useNavigate();
+
+ React.useEffect(() => {
+ if (!userId) {
+ setError("No user ID found");
+ setLoading(false);
+ return;
+ }
+ let endpoint;
+
+ if (userRole === "STUDENT") {
+ endpoint = `http://localhost:8080/api/courses/student/${userId}/summary`;
+ } else if (userRole === "INSTRUCTOR") {
+ endpoint = `http://localhost:8080/api/courses/instructor/${userId}/summary`;
+ } else {
+ setError("Invalid user role");
+ setLoading(false);
+ return;
+ }
+
+ axios
+ .get(endpoint)
+ .then((response) => {
+ setCourses(response.data);
+ setLoading(false);
+ })
+ .catch((err) => {
+ console.error("Error fetching courses:", err);
+ setError("Error fetching courses");
+ setLoading(false);
+ });
+ }, [userId, userRole]);
+
+ if (loading) return
Loading...
;
+ if (error) return
{error}
;
+
+ return (
+
+ {(userRole === "INSTRUCTOR" || userRole === "ADMIN") && (
-
-
-
-
-
Your Courses
-
-
-
-
-
-
-
- {courses.length === 0 &&
No enrolled courses.
}
- {courses.map((course, index) => (
-
- ))}
-
-
-
+ )}
+
+
+
+ Your Courses
+
+
+
+
+
+ {courses.length === 0 &&
No enrolled courses.
}
+ {courses.map((course, index) => (
+
+ ))}
+
-
-
- );
+
+ );
};
-export default CourseGrid;
\ No newline at end of file
+export default CourseGrid;
diff --git a/src/pages/courses/course/AssignmentSubmission.jsx b/src/pages/courses/course/AssignmentSubmission.jsx
index f0ef106..875cbf7 100644
--- a/src/pages/courses/course/AssignmentSubmission.jsx
+++ b/src/pages/courses/course/AssignmentSubmission.jsx
@@ -1,922 +1,1123 @@
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
-import {ArrowLeft, Upload, X, Calendar, CheckCircle, Plus} from "lucide-react";
+import {
+ ArrowLeft,
+ Upload,
+ X,
+ Calendar,
+ CheckCircle,
+ Plus,
+} from "lucide-react";
import axios from "axios";
import { useSelector } from "react-redux";
import { themeConfig } from "../../../themeConfig";
import { iconColors } from "../../../utils/styles";
-import {getAssignmentsByCourse, createAssignment, submitAssignment, getSubmissionsByStudent, getSubmissionsByAssignment, updateAssignment, deleteAssignment} from '../../../services/api';
const AssignmentSubmission = () => {
- const {courseId, assignmentId} = useParams();
- const navigate = useNavigate();
- const {theme} = useSelector((state) => state.theme);
- const {bg, text, accentBg, border} = themeConfig[theme];
-
- // Get user
- const user = JSON.parse(localStorage.getItem("user"));
- const studentId = user?.id;
- const userRole = user?.role || 'STUDENT';
-
- // Form state for submission
- const [submissionForm, setSubmissionForm] = useState({
- text: "",
- fileName: "No file chosen"
- });
+ const { courseId, assignmentId } = useParams();
+ const navigate = useNavigate();
+ const { theme } = useSelector((state) => state.theme);
+ const { bg, text, accentBg, border } = themeConfig[theme];
- // Assignment and loading states
- const [assignment, setAssignment] = useState(null);
- const [assignments, setAssignments] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- // Submission data state for display (grades/feedback)
- const [submissionData, setSubmissionData] = useState({
- grade: null,
- feedback: null,
- isSubmitted: false,
- submittedFileName: null
- });
+ // Get user
+ const user = JSON.parse(localStorage.getItem("user"));
+ const studentId = user?.id;
+ const userRole = user?.role || "STUDENT";
- // Instructor states
- const [courseSubmissions, setCourseSubmissions] = useState([]);
- const [editAssignment, setEditAssignment] = useState(null);
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(null);
- const [submissions, setSubmissions] = useState([]);
- const [selectedSubmission, setSelectedSubmission] = useState(null);
- const [showGrade, setShowGrade] = useState(false);
- const [gradeForm, setGradeForm] = useState({
- grade: '',
- feedback: ''
- });
+ // Form state for submission
+ const [submissionForm, setSubmissionForm] = useState({
+ text: "",
+ fileName: "No file chosen",
+ });
- const [newAssignment, setNewAssignment] = useState({
- courseId: courseId,
- title: '',
- description: '',
- dueDate: ''
- });
+ // Assignment and loading states
+ const [assignment, setAssignment] = useState(null);
+ const [assignments, setAssignments] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
- useEffect(() => {
- if (courseId) {
- fetchAssignments();
- }
- }, [courseId]);
+ // Submission data state for display (grades/feedback)
+ const [submissionData, setSubmissionData] = useState({
+ grade: null,
+ feedback: null,
+ isSubmitted: false,
+ submittedFileName: null,
+ });
- useEffect(() => {
- if (userRole === 'STUDENT' && assignmentId && studentId && courseId) {
- fetchSubmissions();
- }
- }, [assignmentId, userRole, studentId, courseId]);
+ // Instructor states
+ const [courseSubmissions, setCourseSubmissions] = useState([]);
+ const [editAssignment, setEditAssignment] = useState(null);
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(null);
+ const [submissions, setSubmissions] = useState([]);
+ const [selectedSubmission, setSelectedSubmission] = useState(null);
+ const [showGrade, setShowGrade] = useState(false);
+ const [gradeForm, setGradeForm] = useState({
+ grade: "",
+ feedback: "",
+ });
- useEffect(() => {
- if (assignmentId && assignments.length > 0) {
- const foundAssignment = assignments.find(a => a.id.toString() === assignmentId);
- setAssignment(foundAssignment);
- }
- }, [assignmentId, assignments]);
-
- // Fallback useEffect for assignment fetching
- useEffect(() => {
- if (!assignment && assignmentId) {
- setLoading(true);
- axios
- .get(`http://localhost:8080/api/courses/${courseId}/assignments/${assignmentId}`)
- .then((response) => {
- setAssignment(response.data);
- setLoading(false);
- })
- .catch((err) => {
- setError(err.message || "Assignment not found");
- setLoading(false);
- });
- }
- }, [courseId, assignmentId, assignment]);
-
- const fetchAssignments = async () => {
- setLoading(true);
- try {
- const response = await getAssignmentsByCourse(courseId);
- setAssignments(response.data);
-
- if (userRole === 'STUDENT' && studentId) {
- fetchSubmissions();
- } else if (userRole === 'INSTRUCTOR') {
- fetchCourseSubmissions();
- }
- setLoading(false);
- } catch (err) {
- setError(err.message || "Assignment not found");
- setLoading(false);
- }
- };
-
- const fetchSubmissions = async () => {
- try {
- const response = await getSubmissionsByStudent(courseId, studentId);
- setSubmissions(response.data);
-
- if (assignmentId) {
- const currentSubmission = response.data.find(s =>
- s.assignmentId && s.assignmentId.toString() === assignmentId
- );
-
- if (currentSubmission) {
- setSubmissionData({
- grade: currentSubmission.grade,
- feedback: currentSubmission.feedback,
- isSubmitted: !!currentSubmission.submittedFileName,
- submittedFileName: currentSubmission.submittedFileName
- });
- } else {
- setSubmissionData({
- grade: null,
- feedback: null,
- isSubmitted: false,
- submittedFileName: null
- });
- }
- }
- } catch (err) {
- if (err.response?.status !== 404) {
- console.error('Error fetching submissions:', err);
- }
- }
- };
-
- const fetchCourseSubmissions = async () => {
- try {
- if (assignmentId) {
- const response = await getSubmissionsByAssignment(courseId, assignmentId);
- setCourseSubmissions(response.data);
- } else {
- setCourseSubmissions([]);
- }
- } catch (err) {
- if (err.response?.status === 404) {
- setCourseSubmissions([]);
- } else {
- console.error('Error fetching assignment submissions:', err);
- setCourseSubmissions([]);
- }
- }
- };
-
- const handleFileChange = (e) => {
- const file = e.target.files[0];
- if (file) {
- setSubmissionForm((prev) => ({
- ...prev,
- fileName: file.name
- }));
- }
- };
+ const [newAssignment, setNewAssignment] = useState({
+ courseId: courseId,
+ title: "",
+ description: "",
+ dueDate: "",
+ });
- const clearFile = () => {
- setSubmissionForm((prev) => ({ ...prev, fileName: "No file chosen" }));
- const fileInput = document.getElementById('assignmentFile');
- if (fileInput) {
- fileInput.value = '';
- }
- };
+ useEffect(() => {
+ if (courseId) {
+ fetchAssignments();
+ }
+ }, [courseId]);
- const handleSubmit = async (e) => {
- e.preventDefault();
+ useEffect(() => {
+ if (userRole === "STUDENT" && assignmentId && studentId && courseId) {
+ fetchSubmissions();
+ }
+ }, [assignmentId, userRole, studentId, courseId]);
- try {
- const fileInput = document.getElementById('assignmentFile');
- const file = fileInput.files[0];
+ useEffect(() => {
+ if (assignmentId && assignments.length > 0) {
+ const foundAssignment = assignments.find(
+ (a) => a.id.toString() === assignmentId,
+ );
+ setAssignment(foundAssignment);
+ }
+ }, [assignmentId, assignments]);
- if (!file) {
- alert('Please select a file to submit');
- return;
- }
+ // Fallback useEffect for assignment fetching
+ useEffect(() => {
+ if (!assignment && assignmentId) {
+ setLoading(true);
+ axios
+ .get(
+ `http://localhost:8080/api/courses/${courseId}/assignments/${assignmentId}`,
+ )
+ .then((response) => {
+ setAssignment(response.data);
+ setLoading(false);
+ })
+ .catch((err) => {
+ setError(err.message || "Assignment not found");
+ setLoading(false);
+ });
+ }
+ }, [courseId, assignmentId, assignment]);
- await submitAssignment(courseId, assignmentId, studentId, file);
- alert('Assignment submitted successfully!');
+ const fetchAssignments = async () => {
+ setLoading(true);
+ try {
+ const response = await axios.get(
+ `http://localhost:8080/api/courses/${courseId}/assignments`,
+ );
+ setAssignments(response.data);
- setSubmissionData(prev => ({
- ...prev,
- isSubmitted: true,
- submittedFileName: file.name
- }));
+ if (userRole === "STUDENT" && studentId) {
+ await fetchSubmissions();
+ } else if (userRole === "INSTRUCTOR") {
+ await fetchCourseSubmissions();
+ }
+ setLoading(false);
+ } catch (err) {
+ setError(err.message || "Assignment not found");
+ setLoading(false);
+ }
+ };
- await fetchSubmissions();
- setSubmissionForm({text: '', fileName: 'No file chosen'});
- fileInput.value = '';
+ const fetchSubmissions = async () => {
+ try {
+ const response = await axios.get(
+ `http://localhost:8080/api/courses/${courseId}/submissions/student/${studentId}`,
+ );
+ setSubmissions(response.data);
- } catch (err) {
- console.error("Submission error:", err);
- alert("Failed to submit assignment");
- }
- };
-
- const handleDownload = async () => {
- try {
- const currentSubmission = submissions.find(s =>
- s && s.assignmentId && s.assignmentId.toString() === assignmentId
- );
-
- if (!currentSubmission) {
- alert('Submission not found');
- return;
- }
-
- const response = await axios.get(
- `http://localhost:8080/api/courses/${courseId}/submissions/${assignmentId}/student/${studentId}/download`,
- { responseType: 'blob' }
- );
-
- const url = window.URL.createObjectURL(new Blob([response.data]));
- const a = document.createElement('a');
- a.href = url;
- a.setAttribute('download', submissionData.submittedFileName || currentSubmission.fileName || 'download');
- document.body.appendChild(a);
- a.click();
- a.remove();
- window.URL.revokeObjectURL(url);
- } catch (err) {
- console.error('Download error:', err);
- alert('Failed to download file');
- }
- };
-
- const handleCreateAssignment = async (e) => {
- e.preventDefault();
-
- try {
- await createAssignment(courseId, newAssignment);
- alert('Assignment created successfully!');
- setNewAssignment({courseId: courseId, title: '', description: '', dueDate: ''});
- fetchAssignments();
- } catch (err) {
- console.error('Error creating assignment:', err);
- alert('Error creating assignment: ' + (err.response?.data?.message || err.message));
- }
- };
-
- const handleEditAssignment = (assignmentToEdit) => {
- setEditAssignment(assignmentToEdit);
- setNewAssignment({
- courseId: courseId,
- title: assignmentToEdit.title,
- description: assignmentToEdit.description,
- dueDate: assignmentToEdit.dueDate.slice(0, 16)
- });
- };
-
- const cancelEdit = () => {
- setEditAssignment(null);
- setNewAssignment({courseId: courseId, title: '', description: '', dueDate: ''});
- };
-
- const handleUpdateAssignment = async (e) => {
- e.preventDefault();
-
- try {
- await updateAssignment(editAssignment.courseId, editAssignment.id, newAssignment);
- alert('Assignment updated successfully!');
- setNewAssignment({courseId: courseId, title: '', description: '', dueDate: ''});
- setEditAssignment(null);
- fetchAssignments();
- } catch (err) {
- console.error('Error updating assignment:', err);
- alert('Error updating assignment: ' + (err.response?.data?.message || err.message));
- }
- };
-
- const handleDeleteAssignment = async (assignmentId) => {
- try {
- await deleteAssignment(courseId, assignmentId);
- alert('Assignment deleted successfully!');
- setShowDeleteConfirm(null);
- fetchAssignments();
- } catch (err) {
- console.error('Error deleting assignment:', err);
- alert('Error deleting assignment: ' + (err.response?.data?.message || err.message));
- }
- };
+ if (assignmentId) {
+ const currentSubmission = response.data.find(
+ (s) => s.assignmentId && s.assignmentId.toString() === assignmentId,
+ );
- const handleGradeSubmission = (submission) => {
- setSelectedSubmission(submission);
- setGradeForm({
- grade: submission.grade || '',
- feedback: submission.feedback || ''
- });
- setShowGrade(true);
- };
-
- const handleGrade = async () => {
- try {
- await axios.put(
- `http://localhost:8080/api/courses/${courseId}/submissions/${assignmentId}/student/${selectedSubmission.studentId}`,
- {
- grade: gradeForm.grade,
- feedback: gradeForm.feedback
- }
- );
-
- alert('Grade and feedback saved successfully!');
- setShowGrade(false);
- fetchCourseSubmissions();
-
- } catch (err) {
- console.error('Error saving grade:', err);
- alert('Failed to save grade: ' + (err.response?.data?.message || err.message));
+ if (currentSubmission) {
+ setSubmissionData({
+ grade: currentSubmission.grade,
+ feedback: currentSubmission.feedback,
+ isSubmitted: !!currentSubmission.submittedFileName,
+ submittedFileName: currentSubmission.submittedFileName,
+ });
+ } else {
+ setSubmissionData({
+ grade: null,
+ feedback: null,
+ isSubmitted: false,
+ submittedFileName: null,
+ });
}
- };
-
- const handleDownloadSubmission = async (submission) => {
- try {
- const response = await axios.get(
- `http://localhost:8080/api/courses/${courseId}/submissions/${assignmentId}/student/${submission.studentId}/download`,
- { responseType: 'blob' }
- );
-
- const url = window.URL.createObjectURL(new Blob([response.data]));
- const a = document.createElement('a');
- a.href = url;
- a.setAttribute('download', submission.submittedFileName || 'submission');
- document.body.appendChild(a);
- a.click();
- a.remove();
- window.URL.revokeObjectURL(url);
- } catch (err) {
- console.error('Download error:', err);
- alert('Failed to download file');
- }
- };
+ }
+ } catch (err) {
+ if (err.response?.status !== 404) {
+ console.error("Error fetching submissions:", err);
+ }
+ }
+ };
- const handleGoBack = () => navigate(`/course/${courseId}/assignments`);
+ const fetchCourseSubmissions = async () => {
+ try {
+ if (assignmentId) {
+ const response = await axios.get(
+ `http://localhost:8080/api/courses/${courseId}/submissions/${assignmentId}/submissions`,
+ );
+ setCourseSubmissions(response.data);
+ } else {
+ setCourseSubmissions([]);
+ }
+ } catch (err) {
+ if (err.response?.status === 404) {
+ setCourseSubmissions([]);
+ } else {
+ console.error("Error fetching assignment submissions:", err);
+ setCourseSubmissions([]);
+ }
+ }
+ };
- if (loading) return
Loading assignment...
;
- if (error && userRole === 'STUDENT') return
Error: {error}
;
- if (!assignment && assignmentId && userRole === 'STUDENT') return
Assignment not found!
;
+ const handleFileChange = (e) => {
+ const file = e.target.files[0];
+ if (file) {
+ setSubmissionForm((prev) => ({
+ ...prev,
+ fileName: file.name,
+ }));
+ }
+ };
- return (
-
-
-