From 22902b7da1dfd23ea34ab108df826c27b1ead4dd Mon Sep 17 00:00:00 2001 From: Aakash452 Date: Fri, 18 Apr 2025 11:21:57 -0500 Subject: [PATCH] Implemented student dashboard with conditional UI and navigation --- client/src/pages/Home.js | 82 +++++++++++------- client/src/pages/ProtectedRouteStudent.jsx | 16 ++++ client/src/pages/StudentDashboard.jsx | 96 ++++++++++++++++++++++ client/src/router.js | 15 +++- client/src/styles/StudentDashboard.css | 71 ++++++++++++++++ server/index.js | 2 + server/routes/studentRoutes.js | 30 +++++++ server/routes/token.js | 4 + 8 files changed, 283 insertions(+), 33 deletions(-) create mode 100644 client/src/pages/ProtectedRouteStudent.jsx create mode 100644 client/src/pages/StudentDashboard.jsx create mode 100644 client/src/styles/StudentDashboard.css create mode 100644 server/routes/studentRoutes.js diff --git a/client/src/pages/Home.js b/client/src/pages/Home.js index c1fdf9e6..8512f969 100644 --- a/client/src/pages/Home.js +++ b/client/src/pages/Home.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; import { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import "../styles/App.css"; @@ -7,7 +7,7 @@ import "../styles/login.css"; import StudentIcon from "../Icons/StudentIcon"; import CoordinatorIcon from "../Icons/CoordinatorIcon"; import SupervisorIcon from "../Icons/SupervisorIcon"; -import Swal from 'sweetalert2'; +import Swal from "sweetalert2"; function Home() { const navigate = useNavigate(); @@ -17,7 +17,6 @@ function Home() { role: "", }); const [showPassword, setShowPassword] = useState(false); - const handleInputChange = (e) => { const { name, value } = e.target; @@ -29,9 +28,9 @@ function Home() { const handleSubmit = async (e) => { e.preventDefault(); - + const { email: ouEmail, password, role } = formData; - + if (!ouEmail || !password || !role) { return Swal.fire({ icon: "warning", @@ -39,24 +38,40 @@ function Home() { text: "Please fill in all fields to sign in 💫", }); } - + try { - const response = await fetch(`${process.env.REACT_APP_API_URL}/api/token/user-login`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ ouEmail, password, role }), - }); - + const response = await fetch( + `${process.env.REACT_APP_API_URL}/api/token/user-login`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ ouEmail, password, role }), + } + ); + const data = await response.json(); - + if (response.ok) { - Swal.fire({ - icon: "success", - title: "Login Successful 🌟", - text: `Welcome back, ${role}!`, - }); + 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", @@ -73,8 +88,6 @@ function Home() { }); } }; - - return (
@@ -101,11 +114,15 @@ function Home() { ].map(({ role: r, Icon }) => (
setFormData({ - ...formData, - role: r, - })} + className={`role-card ${ + formData.role === r ? "selected" : "" + }`} + onClick={() => + setFormData({ + ...formData, + role: r, + }) + } >

@@ -179,17 +196,20 @@ function Home() { marginBottom: "1rem", }} > -

+
+ +
+
+

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 5461fdc0..0289dea1 100644 --- a/client/src/router.js +++ b/client/src/router.js @@ -16,9 +16,11 @@ import A3JobEvaluationForm from "./pages/A3JobEvaluationForm"; import ActivateAccount from "./pages/ActivateAccount"; import SupervisorDashboard from "./pages/SupervisorDashboard"; import CoordinatorDashboard from "./pages/CoordinatorDashboard"; +import StudentDashboard from "./pages/StudentDashboard"; +import ProtectedRouteStudent from "./pages/ProtectedRouteStudent"; // Create and export the router configuration -const router = createBrowserRouter([ +const router = createBrowserRouter([ { path: "/", element: , @@ -31,11 +33,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 26854aa6..6e4e69cf 100644 --- a/server/index.js +++ b/server/index.js @@ -11,6 +11,7 @@ require("dotenv").config(); const emailRoutes = require("./routes/emailRoutes"); const tokenRoutes = require("./routes/token"); const approvalRoutes = require("./routes/approvalRoutes"); +const studentRoutes = require("./routes/studentRoutes") // Import cron job manager and register jobs const cronJobManager = require("./utils/cronUtils"); @@ -74,6 +75,7 @@ app.use("/api/email", emailRoutes); 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 { 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 247fda86..dd619e89 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 = `