Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0a27610
add back changes
Apr 26, 2025
c86409e
fix error in Home.js
Apr 26, 2025
99c1b42
Update approvalController
Apr 27, 2025
4c9c1d1
Merge branch 'team-a/development' of https://github.com/IPMS-Project/…
vijaychirram Apr 27, 2025
e1763a1
Initial Weekly Progress Coordinator Additions
Apr 27, 2025
5806945
Update email job to send A3 every 3 days instead of 5
Apr 27, 2025
48a911d
revert overwritten merge changes from Sprint3
Apr 27, 2025
0cc2250
Merge branch 'main' into team-a/development
ICook094 Apr 27, 2025
9521153
fix test
Apr 27, 2025
22ed44a
Merge branch 'team-a/development' of https://github.com/IPMS-Project/…
Apr 27, 2025
94d8fd3
fix merge fails
Apr 27, 2025
ff55490
fix merge error
Apr 27, 2025
8632e45
showing pending a3 forms to coordinator
vijaychirram Apr 27, 2025
055f83e
saving my changes before merging
vijaychirram Apr 27, 2025
6e713b9
Resolved merge conflicts manually and completed merge
vijaychirram Apr 27, 2025
6400e46
Finalize Coordinator Dashboard fixes: Updated model, controllers, req…
vijaychirram Apr 27, 2025
12b4417
approve , reject and send mail functionality fixed
vijaychirram Apr 27, 2025
947b171
Finalize Coordinator Sprint 4 fixes by kamal
Kamal-Poshala Apr 28, 2025
0c137a4
Merge pull request #162 from IPMS-Project/team-a/finalize-coordinator…
Kamal-Poshala Apr 28, 2025
aee8261
Resolved index.js
Kamal-Poshala Apr 29, 2025
4b74770
Merge branch 'main' into team-a/development
Kamal-Poshala Apr 29, 2025
e7bd369
Update A1InternshipRequestForm.js
Kamal-Poshala Apr 29, 2025
d860f42
Merge branch 'main' into team-a/development
Kamal-Poshala Apr 29, 2025
c8eb664
Update StudentDashboard.jsx
Kamal-Poshala Apr 29, 2025
dc3c52f
Update StudentDashboard.jsx
Kamal-Poshala Apr 29, 2025
ea3b655
ReAdd A2 Detail Form Link
Apr 29, 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
25 changes: 25 additions & 0 deletions client/src/pages/CoordinatorCumulativeReviewForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const CoordinatorCumulativeReviewForm = () => {

await axios.post(`${process.env.REACT_APP_API_URL}/api/reports/coordinator-comments`, {
groupIndex: parseInt(groupIndex),
coordinator_status: "approved",
comments: coordinatorComment.trim(),
weeks,
});
Expand All @@ -60,7 +61,28 @@ const CoordinatorCumulativeReviewForm = () => {
Swal.fire("Error", "Failed to submit comment. Please try again.", "error");
}
};

// Submit coordinator coordinator rejction
const handleReject = async () => {
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),
coordinator_status: "rejected",
comments: "",
weeks,
});

Swal.fire("Success", "Coordinator rejected weekly update FORM A2.", "success");

localStorage.setItem("reviewedGroupIndex", groupIndex); // ✅ For dashboard refresh
navigate("/coordinator-dashboard");
} catch (err) {
console.error("[CoordinatorCumulativeReviewForm] Failed to reject weekly report", err);
Swal.fire("Error", "Failed to reject weekly report. Please try again.", "error");
}
};

if (loading) {
return <p className="coordinator-review-container">Loading...</p>;
Expand Down Expand Up @@ -108,6 +130,9 @@ const CoordinatorCumulativeReviewForm = () => {
</div>

<div className="button-group">
<button className="reject-btn" onClick={handleReject}>
Reject
</button>
<button className="cancel-btn" onClick={() => navigate("/coordinator-dashboard")}>
Cancel
</button>
Expand Down
182 changes: 131 additions & 51 deletions client/src/pages/CoordinatorDashboard.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import "../styles/SupervisorDashboard.css";
import axios from "axios";
import "../styles/SupervisorDashboard.css";

const CoordinatorDashboard = () => {
const [activeTab, setActiveTab] = useState("requests"); // 'requests' or 'reports'
const [activeTab, setActiveTab] = useState("requests");
const navigate = useNavigate();
// TEAM A's Internship Requests Logic

// Internship Requests (Form A1)
const [requests, setRequests] = useState([]);
const [loadingRequests, setLoadingRequests] = useState(true);

// Weekly Reports (Form A2)
const [reports, setReports] = useState([]);
const [loadingReports, setLoadingReports] = useState(true);

// Job Evaluations (Form A3)
const [evaluations, setEvaluations] = useState([]);
const [loadingEvaluations, setLoadingEvaluations] = useState(true);

// Manual Reviews (Failed A1)
const [manualReviews, setManualReviews] = useState([]);
const [loadingManualReviews, setLoadingManualReviews] = useState(true);

useEffect(() => {
if (activeTab === "requests") {
fetchInternshipRequests();
}
if (activeTab === "requests") fetchInternshipRequests();
if (activeTab === "reports") fetchWeeklyReports();
if (activeTab === "evaluations") fetchEvaluations();
if (activeTab === "manualReviews") fetchManualReviews();
}, [activeTab]);

const fetchInternshipRequests = async () => {
Expand All @@ -25,70 +40,74 @@ 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 () => {
const fetchWeeklyReports = 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 || []);
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/coordinator/reports`);
setReports(res.data.reports || []);
} 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}`);
const fetchEvaluations = async () => {
try {
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/coordinator/evaluations`);
setEvaluations(res.data || []);
} catch (err) {
console.error("Error fetching evaluations:", err);
} finally {
setLoadingEvaluations(false);
}
};

const fetchManualReviews = async () => {
try {
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/coordinator/manual-review-a1`);
setManualReviews(res.data || []);
} catch (err) {
console.error("Error fetching manual review forms:", err);
} finally {
setLoadingManualReviews(false);
}
};


// Render UI

return (
<div className="dashboard-container">
<h2>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>
<button onClick={() => setActiveTab("reports")} className={activeTab === "reports" ? "active" : ""}>Weekly Reports</button>
<button onClick={() => setActiveTab("evaluations")} className={activeTab === "evaluations" ? "active" : ""}>Job Evaluations</button>
<button onClick={() => setActiveTab("manualReviews")} className={activeTab === "manualReviews" ? "active" : ""}>Manual Reviews (A1)</button>
</div>

{/* Tab: Internship Requests */}
{/* Internship Requests */}
{activeTab === "requests" && (
<>
{loadingRequests ? <p>Loading...</p> : (
{loadingRequests ? <p>Loading requests...</p> : (
<table className="dashboard-table">
<thead>
<tr>
<th>Student Name</th>
<th>Student ID</th>
<th>Company</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{requests.map(req => (
{requests.map((req) => (
<tr key={req._id}>
<td>{req.studentName}</td>
<td>{req.studentId}</td>
<td>{req.companyName}</td>
<td>{req.status}</td>
<td>{req.student?.name || "-"}</td>
<td>{req.workplace?.name || "-"}</td>
<td>{req.coordinator_status || "-"}</td>
<td>
<button className="view-details-btn" onClick={() => navigate(`/coordinator/request/${req._id}`)}>View Details</button>
</td>
</tr>
))}
</tbody>
Expand All @@ -97,23 +116,84 @@ const CoordinatorDashboard = () => {
</>
)}

{/* Tab: Weekly Reports Review */}
{/* Weekly Reports */}
{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>
reports.length === 0 ? <p>No reports to review</p> : (
reports.map((report) => (
<div className="report-group-card" key={report._id}>
<h4>Week: {report.week}</h4>
<p>Hours: {report.hours}</p>
<p>Tasks: {report.tasks}</p>
<td>
<button className="review-btn" onClick={() => navigate(`/review-cumulative/${report._id}/coordinator`)}>Review</button>
</td>
</div>
))
)
)}
</>
)}

{/* Job Evaluations */}
{activeTab === "evaluations" && (
<>
{loadingEvaluations ? <p>Loading evaluations...</p> : (
evaluations.length === 0 ? <p>No evaluations pending</p> : (
<table className="dashboard-table">
<thead>
<tr>
<th>Internee Name</th>
<th>Internee Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{evaluations.map((evalItem) => (
<tr key={evalItem._id}>
<td>{evalItem.interneeName}</td>
<td>{evalItem.interneeEmail}</td>
<td>
<button className="review-btn" onClick={() => navigate(`/coordinator/evaluation/${evalItem._id}`)}>Review</button>
</td>
</tr>
))}
</tbody>
</table>
)
)}
</>
)}

{/* Manual Reviews */}
{activeTab === "manualReviews" && (
<>
{loadingManualReviews ? <p>Loading manual reviews...</p> : (
manualReviews.length === 0 ? <p>No manual review forms.</p> : (
<table className="dashboard-table">
<thead>
<tr>
<th>Student Name</th>
<th>Email</th>
<th>Company</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{manualReviews.map((form) => (
<tr key={form._id}>
<td>{form.student?.userName || "N/A"}</td>
<td>{form.student?.email || "N/A"}</td>
<td>{form.workplace?.name || "N/A"}</td>
<td>
<button onClick={() => navigate(`/coordinator/manual-review/${form._id}`)}>Review</button>
</td>
</tr>
))}
</tbody>
</table>
)
)}
</>
)}
Expand Down
99 changes: 99 additions & 0 deletions client/src/pages/CoordinatorEvaluationReview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import axios from "axios";
import "../styles/CoordinatorRequestDetailView.css"; // Reuse styles

const CoordinatorEvaluationReview = () => {
const { id } = useParams();
const navigate = useNavigate();
const [evaluation, setEvaluation] = useState(null);

useEffect(() => {
const fetchEvaluationDetails = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/api/coordinator/evaluations`
);
const matchedEvaluation = res.data.find((form) => form._id === id);
setEvaluation(matchedEvaluation || null);
} catch (err) {
console.error("Error fetching evaluation form:", err);
}
};

fetchEvaluationDetails();
}, [id]);

const handleApprove = async () => {
try {
const res = await axios.post(
`${process.env.REACT_APP_API_URL}/api/coordinator/evaluation/${id}/approve`
);
alert(res.data.message);
navigate("/coordinator-dashboard");
} catch (err) {
console.error("Error approving evaluation:", err);
alert("Error approving evaluation form.");
}
};

const handleReject = async () => {
const reason = prompt("Please enter a reason for rejection:");
if (!reason) {
alert("Rejection reason is required!");
return;
}
try {
const res = await axios.post(
`${process.env.REACT_APP_API_URL}/api/coordinator/evaluation/${id}/reject`,
{ reason }
);
alert(res.data.message);
navigate("/coordinator-dashboard");
} catch (err) {
console.error("Error rejecting evaluation:", err);
alert("Error rejecting evaluation form.");
}
};

if (!evaluation) return <h2>Loading evaluation details...</h2>;

return (
<div className="request-form">
<h2 className="dashboard-title">Job Evaluation (Form A3) Review</h2>

<div className="dashboard-card">
<p><b>Internee Name:</b> {evaluation.interneeName}</p>
<p><b>Internee Email:</b> {evaluation.interneeEmail}</p>

<h3 className="section-title">Evaluation Categories</h3>
<table className="data-table">
<thead>
<tr>
<th>Category</th>
<th>Rating</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
{evaluation.evaluations.map((item, idx) => (
<tr key={idx}>
<td>{item.category}</td>
<td>{item.rating}</td>
<td>{item.comment || "N/A"}</td>
</tr>
))}
</tbody>
</table>

<div className="action-buttons" style={{ marginTop: "20px", display: "flex", gap: "10px" }}>
<button className="approve-btn" onClick={handleApprove}>Approve</button>
<button className="reject-btn" onClick={handleReject}>Reject</button>
<button className="back-btn" onClick={() => navigate("/coordinator-dashboard")}>Back</button>
</div>
</div>
</div>
);
};

export default CoordinatorEvaluationReview;
Loading