Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
2112c51
creating new branch for PR GroupE
Nanvithaa Apr 14, 2025
45a6599
Everything is working now
Nanvithaa Apr 15, 2025
87439df
Everything is working now
Nanvithaa Apr 15, 2025
9c5c628
Merge branch 'main' into GroupE/Sprint2
Nanvithaa Apr 15, 2025
1d517d8
Correct supervisor reminder email:
HozenDev Apr 15, 2025
1d059f5
Merge branch 'GroupE/Sprint2' of github.com:IPMS-Project/IPMS into Gr…
HozenDev Apr 15, 2025
ea218af
Resolve test reminderEmail
HozenDev Apr 15, 2025
a186390
Updated
Nanvithaa Apr 16, 2025
9c4d46c
Add form metadata
HozenDev Apr 17, 2025
75af618
Added common Form Fields (Formfields) and updated A1, A2, A3 schemas
Apr 17, 2025
9e44661
Backend update
HozenDev Apr 17, 2025
eeea96c
Merge branch 'TeamE/S3/Backend' of github.com:IPMS-Project/IPMS into …
HozenDev Apr 17, 2025
21944a8
Delete A?Forms because already added
HozenDev Apr 17, 2025
704f587
Update Backend
HozenDev Apr 17, 2025
45ab82f
Update client to link with new backend
HozenDev Apr 17, 2025
2cca819
Update branch with main changes
HozenDev Apr 17, 2025
dd59218
Cleaned up a little
MRPHFitch Apr 18, 2025
965fb9e
Should be integrated with A1
MRPHFitch Apr 18, 2025
2538bb1
Better Integration with A1
MRPHFitch Apr 18, 2025
9bb35d9
Sorted Submissions
MRPHFitch Apr 19, 2025
a80cb01
Correct email sent to student after approve/reject
HozenDev Apr 19, 2025
573299d
Merge modifications
HozenDev Apr 19, 2025
c66f4a3
Update A3 modal and dashboard: ViewFormModal & SupervisorDashboard en…
Apr 20, 2025
78aad85
Add A3 backend routes and model fields
Apr 20, 2025
1f3db3a
Add FormMetadata.js from backend branch
Apr 20, 2025
714160a
Resolve bad get evaluation (form_type -> supervisor_status)
HozenDev Apr 21, 2025
309ff07
updated A3
Apr 21, 2025
d8c58cc
Resolve conflict: delete evaluationRoutes.js after rebase
Apr 21, 2025
022971f
Merge branch 'GroupE-development' into GroupE/Frontend/a3
MRPHFitch Apr 21, 2025
25eae1f
Merge pull request #133 from IPMS-Project/GroupE/Frontend/a3
MRPHFitch Apr 21, 2025
6e4ac28
fix A3
HozenDev Apr 21, 2025
ca10b3b
Fix A3 with current other files
HozenDev Apr 21, 2025
483d5a1
Fixing A1
MRPHFitch Apr 21, 2025
880bd19
Merge
HozenDev Apr 21, 2025
fbab1b5
fix
HozenDev Apr 21, 2025
2fea087
fix form routes and insert data
HozenDev Apr 21, 2025
25ed6d2
Update with main modification
HozenDev Apr 21, 2025
e7c8168
Update A1 Render
HozenDev Apr 21, 2025
271e665
Fixing display
MRPHFitch Apr 21, 2025
c8024e2
Correct A1 style
HozenDev Apr 21, 2025
ba25367
Merge branch 'GroupE-development' of github.com:IPMS-Project/IPMS int…
HozenDev Apr 21, 2025
2d7b45f
Updated aesthetics
MRPHFitch Apr 21, 2025
f9544f7
Fix form style
HozenDev Apr 21, 2025
7b3b188
Restore good A1 render
HozenDev Apr 21, 2025
249080d
Update ViewFormModal.js
MRPHFitch Apr 21, 2025
597376f
Getting Sooner ID back
MRPHFitch Apr 21, 2025
a147b9c
Fixed build error
MRPHFitch Apr 21, 2025
77a142e
6 Column update
MRPHFitch Apr 21, 2025
1b0e18f
Adjustments to reflect new DB
MRPHFitch Apr 21, 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
2 changes: 1 addition & 1 deletion client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ function App() {
return <RouterProvider router={router} />;
}

export default App;
export default App;
173 changes: 112 additions & 61 deletions client/src/pages/SupervisorDashboard.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import React, { useEffect, useState } from "react";
import axios from "axios";
import "../styles/SupervisorDashboard.css";
Expand All @@ -9,114 +8,166 @@ const SupervisorDashboard = () => {
const [selectedForm, setSelectedForm] = useState(null);
const [loading, setLoading] = useState(true);
const [message, setMessage] = useState("");

useEffect(() => {

useEffect(() => {
const fetchRequests = async () => {
// Token used for authentication for future
// Now it will only be empty
const token = localStorage.getItem("token") || "";

const fetchRequests = async () => {
try {
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/form/internshiprequests`);
console.log("Fetched internship requests:", res.data); // debug log
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/supervisor/forms`,
{
headers: {
Authorization: `Bearer ${token}`,
},
});

const formatted = res.data
.map(item => ({
const formatted = res.data.map(item => ({
_id: item._id,
name: item.student?.userName || item.student?.name || "N/A",
name: item.student_id?.userName || item.student_id?.name || "N/A",
student_id: item.student?._id || item._id,

form_type: "A1",
form_type: item.form_type,
createdAt: item.createdAt,
supervisor_status: item.supervisor_status || "pending",
fullForm: item
}))
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)); // oldest first
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 Internship A1 forms:", err);
setMessage("Error fetching Internship A1 forms.");
console.error("Error fetching forms:", err);
setMessage("Error fetching forms.", err);
setLoading(false);
}
};

fetchRequests();
}, []);

const handleAction = async (id, action, comment) => {
const confirmed = window.confirm(`Are you sure you want to ${action} this request?`);
if (!confirmed) return;
const handleAction = async (id, form_type, action, comment) => {

const token = localStorage.getItem("token");

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/form/internshiprequests/${id}/${action}`,
{ comment }
`${process.env.REACT_APP_API_URL}/api/supervisor/form/${form_type}/${id}/${action}`,
{ comment },
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);

setMessage(res.data.message || `${action} successful`);
setRequests(prev => prev.filter(req => req._id !== id));
setSelectedForm(null);
setRequests(prev => prev.filter(req => req._id !== id)); // remove from table
return true;
} catch (err) {
console.error(`Failed to ${action} request:`, err);
setMessage(`Failed to ${action} request.`);
return false;
}
};


const openFormView = (form) => setSelectedForm(form);
const closeFormView = () => setSelectedForm(null);
const formatDate = (date) => new Date(date).toLocaleDateString();

return (
<div className="dashboard-container">
<h2>Supervisor Dashboard</h2>
{message && <p className="status-msg">{message}</p>}
const sortedRequests = [...requests]
.filter((res) => res.supervisor_status?.toLowerCase() === "pending")
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));

let content;

{loading ? (
<p>Loading...</p>
) : requests.length === 0 ? (
if (loading) {
content = <p>Loading...</p>;
} else if (sortedRequests.length === 0) {
content = (
<div className="empty-message-container">
<div className="empty-message">No pending approvals.</div>
</div>
) : (
);
} else {
content = (
<table className="dashboard-table">
<thead>
<tr>
<th>Student Name</th>
<th>Student ID</th>
<th>Sooner ID</th>
<th>Student Email</th>
<th>Form Type</th>
<th>Date Submitted</th>
<th>Submitted</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{requests.map((req) => (
<tr key={req._id}>
<td>{req.name}</td>
<td>
<button className="link-button" onClick={() => openFormView(req.fullForm)}>
{req.student_id}
</button>
</td>
<td>{req.form_type}</td>
<td>{formatDate(req.createdAt)}</td>
<td>
<span className={`status-badge ${req.supervisor_status}`}>
{req.supervisor_status}
</span>
</td>
</tr>
))}
{sortedRequests.map((req) => {
console.log(req); // Log the entire request object
console.log(req.Name); // Log the student's full name if populated

return (
<tr key={req._id}>
<td>{req.interneeName || "N/A"}</td>
<td>
<button className="link-button" onClick={() => openFormView(req)}>
{req.soonerId || "N/A"}
</button>
</td>
<td>{req.interneeEmail || req.ouEmail || "N/A"}</td>
<td>{req.form_type}</td>
<td>{formatDate(req.createdAt)}</td>
<td>
<span className={`status-badge ${req.supervisor_status || req.status}`}>
{req.supervisor_status || req.status}
</span>
</td>
</tr>
);
})}
</tbody>
</table>
)}

{selectedForm && (
<ViewFormModal
formData={selectedForm}
onClose={closeFormView}
onAction={handleAction}
/>
)}
</div>
);
);
}

return (
<div className="dashboard-container">
<h2>Supervisor Dashboard</h2>
{message && <p className="status-msg">{message}</p>}
{content}
{selectedForm && (
<ViewFormModal
formData={selectedForm}
onClose={closeFormView}
onAction={(id, action, comment, signature) =>
handleAction(selectedForm.form_type, id, action, comment, signature)
}
/>
)}
</div>
);
};

export default SupervisorDashboard;
export default SupervisorDashboard;
Loading