From 4b3e72b2663973534656f3eee988a1109ea1063e Mon Sep 17 00:00:00 2001 From: Kamal Poshala Date: Thu, 10 Apr 2025 19:53:32 -0500 Subject: [PATCH 01/19] Sprint 2 Task 4: Approval/Email/Logging --- client/package.json | 3 +- client/src/pages/CoordinatorDashboard.js | 91 ++++++++++++++++++++-- client/src/pages/Home.js | 61 ++++++--------- client/src/router.js | 6 +- client/src/styles/dashboard.css | 31 ++++++++ package.json | 5 ++ server/index.js | 4 + server/routes/coordinator.js | 99 ++++++++++++++++++++++++ server/services/emailService.js | 86 +++++++++++++++----- 9 files changed, 320 insertions(+), 66 deletions(-) create mode 100644 client/src/styles/dashboard.css create mode 100644 package.json create mode 100644 server/routes/coordinator.js diff --git a/client/package.json b/client/package.json index f9599a871..1eeae380b 100644 --- a/client/package.json +++ b/client/package.json @@ -2,6 +2,7 @@ "name": "client", "version": "0.1.0", "private": true, + "proxy": "http://localhost:5001", "dependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", @@ -19,7 +20,7 @@ "web-vitals": "^2.1.4" }, "scripts": { - "start": "react-scripts start", + "start": "set NODE_OPTIONS=--openssl-legacy-provider && react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" diff --git a/client/src/pages/CoordinatorDashboard.js b/client/src/pages/CoordinatorDashboard.js index 082ff2478..c4949c513 100644 --- a/client/src/pages/CoordinatorDashboard.js +++ b/client/src/pages/CoordinatorDashboard.js @@ -1,12 +1,91 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; +import "../styles/dashboard.css"; + +function CoordinatorDashboard() { + const [requests, setRequests] = useState([]); + + useEffect(() => { + const fetchRequests = async () => { + try { + const res = await fetch("/api/coordinator/requests"); + const data = await res.json(); + setRequests(data); + } catch (err) { + console.error("Failed to fetch requests:", err); + } + }; + + fetchRequests(); + }, []); + + const handleApprove = async (_id) => { + try { + const res = await fetch(`/api/coordinator/requests/${_id}/approve`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + }); + + const result = await res.json(); + alert(result.message); + } catch (err) { + console.error("Approval failed:", err); + alert("Error approving request."); + } + }; + + const handleReject = async (_id) => { + const reason = prompt("Enter rejection reason:"); + if (!reason) return; + + try { + const res = await fetch(`/api/coordinator/requests/${_id}/reject`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ reason }), + }); + + const result = await res.json(); + alert(result.message); + } catch (err) { + console.error("Rejection failed:", err); + alert("Error rejecting request."); + } + }; + + const daysRemaining = (deadline) => { + const now = new Date(); + const due = new Date(deadline); + const diff = Math.ceil((due - now) / (1000 * 60 * 60 * 24)); + return diff; + }; -const CoordinatorDashboard = () => { return ( -
+

Coordinator Dashboard

-

Welcome, Coordinator!

+

Review and manage internship requests.

+ +
+ {requests.map((req) => ( +
+

{req.fullName}

+

Email: {req.ouEmail}

+

Advisor: {req.academicAdvisor}

+

Status: {req.status}

+

Requested At: {new Date(req.requestedAt).toLocaleDateString()}

+ +
+ + +
+
+ ))} +
); -}; +} -export default CoordinatorDashboard; \ No newline at end of file +export default CoordinatorDashboard; diff --git a/client/src/pages/Home.js b/client/src/pages/Home.js index 449478f73..fd105af53 100644 --- a/client/src/pages/Home.js +++ b/client/src/pages/Home.js @@ -1,5 +1,4 @@ -import React from 'react'; -import { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Link, useNavigate } from "react-router-dom"; import "../styles/App.css"; import { FaEnvelope, FaLock, FaEye, FaEyeSlash } from "react-icons/fa"; @@ -13,10 +12,15 @@ function Home() { const [formData, setFormData] = useState({ email: "", password: "", - role: "Student", + role: "student", }); const [showPassword, setShowPassword] = useState(false); - const [role, setRole] = useState("-"); + const [role, setRole] = useState("student"); + + // Sync role into formData.role + useEffect(() => { + setFormData((prev) => ({ ...prev, role })); + }, [role]); const handleInputChange = (e) => { const { name, value } = e.target; @@ -29,6 +33,17 @@ function Home() { const handleSubmit = (e) => { e.preventDefault(); console.log(`${formData.role} sign in attempted`, formData); + + // Redirect user based on role + if (formData.role === "coordinator") { + navigate("/coordinator/dashboard"); + } else if (formData.role === "student") { + navigate("/student/dashboard"); + } else if (formData.role === "supervisor") { + navigate("/supervisor/dashboard"); + } else { + alert("Please select a valid role."); + } }; return ( @@ -39,9 +54,7 @@ function Home() {
-

- Welcome back -

+

Welcome back

@@ -63,16 +76,6 @@ function Home() {

{r.charAt(0).toUpperCase() + r.slice(1)}

-
))}
@@ -80,9 +83,7 @@ function Home() {
@@ -122,26 +121,14 @@ function Home() {
-
+
- + Forgot password? -