Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4b3e72b
Sprint 2 Task 4: Approval/Email/Logging
Kamal-Poshala Apr 11, 2025
2cf2335
Resolved merge conflicts with origin/main
Kamal-Poshala Apr 12, 2025
11e47db
Finalized coordinator approval/rejection
Kamal-Poshala Apr 12, 2025
1eeae10
Merge pull request #80 from IPMS-Project/teama/4
Kamal-Poshala Apr 13, 2025
149289b
request detail view
vijaychirram Apr 13, 2025
65edf7d
Updated routes in router.js
vijaychirram Apr 13, 2025
f2e5966
final request detail view
vijaychirram Apr 14, 2025
334e991
Merge pull request #99 from IPMS-Project/teama/3
vijaychirram Apr 14, 2025
a053b16
Merge branch 'main' into team-a/development
Kamal-Poshala Apr 14, 2025
19c3d24
Refactor Home component: clean up code formatting, streamline role-ba…
Charan-Nimmagadda Apr 14, 2025
4030ea0
npx prettier on client
Apr 14, 2025
5dea277
Isabell - interval update requests & style changes
Apr 14, 2025
35537a4
style fix
Apr 14, 2025
e575dc3
url cleanup
Apr 14, 2025
30e41d4
Remove legacy NODE_OPTIONS from start script in package.json
Charan-Nimmagadda Apr 14, 2025
d1af5d2
Merge branch 'team-a/development' of https://github.com/NNPhaniCharan…
Charan-Nimmagadda Apr 14, 2025
2080bd4
final commit for sprint2
vijaychirram Apr 14, 2025
d2566eb
coodrinator dashboard with request detail view and approval login fun…
vijaychirram Apr 14, 2025
1c991ac
Merge branch 'main' into teama/3
Kamal-Poshala Apr 14, 2025
f42b58f
Delete server/utils/logger.test.js
Kamal-Poshala Apr 14, 2025
3aba787
Delete server/utils/cronUtils.test.js
Kamal-Poshala Apr 14, 2025
db48bff
fix tests
Apr 14, 2025
551a5ed
remove unused value 'setRole'
Apr 14, 2025
525a613
Update package.json
vijaychirram Apr 15, 2025
1a5ec75
refactor: clean up code by removing unused files and optimizing email…
Charan-Nimmagadda Apr 15, 2025
11ad8b0
Merge branch 'teama/3' of https://github.com/NNPhaniCharan/IPMS into …
Charan-Nimmagadda Apr 15, 2025
5e1ffad
Merge branch 'main' into teama/3
Kamal-Poshala Apr 15, 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/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
]
}
}
50 changes: 43 additions & 7 deletions client/src/pages/CoordinatorDashboard.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
import React from "react";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import "../styles/dashboard.css";

function CoordinatorDashboard() {
const [requests, setRequests] = useState([]);
const navigate = useNavigate();

const fetchRequests = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/api/coordinator/requests`
);
setRequests(res.data);
} catch (err) {
console.error("Failed to fetch requests:", err);
}
};

useEffect(() => {
fetchRequests();
}, []);

const CoordinatorDashboard = () => {
return (
<div style={{ padding: "20px", textAlign: "center" }}>
<h2>Coordinator Dashboard</h2>
<p>Welcome, Coordinator!</p>
<div className="dashboard-container">
<h2 className="dashboard-title">Coordinator Dashboard</h2>

{requests.length === 0 ? (
<p>No Pending Requests</p>
) : (
requests.map((req) => (
<div
key={req._id}
className="request-card"
onClick={() => navigate(`/coordinator/request/${req._id}`)}
>
{/* <h4>{req.student.userName}</h4>
<p>Email: {req.student.email}</p> */}
<p>Company: {req.workplace.name}</p>
</div>
))
)}
</div>
);
};
}

export default CoordinatorDashboard;
export default CoordinatorDashboard;
107 changes: 107 additions & 0 deletions client/src/pages/CoordinatorRequestDetailView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import axios from "axios";
import "../styles/CoordinatorRequestDetailView.css";

const CoordinatorRequestDetailView = () => {
const { id } = useParams();
const navigate = useNavigate();
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]);

const handleApprove = async () => {
try {
const res = await axios.post(
`${process.env.REACT_APP_API_URL}/api/coordinator/request/${id}/approve`
);
alert(res.data.message);
navigate("/coordinator-dashboard");
} catch (err) {
console.error("Approval failed:", err);
alert("Error approving request.");
}
};

const handleReject = async () => {
const reason = prompt("Please enter a reason for rejection:");
if (!reason) return alert("Rejection reason required!");

try {
const res = await axios.post(
`${process.env.REACT_APP_API_URL}/api/coordinator/request/${id}/reject`,
{ reason }
);
alert(res.data.message);
navigate("/coordinator-dashboard");
} catch (err) {
console.error("Rejection failed:", err);
alert("Error rejecting request.");
}
};

if (!data) return <h2>Loading...</h2>;

const { requestData, supervisorStatus } = data;

return (
<div className="request-form">
<h2 className="dashboard-title">Internship Request Details</h2>

<div className="dashboard-card">
<p>
<b>Student:</b> {requestData.student.userName}
</p>
<p>
<b>Email:</b> {requestData.student.email}
</p>
<p>
<b>Company:</b> {requestData.workplace.name}
</p>
<p>
<b>Supervisor Status:</b> {supervisorStatus}
</p>

<h3 className="section-title">Tasks & CS Outcomes</h3>
<table className="data-table">
<thead>
<tr>
<th>Task</th>
<th>Outcomes</th>
</tr>
</thead>
<tbody>
{requestData.tasks.map((task, idx) => (
<tr key={idx}>
<td>{task.description}</td>
<td>{task.outcomes.join(", ")}</td>
</tr>
))}
</tbody>
</table>

<div className="action-buttons" style={{ marginTop: "20px" }}>
<button className="approve-btn" onClick={handleApprove}>
Approve
</button>
<button className="reject-btn" onClick={handleReject}>
Reject
</button>
<button
className="back-btn"
onClick={() => navigate("/coordinator-dashboard")}
>
Back
</button>
</div>
</div>
</div>
);
};

export default CoordinatorRequestDetailView;
87 changes: 50 additions & 37 deletions client/src/pages/Home.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
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";
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();
const [formData, setFormData] = useState({
email: "",
password: "",
role: "",

role: "student",
});
const [showPassword, setShowPassword] = useState(false);

const [role] = useState("student");

// Sync role into formData.role
useEffect(() => {
setFormData((prev) => ({ ...prev, role }));
}, [role]);

const handleInputChange = (e) => {
const { name, value } = e.target;
Expand All @@ -29,34 +34,47 @@ 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",
title: "Oops!",
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",
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 }),
},
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}!`,
});

// 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");
}
} else {
Swal.fire({
icon: "error",
Expand All @@ -73,8 +91,6 @@ function Home() {
});
}
};



return (
<div className="content-container">
Expand All @@ -101,26 +117,20 @@ function Home() {
].map(({ role: r, Icon }) => (
<div
key={r}
className={`role-card ${formData.role === r ? "selected" : ""}`}
onClick={() => setFormData({
...formData,
role: r,
})}
className={`role-card ${
formData.role === r ? "selected" : ""
}`}
onClick={() =>
setFormData({
...formData,
role: r,
})
}
>
<Icon />
<p className="role-label">
{r.charAt(0).toUpperCase() + r.slice(1)}
</p>
<span
className="info-icon"
title={
r === "student"
? "Students request internships and submit weekly reports."
: r === "supervisor"
? "Supervisors review and approve student progress."
: "Coordinators manage the internship workflow and approvals."
}
></span>
</div>
))}
</div>
Expand Down Expand Up @@ -179,17 +189,20 @@ function Home() {
marginBottom: "1rem",
}}
>
<label className='d-flex align-items-center' >
<label className="d-flex align-items-center">
<input type="checkbox" style={{ marginRight: "6px" }} />
Remember me
</label>
<Link
to="/"
style={{ color: "#7f1d1d", fontWeight: "500", textDecoration: "underline" }}
style={{
color: "#7f1d1d",
fontWeight: "500",
textDecoration: "underline",
}}
>
Forgot password?
</Link>

</div>

<button type="submit" className="login-button">
Expand Down Expand Up @@ -220,4 +233,4 @@ function Home() {
);
}

export default Home;
export default Home;
5 changes: 5 additions & 0 deletions client/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ActivateAccount from "./pages/ActivateAccount";
import A4PresentationEvaluationForm from "./pages/A4PresentationEvaluationForm";
import SupervisorDashboard from "./pages/SupervisorDashboard";
import CoordinatorDashboard from "./pages/CoordinatorDashboard";
import CoordinatorRequestDetailView from "./pages/CoordinatorRequestDetailView";

// Create and export the router configuration
const router = createBrowserRouter([
Expand Down Expand Up @@ -60,6 +61,10 @@ const router = createBrowserRouter([
path: "coordinator-dashboard",
element: <CoordinatorDashboard />,
},
{
path: "coordinator/request/:id",
element: <CoordinatorRequestDetailView />,
},
],
},
]);
Expand Down
17 changes: 17 additions & 0 deletions client/src/styles/CoordinatorRequestDetailView.css
Original file line number Diff line number Diff line change
@@ -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;
}
Loading