Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a960c4d
A1 form Completed
Nanvithaa Apr 19, 2025
a002be9
Merge branch 'GroupE-development' into GroupE-frontend
Nanvithaa Apr 19, 2025
df90b23
Removed SoonerID
MRPHFitch Apr 23, 2025
b38d274
Merge branch 'GroupE-frontend' into GroupE-development
MRPHFitch Apr 23, 2025
17c7efd
Merge pull request #143 from IPMS-Project/GroupE-development
MRPHFitch Apr 23, 2025
e57d7d9
All forms displayed
MRPHFitch Apr 23, 2025
d2e7939
Week calculation for length of internship
MRPHFitch Apr 23, 2025
f11f8d5
Establishing RBAC
MRPHFitch Apr 23, 2025
6d14559
Adjusting layout of forms
MRPHFitch Apr 23, 2025
921e8d4
Merge branch 'GroupE-frontend' into GroupE/frontend
MRPHFitch Apr 25, 2025
7b05f67
Merge pull request #152 from IPMS-Project/GroupE/frontend
MRPHFitch Apr 25, 2025
9d056a7
Fixed server and router issue
MRPHFitch Apr 25, 2025
ca3e9fc
Removed SoonerID & fixed Controller issue
MRPHFitch Apr 25, 2025
5056c4f
Fixed Errors in order to npm start
MRPHFitch Apr 25, 2025
8cc098f
Merge branch 'GroupE-frontend' into GroupE/frontend
MRPHFitch Apr 25, 2025
da147f0
Merge pull request #153 from IPMS-Project/GroupE/frontend
MRPHFitch Apr 25, 2025
f4a83bb
Pulled main again and fixed issues
MRPHFitch Apr 25, 2025
cc74e7a
Updated dependencies for UseEffect
MRPHFitch Apr 25, 2025
4e39018
comitted
vikashbalajik Apr 26, 2025
7aea5aa
Group D's changes suck
MRPHFitch Apr 26, 2025
8691d9f
Backend correct get forms, reminder
HozenDev Apr 26, 2025
0def169
Merge branch 'GroupE-frontend' of github.com:IPMS-Project/IPMS into G…
HozenDev Apr 26, 2025
6eb2dee
Better A1 Render, Correct Email Reminder DB save, Redirection
HozenDev Apr 26, 2025
6259f5a
Correct A3 disapear on handle A1 form of same student
HozenDev Apr 26, 2025
d9e8f81
Merge GroupE-backend branch & correct fix A3 disappear after handle A…
HozenDev Apr 26, 2025
63f376c
Update with main
HozenDev Apr 27, 2025
93de404
Save work before pulling from GroupE-development
vikashbalajik Apr 27, 2025
8bf1fa1
Merge branch 'GroupE-development' of github.com:IPMS-Project/IPMS int…
vikashbalajik Apr 27, 2025
cf7161d
latest
vikashbalajik Apr 27, 2025
f89f7f9
saturnday
vikashbalajik Apr 27, 2025
7f94463
WIP: changes to index.js before pull
vikashbalajik Apr 27, 2025
21a7447
sprint 4
vikashbalajik Apr 28, 2025
17d3f3a
sprint 4
vikashbalajik Apr 28, 2025
7586888
resolved conflicts
vikashbalajik Apr 28, 2025
50b6d28
resolved conflicts
vikashbalajik Apr 28, 2025
80b9f06
resolved conflicts
vikashbalajik Apr 28, 2025
f5686e6
resolved conflicts
vikashbalajik Apr 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@
"axios": "^1.8.2",
"bootstrap": "^5.3.5",
"client": "file:",
"date-fns": "^4.1.0",
"dayjs": "^1.11.13",
"react": "^19.0.0",
"react-bootstrap": "^2.10.9",
"react-datepicker": "^8.3.0",
"react-dom": "^19.0.0",
"react-icons": "^5.5.0",
"react-router-dom": "^7.4.1",
"react-scripts": "5.0.1",
"react-signature-canvas": "^1.1.0-alpha.2",
"react-toastify": "^11.0.5",
"sweetalert2": "^11.17.2",
"web-vitals": "^2.1.4",
"date-fns": "^4.1.0",
"react-datepicker": "^8.3.0"
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/A1InternshipRequestForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ const A1InternshipRequestForm = ({ userRole = "student" }) => {
}
};

const sendTaskDescriptions = async (descriptions) => {
try {
const sendTaskDescriptions = async (descriptions) => {
try {
const response = await fetch(`${process.env.REACT_APP_API_URL}/api/align-outcomes`, {
method: "POST",
headers: { "Content-Type": "application/json" },
Expand Down Expand Up @@ -655,4 +655,4 @@ const A1InternshipRequestForm = ({ userRole = "student" }) => {
);
};

export default A1InternshipRequestForm;
export default A1InternshipRequestForm;
208 changes: 157 additions & 51 deletions client/src/pages/CoordinatorDashboard.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import "../styles/SupervisorDashboard.css";
import "../styles/SupervisorDashboard.css"; // Reuse styling

const CoordinatorDashboard = () => {
const [activeTab, setActiveTab] = useState("requests"); // 'requests' or 'reports'
const [activeTab, setActiveTab] = useState("requests");
const navigate = useNavigate();
// TEAM A's Internship Requests Logic
const [requests, setRequests] = useState([]);
const [loadingRequests, setLoadingRequests] = useState(true);
const [reportGroups, setReportGroups] = useState([]);
const [loadingReports, setLoadingReports] = useState(true);

useEffect(() => {
if (activeTab === "requests") {
fetchInternshipRequests();
} else if (activeTab === "reports") {
fetchReportGroups();
}
}, [activeTab]);

Expand All @@ -25,66 +29,105 @@ const CoordinatorDashboard = () => {
setLoadingRequests(false);
}
};
// Group D's Weekly Report Review Logic

const [reportGroups, setReportGroups] = useState([]);
const [loadingReports, setLoadingReports] = useState(true);

useEffect(() => {
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);
const response = await axios.get(`${process.env.REACT_APP_API_URL}/api/reports/supervised-groups`);
console.log("Fetched report groups:", response.data);
setReportGroups(response.data.groups || []);
} catch (error) {
console.error("Error fetching reports:", error);
} finally {
setLoadingReports(false);
}
};

const handleReviewClick = (group) => {
localStorage.setItem(`coordinator_reviewed_${group.groupIndex}`, "true");
navigate(`/review-cumulative/${group.groupIndex}`);
localStorage.setItem("reviewEmail", group.email);
localStorage.setItem("reviewWeeks", JSON.stringify(group.weeks));
navigate(`/coordinator-review/${group.groupIndex}`);
};

const getSupervisorComment = (group) => {
if (!group.reports || group.reports.length === 0) {
return "No comment provided.";
}
const comments = group.reports
.map(r => r.supervisorComments?.trim())
.filter(c => c && c !== "");
const uniqueComments = [...new Set(comments)];

if (uniqueComments.length === 1) {
return uniqueComments[0];
} else if (uniqueComments.length > 1) {
return uniqueComments.join(", ");
} else {
return "No comment provided.";
}
};

const formatWeeks = (weeks) => {
return weeks.map(w => w.split(" ")[1]).join(", ");
};


// Render UI

return (
<div className="dashboard-container">
<h2>Coordinator Dashboard</h2>
<div className="dashboard-container" style={{ padding: "2rem" }}>
<h2 style={{ textAlign: "center", fontWeight: "bold", marginBottom: "2rem" }}>
Coordinator Dashboard
</h2>

{/* Tabs */}
<div className="tab-toggle">
<button onClick={() => setActiveTab("requests")} className={activeTab === "requests" ? "active" : ""}>Internship Requests</button>
<button onClick={() => setActiveTab("reports")} className={activeTab === "reports" ? "active" : ""}>Weekly Reports Review</button>
<div className="tab-toggle" style={{ display: "flex", justifyContent: "center", gap: "20px", marginBottom: "2rem" }}>
<button
onClick={() => setActiveTab("requests")}
style={{
padding: "10px 20px",
fontSize: "16px",
borderRadius: "8px",
border: "1px solid #9b111e",
backgroundColor: activeTab === "requests" ? "#9b111e" : "white",
color: activeTab === "requests" ? "white" : "#9b111e",
cursor: "pointer",
fontWeight: "600",
}}
>
Internship Requests
</button>
<button
onClick={() => setActiveTab("reports")}
style={{
padding: "10px 20px",
fontSize: "16px",
borderRadius: "8px",
border: "1px solid #9b111e",
backgroundColor: activeTab === "reports" ? "#9b111e" : "white",
color: activeTab === "reports" ? "white" : "#9b111e",
cursor: "pointer",
fontWeight: "600",
}}
>
Weekly Reports Review
</button>
</div>

{/* Tab: Internship Requests */}
{/* Internship Requests */}
{activeTab === "requests" && (
<>
{loadingRequests ? <p>Loading...</p> : (
<table className="dashboard-table">
{loadingRequests ? (
<p>Loading internship requests...</p>
) : (
<table className="dashboard-table" style={{ width: "100%", borderCollapse: "collapse" }}>
<thead>
<tr>
<tr style={{ backgroundColor: "#f2f2f2" }}>
<th>Student Name</th>
<th>Student ID</th>
<th>Company</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{requests.map(req => (
<tr key={req._id}>
{requests.map((req) => (
<tr key={req._id} style={{ textAlign: "center" }}>
<td>{req.studentName}</td>
<td>{req.studentId}</td>
<td>{req.companyName}</td>
Expand All @@ -97,23 +140,86 @@ const CoordinatorDashboard = () => {
</>
)}

{/* Tab: Weekly Reports Review */}
{/* Weekly Reports Review */}
{activeTab === "reports" && (
<>
{loadingReports ? <p>Loading reports...</p> : (
reportGroups.length === 0
? <p>No reports to review</p>
: reportGroups.map(group => (
<div className="report-group-card" key={group.groupIndex}>
<h4>Weeks: {group.weeks?.join(", ")}</h4>
<ul>
{group.reports.map((r, i) => (
<li key={i}>Week {r.week} — Hours: {r.hours} — Tasks: {r.tasks}</li>
))}
</ul>
<button onClick={() => handleReviewClick(group)}>Review & Comment</button>
{loadingReports ? (
<p>Loading weekly reports...</p>
) : (
<>
{reportGroups.length === 0 ? (
<div className="empty-message-container" style={{ textAlign: "center", marginTop: "2rem" }}>
<p>No pending groups for review.</p>
</div>
))
) : (
reportGroups.map((group) => (
<div
key={group.groupIndex}
style={{
backgroundColor: "white",
boxShadow: "0px 2px 8px rgba(0,0,0,0.1)",
padding: "2rem",
marginBottom: "2rem",
borderRadius: "12px",
maxWidth: "700px",
marginInline: "auto",
transition: "transform 0.3s",
}}
onMouseOver={(e) => e.currentTarget.style.transform = "scale(1.02)"}
onMouseOut={(e) => e.currentTarget.style.transform = "scale(1)"}
>
<h3 style={{ color: "#9b111e", marginBottom: "15px", textAlign: "center" }}>
Weeks: {formatWeeks(group.weeks)}{group.reports?.[0]?.name ? ` of ${group.reports[0].name}` : ""}
</h3>

<div style={{ marginBottom: "20px" }}>
<strong>
{group.reports?.[0]?.supervisorName ? `(${group.reports[0].supervisorName})` : ""} Supervisor's Comment:
</strong>
<div
style={{
backgroundColor: "#f9f9f9",
padding: "12px",
borderRadius: "8px",
marginTop: "8px",
fontStyle: "italic",
color: "#555",
}}
>
{getSupervisorComment(group)}
</div>
</div>

<div style={{ textAlign: "center" }}>
<button
onClick={() => handleReviewClick(group)}
style={{
padding: "10px 24px",
borderRadius: "8px",
backgroundColor: "#9b111e",
color: "white",
fontWeight: "bold",
fontSize: "16px",
border: "none",
cursor: "pointer",
transition: "background-color 0.3s, transform 0.2s",
}}
onMouseOver={(e) => {
e.target.style.backgroundColor = "#7e0e18";
e.target.style.transform = "scale(1.05)";
}}
onMouseOut={(e) => {
e.target.style.backgroundColor = "#9b111e";
e.target.style.transform = "scale(1)";
}}
>
Review & Comment
</button>
</div>
</div>
))
)}
</>
)}
</>
)}
Expand Down
Loading