diff --git a/.gitignore b/.gitignore
index 7f5b38cc7..1851250da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -141,3 +141,4 @@ dist
/client/package-lock.json
/server/package-lock.json
+.DS_Store
\ No newline at end of file
diff --git a/client/src/pages/CoordinatorCumulativeReviewForm.js b/client/src/pages/CoordinatorCumulativeReviewForm.js
new file mode 100644
index 000000000..0dd496df3
--- /dev/null
+++ b/client/src/pages/CoordinatorCumulativeReviewForm.js
@@ -0,0 +1,122 @@
+import React, { useEffect, useState } from "react";
+import { useParams, useNavigate } from "react-router-dom";
+import axios from "axios";
+import Swal from "sweetalert2";
+import "../styles/CoordinatorCumulativeReviewForm.css";
+
+const CoordinatorCumulativeReviewForm = () => {
+ const { groupIndex } = useParams();
+ const navigate = useNavigate();
+
+ const [reports, setReports] = useState([]);
+ const [coordinatorComment, setCoordinatorComment] = useState("");
+ const [supervisorComment, setSupervisorComment] = useState("");
+ const [loading, setLoading] = useState(true);
+
+ // Fetch the report group when component mounts
+ useEffect(() => {
+ const fetchGroup = async () => {
+ try {
+ const res = await axios.get(
+ `${process.env.REACT_APP_API_URL}/api/reports/cumulative/group/${groupIndex}`
+ );
+ if (res.data.success) {
+ const fetchedReports = res.data.group.reports || [];
+ setReports(fetchedReports);
+ setSupervisorComment(fetchedReports[0]?.supervisorComments || "Not available");
+ }
+ } catch (err) {
+ console.error("Failed to fetch group:", err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchGroup();
+ }, [groupIndex]);
+
+ // Submit coordinator comments for all reports in the group
+ const handleSubmit = async () => {
+ if (!coordinatorComment.trim()) {
+ Swal.fire("Error", "Comment cannot be empty.", "error");
+ return;
+ }
+
+ try {
+ const weeks = reports.map((report) => report.week); // extract weeks
+
+ await axios.post(`${process.env.REACT_APP_API_URL}/api/reports/coordinator-comments`, {
+ groupIndex: parseInt(groupIndex),
+ comments: coordinatorComment.trim(),
+ weeks,
+ });
+
+ Swal.fire("Success", "Coordinator comment submitted.", "success");
+
+ localStorage.setItem("reviewedGroupIndex", groupIndex); // ✅ For dashboard refresh
+ navigate("/coordinator-dashboard");
+ } catch (err) {
+ console.error("Failed to submit coordinator comment", err);
+ Swal.fire("Error", "Failed to submit comment. Please try again.", "error");
+ }
+ };
+
+
+ if (loading) {
+ return
Loading...
;
+ }
+
+ return (
+
+
Review Cumulative Weekly Reports
+
+
+
+
+ | Week |
+ Hours |
+ Tasks |
+ Lessons |
+
+
+
+ {reports.map((report, idx) => (
+
+ | {report.week} |
+ {report.hours} |
+ {report.tasks} |
+ {report.lessons} |
+
+ ))}
+
+
+
+
+
+
{supervisorComment}
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CoordinatorCumulativeReviewForm;
diff --git a/client/src/pages/CoordinatorDashboard.js b/client/src/pages/CoordinatorDashboard.js
index 8259b6507..ed7121555 100644
--- a/client/src/pages/CoordinatorDashboard.js
+++ b/client/src/pages/CoordinatorDashboard.js
@@ -1,48 +1,124 @@
import React, { useEffect, useState } from "react";
-import { useNavigate } from "react-router-dom";
import axios from "axios";
-import "../styles/dashboard.css";
-
-function CoordinatorDashboard() {
- const [requests, setRequests] = useState([]);
+import { useNavigate } from "react-router-dom";
+import "../styles/SupervisorDashboard.css";
+const CoordinatorDashboard = () => {
+ const [activeTab, setActiveTab] = useState("requests"); // 'requests' or 'reports'
const navigate = useNavigate();
+ // TEAM A's Internship Requests Logic
+ const [requests, setRequests] = useState([]);
+ const [loadingRequests, setLoadingRequests] = useState(true);
- const fetchRequests = async () => {
+ useEffect(() => {
+ if (activeTab === "requests") {
+ fetchInternshipRequests();
+ }
+ }, [activeTab]);
+
+ const fetchInternshipRequests = async () => {
try {
- const res = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/coordinator/requests`
- );
- setRequests(res.data);
+ const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/coordinator/requests`);
+ setRequests(res.data || []);
} catch (err) {
- console.error("Failed to fetch requests:", err);
+ console.error("Error fetching internship requests:", err);
+ } finally {
+ setLoadingRequests(false);
}
};
+ // Group D's Weekly Report Review Logic
+
+ const [reportGroups, setReportGroups] = useState([]);
+ const [loadingReports, setLoadingReports] = useState(true);
useEffect(() => {
- fetchRequests();
- }, []);
+ if (activeTab === "reports") {
+ fetchReportGroups();
+ }
+ }, [activeTab]);
+ const fetchReportGroups = async () => {
+ try {
+ const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/reports/supervised-groups`);
+ const filtered = res.data?.groups?.filter(group => {
+ const key = `coordinator_reviewed_${group.groupIndex}`;
+ return !localStorage.getItem(key);
+ });
+ setReportGroups(filtered || []);
+ } catch (err) {
+ console.error("Error fetching reports:", err);
+ } finally {
+ setLoadingReports(false);
+ }
+ };
+
+ const handleReviewClick = (group) => {
+ localStorage.setItem(`coordinator_reviewed_${group.groupIndex}`, "true");
+ navigate(`/review-cumulative/${group.groupIndex}`);
+ };
+
+
+ // Render UI
+
return (
-
Coordinator Dashboard
-
- {requests.length === 0 ? (
-
No Pending Requests
- ) : (
- requests.map((req) => (
-
navigate(`/coordinator/request/${req._id}`)}
- >
- {/*
{req.student.userName}
-
Email: {req.student.email}
*/}
-
Company: {req.workplace.name}
-
- ))
+
Coordinator Dashboard
+
+ {/* Tabs */}
+
+
+
+
+
+ {/* Tab: Internship Requests */}
+ {activeTab === "requests" && (
+ <>
+ {loadingRequests ?
Loading...
: (
+
+
+
+ | Student Name |
+ Student ID |
+ Company |
+ Status |
+
+
+
+ {requests.map(req => (
+
+ | {req.studentName} |
+ {req.studentId} |
+ {req.companyName} |
+ {req.status} |
+
+ ))}
+
+
+ )}
+ >
+ )}
+
+ {/* Tab: Weekly Reports Review */}
+ {activeTab === "reports" && (
+ <>
+ {loadingReports ?
Loading reports...
: (
+ reportGroups.length === 0
+ ?
No reports to review
+ : reportGroups.map(group => (
+
+
Weeks: {group.weeks?.join(", ")}
+
+ {group.reports.map((r, i) => (
+ - Week {r.week} — Hours: {r.hours} — Tasks: {r.tasks}
+ ))}
+
+
+
+ ))
+ )}
+ >
)}
);
-}
+};
export default CoordinatorDashboard;
diff --git a/client/src/pages/CoordinatorReviewForm.js b/client/src/pages/CoordinatorReviewForm.js
new file mode 100644
index 000000000..e3f793c34
--- /dev/null
+++ b/client/src/pages/CoordinatorReviewForm.js
@@ -0,0 +1,76 @@
+import React, { useEffect, useState } from "react";
+import axios from "axios";
+import { useParams, useNavigate } from "react-router-dom";
+import "../styles/CumulativeReviewForm.css";
+
+const CoordinatorReviewForm = () => {
+ const { groupIndex } = useParams();
+ const navigate = useNavigate();
+ const [reports, setReports] = useState([]);
+ const [comment, setComment] = useState("");
+ const [message, setMessage] = useState("");
+
+ useEffect(() => {
+ const fetchGroup = async () => {
+ try {
+ const res = await axios.get(
+ `${process.env.REACT_APP_API_URL}/api/reports/group/${groupIndex}`
+ );
+ if (res.data.success) {
+ setReports(res.data.group.reports);
+ }
+ } catch (err) {
+ console.error("Failed to load group reports", err);
+ }
+ };
+
+ fetchGroup();
+ }, [groupIndex]);
+
+ const handleSubmit = async () => {
+ try {
+ const promises = reports.map((r) =>
+ axios.put(
+ `${process.env.REACT_APP_API_URL}/api/reports/${r._id}/coordinator-comment`,
+ { coordinatorComments: comment }
+ )
+ );
+ await Promise.all(promises);
+ setMessage("Coordinator comment submitted successfully!");
+ setTimeout(() => navigate("/coordinator-dashboard"), 1500);
+ } catch (err) {
+ console.error("Failed to submit coordinator comments", err);
+ setMessage("Failed to submit comment.");
+ }
+ };
+
+ return (
+
+
Coordinator Review - Group {parseInt(groupIndex) + 1}
+
+ {reports.map((r, idx) => (
+
+
Week {r.week}
+
Hours: {r.hours}
+
Tasks: {r.tasks}
+
Lessons: {r.lessons}
+
Supervisor Comments: {r.supervisorComments}
+
+ ))}
+
+
+
+
+
+ {message &&
{message}
}
+
+ );
+};
+
+export default CoordinatorReviewForm;
diff --git a/client/src/pages/CumulativeReviewForm.js b/client/src/pages/CumulativeReviewForm.js
new file mode 100644
index 000000000..d621db4fc
--- /dev/null
+++ b/client/src/pages/CumulativeReviewForm.js
@@ -0,0 +1,134 @@
+import React, { useEffect, useState } from "react";
+import { useParams, useNavigate } from "react-router-dom";
+import axios from "axios";
+import Swal from "sweetalert2";
+import "../styles/CumulativeReviewForm.css";
+
+const CumulativeReviewForm = () => {
+ const { groupIndex } = useParams();
+ const navigate = useNavigate();
+
+ const [groupData, setGroupData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [comment, setComment] = useState("");
+
+ useEffect(() => {
+ const fetchGroup = async () => {
+ try {
+ const res = await axios.get(
+ `${process.env.REACT_APP_API_URL}/api/reports/cumulative/group/${groupIndex}`
+ );
+ setGroupData(res.data.group);
+ } catch (err) {
+ console.error("Failed to fetch group:", err);
+ Swal.fire({
+ icon: "error",
+ title: "Failed to load report group.",
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchGroup();
+ }, [groupIndex]);
+
+ const handleSubmit = async () => {
+ if (!comment.trim()) {
+ return Swal.fire({
+ icon: "warning",
+ title: "Comment cannot be empty!",
+ });
+ }
+
+ try {
+ await axios.post(
+ `${process.env.REACT_APP_API_URL}/api/reports/supervisor-comments`,
+ {
+ groupIndex: groupData.groupIndex,
+ comments: comment,
+ weeks: groupData.weeks,
+ }
+ );
+
+ Swal.fire({
+ icon: "success",
+ title: "Comment Submitted Successfully!",
+ timer: 1500,
+ showConfirmButton: false,
+ });
+
+ navigate("/supervisor-dashboard");
+ } catch (err) {
+ console.error("Error submitting comment:", err);
+ Swal.fire({
+ icon: "error",
+ title: "Failed to submit comment.",
+ });
+ }
+ };
+
+ if (loading) return Loading...
;
+ if (!groupData) return No data found.
;
+
+ return (
+
+
Review Cumulative Weekly Reports
+
+
+
+
+ | Week |
+ Hours |
+ Tasks |
+ Lessons |
+
+
+
+ {groupData.reports.map((report, index) => (
+
+ navigate(
+ `/weekly-report/${groupIndex}/week-${report.week}/${groupData.studentName}`,
+ {
+ state: { reportData: report },
+ }
+ )
+ }
+ >
+ | {report.week} |
+ {report.hours} |
+ {report.tasks} |
+ {report.lessons} |
+
+ ))}
+
+
+
+
+
+ );
+};
+
+export default CumulativeReviewForm;
diff --git a/client/src/pages/Home.js b/client/src/pages/Home.js
index 1c08db672..ffe18418f 100644
--- a/client/src/pages/Home.js
+++ b/client/src/pages/Home.js
@@ -259,4 +259,4 @@ function Home() {
);
}
-export default Home;
+export default Home;
\ No newline at end of file
diff --git a/client/src/pages/SubmittedReports.js b/client/src/pages/SubmittedReports.js
new file mode 100644
index 000000000..fb69be6e7
--- /dev/null
+++ b/client/src/pages/SubmittedReports.js
@@ -0,0 +1,70 @@
+import React, { useEffect, useState } from "react";
+import axios from "axios";
+import { useNavigate } from "react-router-dom";
+import "../styles/SubmittedReports.css";
+
+const SubmittedReports = () => {
+ const [reports, setReports] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ const fetchReports = async () => {
+ try {
+ const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/reports/mine`);
+ if (res.data.success) {
+ setReports(res.data.reports);
+ }
+ } catch (err) {
+ console.error("Error fetching reports", err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchReports();
+ }, []);
+
+ return (
+
+
Previous Weekly Reports
+
+ {loading ? (
+
Loading...
+ ) : reports.length === 0 ? (
+
No reports found.
+ ) : (
+
+
+
+ | Week |
+ Hours |
+ Tasks |
+ Lessons |
+ Supervisor Comments |
+
+
+
+ {reports.map((report) => (
+ navigate(`/submitted-reports/view/${report._id}`)}
+ >
+ | {report.week} |
+ {report.hours} |
+ {report.tasks} |
+ {report.lessons} |
+
+ {report.supervisorComments || "—"}
+ |
+
+ ))}
+
+
+ )}
+
+ );
+};
+
+export default SubmittedReports;
diff --git a/client/src/pages/SupervisorDashboard.js b/client/src/pages/SupervisorDashboard.js
index 8d3a692bf..4141a2aec 100644
--- a/client/src/pages/SupervisorDashboard.js
+++ b/client/src/pages/SupervisorDashboard.js
@@ -5,57 +5,57 @@ import ViewFormModal from "./ViewFormModal";
const SupervisorDashboard = () => {
const [requests, setRequests] = useState([]);
+ // const [cumulativeReports, setCumulativeReports] = useState([]);
const [selectedForm, setSelectedForm] = useState(null);
const [loading, setLoading] = useState(true);
const [message, setMessage] = useState("");
-
- useEffect(() => {
-
- // Token used for authentication for future
- // Now it will only be empty
- const token = localStorage.getItem("token") || "";
-
- const fetchRequests = async () => {
+
+ useEffect(() => {
+ const token = localStorage.getItem("token") || "";
+
+ const fetchRequests = async () => {
try {
- const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/supervisor/forms`,
+ const res = await axios.get(
+ `${process.env.REACT_APP_API_URL}/api/supervisor/forms`,
{
headers: {
Authorization: `Bearer ${token}`,
},
- });
-
- const formatted = res.data.map(item => ({
- _id: item._id,
- name: item.student_id?.userName || item.student_id?.name || "N/A",
- student_id: item.student?._id || item._id,
- form_type: item.form_type,
- createdAt: item.createdAt,
- supervisor_status: item.supervisor_status || "pending",
- fullForm: item,
- workplace: {
- name: item.workplace?.name || "N/A",
- website: item.workplace?.website || "N/A",
- phone: item.workplace?.phone || "N/A",
- },
- internshipAdvisor: {
- name: item.internshipAdvisor?.name || "N/A",
- jobTitle: item.internshipAdvisor?.jobTitle || "N/A",
- email: item.internshipAdvisor?.email || "N/A",
- },
- creditHours: item.creditHours || 0,
- startDate: item.startDate || "N/A",
- endDate: item.endDate || "N/A",
- tasks: item.tasks || [],
- status: item.status || "pending",
- supervisor_comment: item.supervisor_comment || "N/A"
+ }
+ );
+
+ const formatted = res.data.map((item) => ({
+ _id: item._id,
+ interneeName: item.interneeName || item.student_id?.userName || "N/A",
+ soonerId: item.soonerId || item.student_id?.soonerId || "N/A",
+ interneeEmail: item.interneeEmail || item.student_id?.email || "N/A",
+ form_type: item.form_type,
+ createdAt: item.createdAt,
+ supervisor_status: item.supervisor_status || "pending",
+ fullForm: item,
+ workplace: {
+ name: item.workplace?.name || "N/A",
+ website: item.workplace?.website || "N/A",
+ phone: item.workplace?.phone || "N/A",
+ },
+ internshipAdvisor: {
+ name: item.internshipAdvisor?.name || "N/A",
+ jobTitle: item.internshipAdvisor?.jobTitle || "N/A",
+ email: item.internshipAdvisor?.email || "N/A",
+ },
+ creditHours: item.creditHours || 0,
+ startDate: item.startDate || "N/A",
+ endDate: item.endDate || "N/A",
+ tasks: item.tasks || [],
+ status: item.status || "pending",
+ supervisor_comment: item.supervisor_comment || "N/A",
}));
-
setRequests(formatted);
- setLoading(false);
} catch (err) {
console.error("Error fetching forms:", err);
- setMessage("Error fetching forms.", err);
+ setMessage("Error fetching forms.");
+ } finally {
setLoading(false);
}
};
@@ -63,34 +63,34 @@ const SupervisorDashboard = () => {
fetchRequests();
}, []);
- const handleAction = async (id, form_type, action, comment) => {
+ const handleAction = async (form_type, id, action, comment, signature) => {
+ const token = localStorage.getItem("token");
- const token = localStorage.getItem("token");
-
- const confirmed = window.confirm(`Are you sure you want to ${action} this request?`);
- if (!confirmed) return;
+ const confirmed = window.confirm(
+ `Are you sure you want to ${action} this request?`
+ );
+ if (!confirmed) return;
try {
const res = await axios.post(
`${process.env.REACT_APP_API_URL}/api/supervisor/form/${form_type}/${id}/${action}`,
- { comment },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
+ { comment, signature },
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ }
);
setMessage(res.data.message || `${action} successful`);
- setRequests(prev => prev.filter(req => req._id !== id)); // remove from table
+ setRequests((prev) => prev.filter((req) => req._id !== id));
return true;
} catch (err) {
- console.error(`Failed to ${action} request:`, err);
+ console.error(err);
setMessage(`Failed to ${action} request.`);
return false;
}
};
-
const openFormView = (form) => setSelectedForm(form);
const closeFormView = () => setSelectedForm(null);
@@ -99,75 +99,73 @@ const SupervisorDashboard = () => {
const sortedRequests = [...requests]
.filter((res) => res.supervisor_status?.toLowerCase() === "pending")
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
-
- let content;
-
- if (loading) {
- content = Loading...
;
- } else if (sortedRequests.length === 0) {
- content = (
-
-
No pending approvals.
-
- );
- } else {
- content = (
-
-
-
- | Student Name |
- Sooner ID |
- Student Email |
- Form Type |
- Submitted |
- Status |
-
-
-
- {sortedRequests.map((req) => {
- console.log(req); // Log the entire request object
- console.log(req.Name); // Log the student's full name if populated
-
- return (
-
- | {req.interneeName || "N/A"} |
-
-
- |
- {req.interneeEmail || req.ouEmail || "N/A"} |
- {req.form_type} |
- {formatDate(req.createdAt)} |
-
-
- {req.supervisor_status || req.status}
-
- |
-
- );
- })}
-
-
- );
- }
-
- return (
-
-
Supervisor Dashboard
- {message &&
{message}
}
- {content}
- {selectedForm && (
-
- handleAction(selectedForm.form_type, id, action, comment, signature)
- }
- />
- )}
+
+ let content;
+
+ if (loading) {
+ content = Loading...
;
+ } else if (sortedRequests.length === 0) {
+ content = (
+
);
+ } else {
+ content = (
+
+
+
+ | Student Name |
+ Sooner ID |
+ Student Email |
+ Form Type |
+ Submitted |
+ Status |
+
+
+
+ {sortedRequests.map((req) => (
+
+ | {req.interneeName} |
+
+
+ |
+ {req.interneeEmail} |
+ {req.form_type} |
+ {formatDate(req.createdAt)} |
+
+
+ {req.supervisor_status}
+
+ |
+
+ ))}
+
+
+ );
+ }
+
+ return (
+
+
Supervisor Dashboard
+ {message &&
{message}
}
+ {content}
+ {selectedForm && (
+
+ handleAction(selectedForm.form_type, id, action, comment, signature)
+ }
+ />
+ )}
+
+ );
};
-export default SupervisorDashboard;
\ No newline at end of file
+export default SupervisorDashboard;
diff --git a/client/src/pages/WeeklyFourWeekReportForm.js b/client/src/pages/WeeklyFourWeekReportForm.js
new file mode 100644
index 000000000..440cfbab5
--- /dev/null
+++ b/client/src/pages/WeeklyFourWeekReportForm.js
@@ -0,0 +1,151 @@
+
+import React, { useState } from "react";
+import axios from "axios";
+import "../styles/WeeklyFourWeekReportForm.css";
+
+const WeeklyFourWeekReportForm = () => {
+ const userRole = localStorage.getItem("role") || "student"; // Default role is student
+
+ const isStudent = userRole === "student";
+ const isSupervisor = userRole === "supervisor";
+ const isCoordinator = userRole === "coordinator";
+
+ const [formData, setFormData] = useState({
+ week: "Week 1",
+ tasks: "",
+ lessons: "",
+ challenges: "",
+ supervisorComments: "",
+ coordinatorComments: "",
+ });
+
+ const [message, setMessage] = useState("");
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData((prev) => ({ ...prev, [name]: value }));
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ const payload = {
+ studentId: "123456",
+ ...formData,
+ };
+
+ console.log("Payload Sending:", payload);
+
+ try {
+ await axios.post(`${process.env.REACT_APP_API_URL}/api/fourWeekReports`, payload);
+ setMessage("✅ Report Submitted Successfully!");
+
+ setFormData({
+ week: "Week 1",
+ tasks: "",
+ lessons: "",
+ challenges: "",
+ supervisorComments: "",
+ coordinatorComments: "",
+ });
+ } catch (error) {
+ console.error(error);
+ setMessage("❌ Submission Failed! Please try again.");
+ }
+ };
+
+ return (
+
+
4-Week Progress Report
+
+
+
+ );
+};
+
+export default WeeklyFourWeekReportForm;
\ No newline at end of file
diff --git a/client/src/pages/WeeklyProgressReportForm.css b/client/src/pages/WeeklyProgressReportForm.css
deleted file mode 100644
index b8b8989fa..000000000
--- a/client/src/pages/WeeklyProgressReportForm.css
+++ /dev/null
@@ -1,45 +0,0 @@
-/* WeeklyProgressReportForm.css */
-
-.a2-form-container {
- max-width: 700px;
- margin: auto;
- padding: 2rem;
- border: 1px solid #ccc;
- background: #f9f9f9;
- border-radius: 8px;
- }
-
- .form-row {
- display: flex;
- gap: 1rem;
- margin-bottom: 1rem;
- justify-content: space-between;
- }
-
- .form-row label {
- flex: 1;
- }
-
- .form-group {
- margin-bottom: 1rem;
- }
-
- textarea {
- width: 100%;
- height: 100px;
- }
-
- .submit-button {
- background: maroon;
- color: white;
- padding: 0.7rem 1.5rem;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- }
-
- .form-message {
- margin-top: 1rem;
- color: green;
- }
-
\ No newline at end of file
diff --git a/client/src/pages/WeeklyProgressReportForm.js b/client/src/pages/WeeklyProgressReportForm.js
index 2e9b8c54e..b2bee0d99 100644
--- a/client/src/pages/WeeklyProgressReportForm.js
+++ b/client/src/pages/WeeklyProgressReportForm.js
@@ -1,132 +1,272 @@
-
-
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
import axios from "axios";
-import "./WeeklyProgressReportForm.css"; // optional: for clean styling
+import { useNavigate, useParams } from "react-router-dom";
+import "../styles/WeeklyProgressReportForm.css";
+
+const WeeklyProgressReportForm = ({ role = "student", readOnly = false }) => {
+ const navigate = useNavigate();
+ const { reportId } = useParams();
-const WeeklyProgressReportForm = () => {
const [formData, setFormData] = useState({
- week: "Week 1",
+ name: "",
+ email: "",
+ supervisorName: "",
+ supervisorEmail: "",
+ coordinatorName: "Naveena",
+ coordinatorEmail: "naveena.suddapalli-1@ou.edu",
+ creditHours: "",
+ completedHours: 0,
+ requiredHours: 0,
+ week: "",
hours: "",
tasks: "",
lessons: "",
supervisorComments: "",
+ coordinatorComments: "",
});
const [message, setMessage] = useState("");
+ // Load report data in read-only mode
+ useEffect(() => {
+ if (readOnly && reportId) {
+ axios
+ .get(`${process.env.REACT_APP_API_URL}/api/reports/${reportId}`)
+ .then((res) => {
+ if (res.data.success) {
+ setFormData((prev) => ({
+ ...prev,
+ ...res.data.report,
+ }));
+ }
+ })
+ .catch((err) => {
+ console.error("Failed to load report", err);
+ });
+ }
+ }, [readOnly, reportId]);
+
+ // Auto-fill A1 data
+ useEffect(() => {
+ const fetchA1Data = async () => {
+ try {
+ const email = "vikash@example.com"; // TODO: replace with real session email
+ const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/reports/a1/${email}`);
+
+ if (res.data.success) {
+ const {
+ name,
+ email: userEmail,
+ supervisorName,
+ supervisorEmail,
+ creditHours,
+ completedHours,
+ requiredHours,
+ } = res.data.form;
+
+ setFormData((prev) => ({
+ ...prev,
+ name,
+ email: userEmail,
+ supervisorName,
+ supervisorEmail,
+ creditHours,
+ completedHours,
+ requiredHours: requiredHours || (creditHours ? creditHours * 60 : 0),
+ }));
+ }
+ } catch (err) {
+ console.error("A1 form not found or failed to fetch.");
+ setMessage("⚠️ You must submit the A1 form before submitting weekly reports.");
+ }
+ };
+
+ if (!readOnly) fetchA1Data();
+ }, [readOnly]);
+
const handleChange = (e) => {
const { name, value } = e.target;
+
+ if (readOnly && !(role === "coordinator" && name === "coordinatorComments")) return;
+
+ if (name === "hours") {
+ const num = parseInt(value);
+ if (num > 40) return setFormData((prev) => ({ ...prev, hours: 40 }));
+ if (num < 1 && value !== "") return setFormData((prev) => ({ ...prev, hours: 1 }));
+ }
+
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e) => {
e.preventDefault();
-
- // Get the user ID from localStorage (ensure it exists)
- // const user = JSON.parse(localStorage.getItem("user"));
- // const studentId = user?.user?._id;
-
- // // Check if studentId exists in localStorage
- // if (!studentId) {
- // setMessage("Student ID not found. Please log in again.");
- // return;
- // }
-
- // Check that all required fields are filled
- if (!formData.week || !formData.hours || !formData.tasks || !formData.lessons) {
- setMessage("Please fill in all the fields.");
- return;
+ const { week, hours, tasks, lessons, name, email, supervisorName, supervisorEmail } = formData;
+
+ if (!name || !email || !supervisorName || !supervisorEmail) {
+ return setMessage("Please complete the A1 form first.");
}
-
- //const payload = { studentId, ...formData };
- const payload = { ...formData };
-
+
+ if (!week || !hours || !tasks || !lessons) {
+ return setMessage("Please fill in all the required fields.");
+ }
+
try {
- // Sending the form data to the backend
- const res = await axios.post(`${process.env.REACT_APP_API_URL}/api/reports`, payload);
-
- // Display success message
- setMessage(res.data.message || "Report submitted!");
+ const res = await axios.post(`${process.env.REACT_APP_API_URL}/api/reports`, formData);
+ setMessage(res.data.message || "Report submitted successfully!");
setFormData({
- week: "Week 1",
+ name: "",
+ email: "",
+ supervisorName: "",
+ supervisorEmail: "",
+ coordinatorName: "Naveena",
+ coordinatorEmail: "naveena.suddapalli-1@ou.edu",
+ creditHours: "",
+ completedHours: 0,
+ requiredHours: 0,
+ week: "",
hours: "",
tasks: "",
lessons: "",
supervisorComments: "",
+ coordinatorComments: "",
});
} catch (err) {
console.error(err);
- setMessage("Submission failed. Try again.");
+ setMessage("Submission failed. Please try again.");
+ }
+ };
+
+ const handleCoordinatorSubmit = async () => {
+ try {
+ const res = await axios.put(
+ `${process.env.REACT_APP_API_URL}/api/reports/${reportId}/coordinator-comment`,
+ { coordinatorComments: formData.coordinatorComments }
+ );
+ setMessage(res.data.message || "Coordinator comment submitted!");
+ } catch (err) {
+ console.error(err);
+ setMessage("Failed to submit coordinator comment.");
}
};
-
return (
-
A.2 - Weekly Progress Report
+
Weekly Progress Report
+
+
+