diff --git a/client/src/pages/CoordinatorRequestDetailView.js b/client/src/pages/CoordinatorRequestDetailView.js new file mode 100644 index 000000000..3eadf0aaa --- /dev/null +++ b/client/src/pages/CoordinatorRequestDetailView.js @@ -0,0 +1,81 @@ +import React, { useEffect, useState } from "react"; +import axios from "axios"; +import { useParams } from "react-router-dom"; +import "../styles/CoordinatorRequestDetailView.css"; + +const CoordinatorRequestDetailView = () => { + const { id } = useParams(); + const [data, setData] = useState(null); + + useEffect(() => { + axios + .get(`${process.env.REACT_APP_API_URL}/api/coordinator/request/${id}`) + .then((res) => setData(res.data)) + .catch((err) => console.log(err)); + }, [id]); + + if (!data) return

Loading...

; + + const { requestData, supervisorStatus } = data; + + return ( +
+

Internship Request Details

+ +
+

+ Student Name: {requestData.student.userName} +

+

+ Student Email: {requestData.student.email} +

+

+ Company: {requestData.workplace.name} +

+

+ Company Website: {requestData.workplace.website} +

+

+ Company Phone: {requestData.workplace.phone} +

+

+ Internship Advisor: {requestData.internshipAdvisor.name} ( + {requestData.internshipAdvisor.email}) +

+

+ Credit Hours: {requestData.creditHours} +

+

+ Start Date:{" "} + {new Date(requestData.startDate).toLocaleDateString()} +

+

+ End Date: {new Date(requestData.endDate).toLocaleDateString()} +

+

+ Supervisor Approval Status: {supervisorStatus} +

+ +

Tasks & CS Outcomes

+ + + + + + + + + {requestData.tasks.map((task, idx) => ( + + + + + ))} + +
Task DescriptionCS Outcomes
{task.description}{task.outcomes.join(", ")}
+
+
+ ); +}; + +export default CoordinatorRequestDetailView; diff --git a/client/src/router.js b/client/src/router.js index 740942425..e562e458f 100644 --- a/client/src/router.js +++ b/client/src/router.js @@ -3,7 +3,6 @@ import React from "react"; import { createBrowserRouter } from "react-router-dom"; import A1InternshipRequestForm from "./pages/A1InternshipRequestForm"; - // Layout import Layout from "./components/Layout"; @@ -15,6 +14,7 @@ import WeeklyProgressReportForm from "./pages/WeeklyProgressReportForm"; import A3JobEvaluationForm from "./pages/A3JobEvaluationForm"; import SupervisorDashboard from "./pages/SupervisorDashboard"; import CoordinatorDashboard from "./pages/CoordinatorDashboard"; +import CoordinatorRequestDetailView from "./pages/CoordinatorRequestDetailView"; // Create and export the router configuration const router = createBrowserRouter([ @@ -51,9 +51,12 @@ const router = createBrowserRouter([ path: "coordinator-dashboard", element: , }, + { + path: "coordinator/request/:id", + element: , + }, ], }, ]); - export default router; diff --git a/client/src/styles/CoordinatorRequestDetailView.css b/client/src/styles/CoordinatorRequestDetailView.css new file mode 100644 index 000000000..f47f167dd --- /dev/null +++ b/client/src/styles/CoordinatorRequestDetailView.css @@ -0,0 +1,17 @@ +@import "./App.css"; + +.request-form { + max-width: 700px; + margin: 40px auto; + padding: 30px; + background-color: white; + border-radius: 12px; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); +} + +.section-title { + color: #9d2235; + margin-top: 20px; + font-weight: 600; + font-size: 1.1rem; +} diff --git a/server/controllers/approvalController.js b/server/controllers/approvalController.js index 8b3357a5e..65e2727b4 100644 --- a/server/controllers/approvalController.js +++ b/server/controllers/approvalController.js @@ -1,4 +1,6 @@ const Submission = require("../models/Submission"); +const InternshipRequest = require("../models/InternshipRequest"); +const EmailService = require("../services/emailService"); // ✅ Get pending submissions for supervisor exports.getPendingSubmissions = async (req, res) => { @@ -6,7 +8,9 @@ exports.getPendingSubmissions = async (req, res) => { const submissions = await Submission.find({ supervisor_status: "pending" }); res.json(submissions); } catch (err) { - res.status(500).json({ message: "Failed to fetch pending submissions", error: err }); + res + .status(500) + .json({ message: "Failed to fetch pending submissions", error: err }); } }; @@ -27,9 +31,8 @@ exports.approveSubmission = async (req, res) => { res.json({ message: "Submission approved and forwarded to Coordinator", - updatedSubmission: submission + updatedSubmission: submission, }); - } catch (err) { res.status(500).json({ message: "Approval failed", error: err }); } @@ -52,10 +55,34 @@ exports.rejectSubmission = async (req, res) => { res.json({ message: "Submission rejected", - updatedSubmission: submission + updatedSubmission: submission, }); - } catch (err) { res.status(500).json({ message: "Rejection failed", error: err }); } }; +// Coordinator: Get Request Details +exports.getCoordinatorRequestDetails = async (req, res) => { + try { + const requestData = await InternshipRequest.findById( + req.params.id + ).populate("student", "userName email"); + + if (!requestData) { + return res.status(404).json({ message: "Request not found" }); + } + + const submissionData = await Submission.findOne({ + student_name: requestData.student.userName, + }); + + res.status(200).json({ + requestData, + supervisorStatus: submissionData + ? submissionData.supervisor_status + : "Not Submitted", + }); + } catch (err) { + res.status(500).json({ message: "Failed to fetch details", error: err }); + } +}; diff --git a/server/index.js b/server/index.js index 8b71ee0cc..fc6784ac6 100644 --- a/server/index.js +++ b/server/index.js @@ -17,7 +17,6 @@ const cronJobManager = require("./utils/cronUtils"); const { registerAllJobs } = require("./jobs/registerCronJobs"); const Evaluation = require("./models/Evaluation"); - const app = express(); app.use(express.json()); app.use(cors()); diff --git a/server/middleware/authMiddleware.js b/server/middleware/authMiddleware.js index adef8663d..e0c14580c 100644 --- a/server/middleware/authMiddleware.js +++ b/server/middleware/authMiddleware.js @@ -1,11 +1,20 @@ exports.isSupervisor = (req, res, next) => { // const supervisor = Sup.find({$id: username}) - - req.user = { role: 'supervisor' }; // Mocking user role for demo + req.user = { role: "supervisor" }; // Mocking user role for demo if (req.user.role === "supervisor") { next(); } else { res.status(403).json({ message: "Access denied. Not a supervisor." }); } -}; \ No newline at end of file +}; + +exports.isCoordinator = (req, res, next) => { + req.user = { role: "coordinator" }; // Mocking role for now (or fetch from DB if implemented) + + if (req.user.role === "coordinator") { + next(); + } else { + res.status(403).json({ message: "Access denied. Not a coordinator." }); + } +}; diff --git a/server/routes/approvalRoutes.js b/server/routes/approvalRoutes.js index 0d8211b83..dc4d62ba8 100644 --- a/server/routes/approvalRoutes.js +++ b/server/routes/approvalRoutes.js @@ -1,10 +1,24 @@ const express = require("express"); const router = express.Router(); -const { getPendingSubmissions, approveSubmission, rejectSubmission } = require("../controllers/approvalController"); -const { isSupervisor } = require("../middleware/authMiddleware"); +const { + getPendingSubmissions, + approveSubmission, + rejectSubmission, +} = require("../controllers/approvalController"); +const { isSupervisor, isCoordinator } = require("../middleware/authMiddleware"); +const { + getCoordinatorRequestDetails, + coordinatorApproveRequest, + coordinatorRejectRequest, +} = require("../controllers/approvalController"); router.get("/submissions/pending", isSupervisor, getPendingSubmissions); router.post("/submissions/:id/approve", isSupervisor, approveSubmission); router.post("/submissions/:id/reject", isSupervisor, rejectSubmission); +router.get( + "/coordinator/request/:id", + isCoordinator, + getCoordinatorRequestDetails +); -module.exports = router; \ No newline at end of file +module.exports = router;