diff --git a/client/src/pages/Home.js b/client/src/pages/Home.js index c8ed3df5..331a14cb 100644 --- a/client/src/pages/Home.js +++ b/client/src/pages/Home.js @@ -34,10 +34,10 @@ function Home() { const handleSubmit = async (e) => { e.preventDefault(); - console.log(`${formData.role} sign in attempted`, formData); const { email: ouEmail, password, role } = formData; + if (!ouEmail || !password || !role) { return Swal.fire({ icon: "warning", @@ -61,20 +61,24 @@ function Home() { const data = await response.json(); if (response.ok) { - Swal.fire({ - icon: "success", - title: "Login Successful 🌟", - text: `Welcome back, ${role}!`, - }); - - // Redirect user based on role - if (role === "coordinator") { - navigate("/coordinator-dashboard"); - } else if (role === "student") { - navigate("/student-dashboard"); - } else if (role === "supervisor") { - navigate("/supervisor-dashboard"); - } + const user = data.user; + + // Store only required fields + const limitedUserInfo = { + fullName: user.fullName, + id: user._id, + email:user.ouEmail + }; + + localStorage.setItem("ipmsUser", JSON.stringify(limitedUserInfo)); + + // Swal.fire({ + // icon: "success", + // title: "Login Successful", + // text: `Welcome back, `, + // }); + + navigate("/student-dashboard"); } else { Swal.fire({ icon: "error", @@ -126,6 +130,7 @@ function Home() { role: r, }) } + >

diff --git a/client/src/pages/ProtectedRouteStudent.jsx b/client/src/pages/ProtectedRouteStudent.jsx new file mode 100644 index 00000000..02a0396e --- /dev/null +++ b/client/src/pages/ProtectedRouteStudent.jsx @@ -0,0 +1,16 @@ +// src/components/ProtectedRouteStudent.js +import React from "react"; +import { Navigate } from "react-router-dom"; + +const ProtectedRouteStudent = ({ children }) => { + const user = JSON.parse(localStorage.getItem("ipmsUser")); + + // Check if user info is missing + if (!user || !user.id || !user.fullName) { + return ; + } + + return children; + }; + +export default ProtectedRouteStudent; diff --git a/client/src/pages/StudentDashboard.jsx b/client/src/pages/StudentDashboard.jsx new file mode 100644 index 00000000..af9f4614 --- /dev/null +++ b/client/src/pages/StudentDashboard.jsx @@ -0,0 +1,96 @@ +import React, { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import "../styles/StudentDashboard.css"; // Make sure you create this CSS + +const StudentDashboard = () => { + const navigate = useNavigate(); + + const user = JSON.parse(localStorage.getItem("ipmsUser")); + const backendUrl = process.env.REACT_APP_API_URL; + const ouEmail = user?.email; + const [approvalStatus, setApprovalStatus] = useState(false) + + + useEffect(() => { + const fetchData = async () => { + try { + const res = await fetch(`${backendUrl}/api/student`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ ouEmail }), + }); + + const data = await res.json(); + setApprovalStatus(data.approvalStatus); + + } catch (err) { + console.error("Error fetching internship data", err); + } + }; + + if (ouEmail) { + fetchData(); + } + }, [ouEmail]); + + + + + + return ( +

+
+

Welcome, {user.fullName}

+
+ +
+
+
+

Request Internship (FORM A1)

+

Track your internship journey

+
+ +
+ +
+
+

Weekly Report (Form A2)

+ {!approvalStatus && ( +

+ Finish your Form A1 first +

+ )} +
+ +
+
+
+ + ); +}; + +export default StudentDashboard; diff --git a/client/src/router.js b/client/src/router.js index db8aaf77..8fac8de1 100644 --- a/client/src/router.js +++ b/client/src/router.js @@ -18,9 +18,11 @@ import SupervisorDashboard from "./pages/SupervisorDashboard"; import CoordinatorDashboard from "./pages/CoordinatorDashboard"; import CoordinatorRequestDetailView from "./pages/CoordinatorRequestDetailView"; import TokenRenewal from "./pages/TokenRenewal"; +import StudentDashboard from "./pages/StudentDashboard"; +import ProtectedRouteStudent from "./pages/ProtectedRouteStudent"; // Create and export the router configuration -const router = createBrowserRouter([ +const router = createBrowserRouter([ { path: "/", element: , @@ -33,11 +35,20 @@ const router = createBrowserRouter([ { path: "signup", element: , - }, + }, { path: "weekly-report", element: , }, + { + path: "/student-dashboard", + element: ( + + + + ) + }, + { path: "a1-form", element: , diff --git a/client/src/styles/StudentDashboard.css b/client/src/styles/StudentDashboard.css new file mode 100644 index 00000000..71975b3e --- /dev/null +++ b/client/src/styles/StudentDashboard.css @@ -0,0 +1,71 @@ +.student-dashboard { + display: flex; + flex-direction: column; + align-items: center; + padding: 2rem 1rem; + background-color: #f7f7f7; + min-height: 90vh; + } + + .dashboard-header { + width: 100%; + max-width: 900px; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; + } + + .user-role { + font-weight: bold; + font-size: 1rem; + color: #5c0a0a; + } + + .dashboard-card { + background-color: white; + border-radius: 10px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); + padding: 2rem; + width: 100%; + max-width: 900px; + } + + .card-section { + background-color: #842020; + border-radius: 10px; + padding: 1.5rem; + margin-bottom: 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; + color: white; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.1); + } + + .card-content h3 { + margin: 0; + font-size: 1.2rem; + font-weight: 600; + } + + .card-content p { + margin: 5px 0 0; + font-size: 0.9rem; + } + + .card-button { + background-color: white; + color: #842020; + border: none; + padding: 8px 16px; + border-radius: 6px; + font-weight: 500; + cursor: pointer; + transition: 0.3s ease-in-out; + } + + .card-button:hover { + background-color: #e6e6e6; + } + \ No newline at end of file diff --git a/server/index.js b/server/index.js index 45104393..c64c5d22 100644 --- a/server/index.js +++ b/server/index.js @@ -10,6 +10,7 @@ const formRoutes = require("./routes/formRoutes"); const emailRoutes = require("./routes/emailRoutes"); const tokenRoutes = require("./routes/token"); const approvalRoutes = require("./routes/approvalRoutes"); +const studentRoutes = require("./routes/studentRoutes") const outcomeRoutes = require("./routes/outcomeRoutes"); @@ -78,6 +79,7 @@ app.use("/api/token", tokenRoutes); app.use("/api", approvalRoutes); app.use("/api/reports", weeklyReportRoutes); +app.use("/api/student",studentRoutes) app.post("/api/createUser", async (req, res) => { try { const { userName, email, password, role } = req.body; diff --git a/server/routes/studentRoutes.js b/server/routes/studentRoutes.js new file mode 100644 index 00000000..55714ef8 --- /dev/null +++ b/server/routes/studentRoutes.js @@ -0,0 +1,30 @@ +const express = require("express"); +const router = express.Router(); +const InternshipRequest = require("../models/InternshipRequest"); +const User = require("../models/User"); + +// GET internship request by student's ouEmail +router.post("/", async (req, res) => { + const { ouEmail } = req.body; + console.log(ouEmail) + try { + const studentUser = await User.findOne({ email: ouEmail }); + if (!studentUser) { + return res.status(404).json({ message: "Student not found" }); + } + + const internshipData = await InternshipRequest.findOne({ student: studentUser._id }); + + if (!internshipData) { + return res.status(404).json({ message: "No internship request found for this student" }); + } + const approvalStatus = internshipData.status == "approved" ? true : false + return res.status(200).json({ message: "Success" , approvalStatus }); + } catch (error) { + console.error("Error fetching internship request:", error); + return res.status(500).json({ message: "Server error" }); + } + }); + + +module.exports = router; \ No newline at end of file diff --git a/server/routes/token.js b/server/routes/token.js index 4d82d42d..f83355ed 100644 --- a/server/routes/token.js +++ b/server/routes/token.js @@ -5,6 +5,7 @@ const crypto = require("crypto"); const bcrypt = require("bcrypt"); const TokenRequest = require("../models/TokenRequest"); const emailService = require("../services/emailService"); +const User = require("../models/User") const JWT_SECRET = process.env.JWT_SECRET; const FRONTEND_URL = process.env.FRONTEND_URL; @@ -51,7 +52,10 @@ router.post("/request", async (req, res) => { activationLinkSentAt: new Date(), }); + + await request.save(); + const activationLink = `${FRONTEND_URL}/activate/${plainToken}`; const emailBody = `