Skip to content
Snippets Groups Projects
Commit 5b875a20 authored by Fatima Ezzahra Majidi's avatar Fatima Ezzahra Majidi
Browse files

ajout de roles

parent 1aaee02b
No related branches found
No related tags found
1 merge request!5Master
...@@ -20,6 +20,8 @@ import UpdateEnterpriseForm from "./components/UpdateEnterpriseForm.jsx"; ...@@ -20,6 +20,8 @@ import UpdateEnterpriseForm from "./components/UpdateEnterpriseForm.jsx";
import UpdateStageForm from "./components/UpdateStageForm.jsx"; import UpdateStageForm from "./components/UpdateStageForm.jsx";
import UpdateStudentForm from "./components/UpdateStudentForm.jsx"; import UpdateStudentForm from "./components/UpdateStudentForm.jsx";
import UpdateUnivSupervisorForm from "./components/UpdateUnivSupervisorForm.jsx"; import UpdateUnivSupervisorForm from "./components/UpdateUnivSupervisorForm.jsx";
import Login from "./components/Login.jsx";
import Logout from "./components/Logout.jsx";
function App() { function App() {
return ( return (
...@@ -32,6 +34,9 @@ function App() { ...@@ -32,6 +34,9 @@ function App() {
<Route path="/entreprises" element={<EnterpriseList />} /> <Route path="/entreprises" element={<EnterpriseList />} />
<Route path="/candidatures" element={<CandidacyList />} /> <Route path="/candidatures" element={<CandidacyList />} />
<Route path="/superviseurs" element={<UnivSupervisorList />} /> <Route path="/superviseurs" element={<UnivSupervisorList />} />
<Route path="/login" element={<Login />} />
<Route path="/logout" element={<Logout />} />
{/* Routes for Forms */} {/* Routes for Forms */}
<Route path="/ajouter-stage" element={<StageForm />} /> <Route path="/ajouter-stage" element={<StageForm />} />
......
...@@ -33,7 +33,7 @@ const CandidacyForm = () => { ...@@ -33,7 +33,7 @@ const CandidacyForm = () => {
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
fetch("http://localhost:8080/api/candidacies", { fetch("http://localhost:8080/api/candidacies/add", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ body: JSON.stringify({
......
...@@ -15,7 +15,7 @@ function CandidacyList() { ...@@ -15,7 +15,7 @@ function CandidacyList() {
// Function to delete candidacy // Function to delete candidacy
const handleDelete = (id) => { const handleDelete = (id) => {
if (window.confirm("Êtes-vous sûr de vouloir supprimer cette candidature ?")) { if (window.confirm("Êtes-vous sûr de vouloir supprimer cette candidature ?")) {
fetch(`http://localhost:8080/api/candidacies/${id}`, { method: "DELETE" }) fetch(`http://localhost:8080/api/candidacies/delete/${id}`, { method: "DELETE" })
.then(() => { .then(() => {
alert("Candidature supprimée avec succès !"); alert("Candidature supprimée avec succès !");
setCandidacies(candidacies.filter((candidacy) => candidacy.id !== id)); setCandidacies(candidacies.filter((candidacy) => candidacy.id !== id));
......
...@@ -10,7 +10,7 @@ function EnterpriseForm() { ...@@ -10,7 +10,7 @@ function EnterpriseForm() {
const newEnterprise = { name, address }; const newEnterprise = { name, address };
fetch("http://localhost:8080/api/enterprises", { fetch("http://localhost:8080/api/enterprises/add", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(newEnterprise) body: JSON.stringify(newEnterprise)
......
...@@ -20,7 +20,7 @@ function EnterpriseList() { ...@@ -20,7 +20,7 @@ function EnterpriseList() {
// Handle Delete // Handle Delete
const handleDelete = (id) => { const handleDelete = (id) => {
if (window.confirm("Voulez-vous vraiment supprimer cette entreprise ?")) { if (window.confirm("Voulez-vous vraiment supprimer cette entreprise ?")) {
fetch(`http://localhost:8080/api/enterprises/${id}`, { fetch(`http://localhost:8080/api/enterprises/delete/${id}`, {
method: "DELETE", method: "DELETE",
}) })
.then(() => { .then(() => {
......
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
const Login = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const navigate = useNavigate();
useEffect(() => {
const token = localStorage.getItem("token");
if (token) {
navigate("/"); // Redirect if already logged in
}
}, [navigate]);
const handleLogin = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:8080/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
});
if (!response.ok) {
throw new Error("Invalid credentials");
}
const data = await response.text(); // Adjust this if backend returns JSON
console.log("✅ Login successful!", data);
localStorage.setItem("token", "dummy-token"); // Store token (if applicable)
navigate("/"); // Redirect after login
} catch (error) {
console.error("❌ Login failed:", error.message);
setError("Invalid username or password");
}
};
return (
<div style={{ textAlign: "center", marginTop: "50px" }}>
<h2>Login</h2>
<form onSubmit={handleLogin}>
<div>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
</div>
<div>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <p style={{ color: "red" }}>{error}</p>}
<button type="submit">Login</button>
</form>
</div>
);
};
export default Login;
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
const Logout = () => {
const navigate = useNavigate();
useEffect(() => {
const logoutUser = async () => {
try {
const response = await fetch("http://localhost:8080/api/auth/logout", {
method: "POST",
credentials: "include", // Ensures cookies are sent and removed
});
if (response.ok) {
console.log("✅ Logout successful");
} else {
console.error("❌ Logout request failed:", response.status);
}
} catch (error) {
console.error("❌ Error during logout:", error);
}
// Clear stored auth details and redirect
localStorage.removeItem("token");
localStorage.removeItem("user");
navigate("/login");
};
logoutUser();
}, [navigate]);
return <h2>Logging out... Redirecting</h2>;
};
export default Logout;
...@@ -19,38 +19,70 @@ function Navbar() { ...@@ -19,38 +19,70 @@ function Navbar() {
</button> </button>
<div className="collapse navbar-collapse" id="navbarNav"> <div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav ms-auto"> <ul className="navbar-nav ms-auto">
<li className="nav-item">
<Link className="nav-link" to="/login">🔑 Login</Link> {/* Stages Dropdown */}
</li> <li className="nav-item dropdown">
<li className="nav-item"> <a className="nav-link dropdown-toggle" href="#" id="stagesDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<Link className="nav-link" to="/stages">📚 Stages</Link> 📚 Stages
</li> </a>
<li className="nav-item"> <ul className="dropdown-menu" aria-labelledby="stagesDropdown">
<Link className="nav-link" to="/etudiants">👨‍🎓 Étudiants</Link> <li><Link className="dropdown-item" to="/stages">📜 Liste des Stages</Link></li>
<li><Link className="dropdown-item" to="/ajouter-stage">➕ Ajouter un Stage</Link></li>
</ul>
</li> </li>
<li className="nav-item">
<Link className="nav-link" to="/entreprises">🏢 Entreprises</Link> {/* Étudiants Dropdown */}
<li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="etudiantsDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
👨‍🎓 Étudiants
</a>
<ul className="dropdown-menu" aria-labelledby="etudiantsDropdown">
<li><Link className="dropdown-item" to="/etudiants">📜 Liste des Étudiants</Link></li>
<li><Link className="dropdown-item" to="/ajouter-etudiant">➕ Ajouter un Étudiant</Link></li>
</ul>
</li> </li>
<li className="nav-item">
<Link className="nav-link" to="/candidatures">📝 Candidatures</Link> {/* Entreprises Dropdown */}
<li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="entreprisesDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
🏢 Entreprises
</a>
<ul className="dropdown-menu" aria-labelledby="entreprisesDropdown">
<li><Link className="dropdown-item" to="/entreprises">📜 Liste des Entreprises</Link></li>
<li><Link className="dropdown-item" to="/ajouter-entreprise">➕ Ajouter une Entreprise</Link></li>
</ul>
</li> </li>
<li className="nav-item">
<Link className="nav-link" to="/superviseurs">👨‍🏫 Superviseurs</Link> {/* Candidatures Dropdown */}
<li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="candidaturesDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
📝 Candidatures
</a>
<ul className="dropdown-menu" aria-labelledby="candidaturesDropdown">
<li><Link className="dropdown-item" to="/candidatures">📜 Liste des Candidatures</Link></li>
<li><Link className="dropdown-item" to="/ajouter-candidature">➕ Ajouter une Candidature</Link></li>
</ul>
</li> </li>
{/* Dropdown for adding new entries */} {/* Superviseurs Dropdown */}
<li className="nav-item dropdown"> <li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"> <a className="nav-link dropdown-toggle" href="#" id="superviseursDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
➕ Ajouter 👨‍🏫 Superviseurs
</a> </a>
<ul className="dropdown-menu" aria-labelledby="navbarDropdown"> <ul className="dropdown-menu" aria-labelledby="superviseursDropdown">
<li><Link className="dropdown-item" to="/ajouter-stage">Ajouter Stage</Link></li> <li><Link className="dropdown-item" to="/superviseurs">📜 Liste des Superviseurs</Link></li>
<li><Link className="dropdown-item" to="/ajouter-entreprise">Ajouter Entreprise</Link></li> <li><Link className="dropdown-item" to="/ajouter-univsuperviseur">➕ Ajouter un Superviseur</Link></li>
<li><Link className="dropdown-item" to="/ajouter-etudiant">Ajouter Étudiant</Link></li>
<li><Link className="dropdown-item" to="/ajouter-candidature">Ajouter Candidature</Link></li>
<li><Link className="dropdown-item" to="/ajouter-univsuperviseur">Ajouter Superviseur</Link></li>
</ul> </ul>
</li> </li>
{/* Authentication Links */}
<li className="nav-item">
<Link className="nav-link" to="/login">🔑 Login</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/logout">🔓 Logout</Link>
</li>
</ul> </ul>
</div> </div>
</div> </div>
......
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Navigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
function StageForm() { function StageForm() {
const [name, setName] = useState(""); const [title, setTitle] = useState("");
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
const [enterpriseId, setEnterpriseId] = useState(""); const [enterpriseId, setEnterpriseId] = useState(""); // Stores selected enterprise ID
const [enterprises, setEnterprises] = useState([]); const [enterprises, setEnterprises] = useState([]); // List of enterprises for dropdown
const navigate = useNavigate();
/** Fetch the list of enterprises from the backend **/
useEffect(() => { useEffect(() => {
fetch("http://localhost:8080/api/enterprises") fetch("http://localhost:8080/api/enterprises", {
method: "GET",
headers: { "Content-Type": "application/json" },
credentials: "include",
})
.then((res) => res.json()) .then((res) => res.json())
.then((data) => setEnterprises(data)) .then((data) => {
.catch((err) => console.error("Error fetching enterprises:", err)); console.log("📌 Enterprises loaded:", data);
setEnterprises(data);
})
.catch((err) => console.error("❌ Erreur lors du chargement des entreprises :", err));
}, []); }, []);
/** Handle form submission **/
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
// Ensure enterpriseId is selected
if (!enterpriseId || enterpriseId === "none") {
alert("❌ Veuillez sélectionner une entreprise !");
return;
}
const newStage = { const newStage = {
name, title,
description, description,
enterprise: { id: enterpriseId } enterprise: { id: parseInt(enterpriseId, 10) }, // Send enterprise as an object
}; };
fetch("http://localhost:8080/api/stages", { console.log("📌 Sending stage data:", newStage);
fetch("http://localhost:8080/api/stages/add", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(newStage) credentials: "include",
body: JSON.stringify(newStage), // Ensure correct format
}) })
.then((res) => res.json()) .then((res) => {
.then(() => { console.log("📌 Response status:", res.status);
alert("Stage added successfully!");
setName(""); if (!res.ok) {
return res.text().then((text) => {
console.error("❌ Backend Error (text):", text);
throw new Error(text || "Erreur inconnue");
});
}
return res.json();
})
.then((data) => {
console.log("✅ Stage added successfully:", data);
alert("Stage ajouté avec succès !");
setTitle("");
setDescription(""); setDescription("");
setEnterpriseId(""); setEnterpriseId(""); // Reset dropdown
navigate("/stages");
}) })
.catch((err) => console.error("Error adding stage:", err)); .catch((err) => console.error("Erreur lors de l'ajout du stage :", err.message));
}; };
// Handle cancel button
const handleCancel = () => {
Navigate("/stages"); // Redirect back to candidacy list /** Handle cancel button **/
const handleCancel = () => {
navigate("/stages"); // Redirect back to stages list
}; };
return ( return (
...@@ -47,28 +81,49 @@ function StageForm() { ...@@ -47,28 +81,49 @@ function StageForm() {
<h2>Ajouter un Stage</h2> <h2>Ajouter un Stage</h2>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Nom du Stage</label> <label className="form-label">Titre du Stage</label>
<input type="text" className="form-control" value={name} onChange={(e) => setName(e.target.value)} required /> <input
type="text"
className="form-control"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div> </div>
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Description</label> <label className="form-label">Description</label>
<input type="text" className="form-control" value={description} onChange={(e) => setDescription(e.target.value)} required /> <textarea
className="form-control"
value={description}
onChange={(e) => setDescription(e.target.value)}
required
></textarea>
</div> </div>
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Entreprise</label> <label className="form-label">Entreprise</label>
<select className="form-select" value={enterpriseId} onChange={(e) => setEnterpriseId(e.target.value)} required> <select
<option value="">Sélectionner une entreprise</option> className="form-control"
value={enterpriseId}
onChange={(e) => setEnterpriseId(e.target.value)}
required
>
<option value="none">Sélectionnez une entreprise</option>
{enterprises.map((enterprise) => ( {enterprises.map((enterprise) => (
<option key={enterprise.id} value={enterprise.id}>{enterprise.name}</option> <option key={enterprise.id} value={enterprise.id}>
{enterprise.name}
</option>
))} ))}
</select> </select>
</div> </div>
<div className="d-flex gap-2"> <div className="d-flex gap-2">
<button type="submit" className="btn btn-primary"> <button type="submit" className="btn btn-primary">
Ajouter Ajouter
</button> </button>
<button type="button" className="btn btn-secondary" onClick={handleCancel}>Annuler</button> <button type="button" className="btn btn-secondary" onClick={handleCancel}>
</div> </form> Annuler
</button>
</div>
</form>
</div> </div>
); );
} }
......
import React, { useState } from "react"; import React, { useState } from "react";
import { Navigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
function StudentForm() { function StudentForm() {
const [firstname, setFirstname] = useState(""); const [firstname, setFirstname] = useState("");
const [lastname, setLastname] = useState(""); const [lastname, setLastname] = useState("");
const navigate = useNavigate(); // Correct use of useNavigate
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
const newStudent = { firstname, lastname }; const newStudent = { firstname, lastname };
fetch("http://localhost:8080/api/students", { fetch("http://localhost:8080/api/students/add", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(newStudent) body: JSON.stringify(newStudent)
...@@ -23,9 +25,9 @@ function StudentForm() { ...@@ -23,9 +25,9 @@ function StudentForm() {
}) })
.catch((err) => console.error("Erreur lors de l'ajout de l'étudiant :", err)); .catch((err) => console.error("Erreur lors de l'ajout de l'étudiant :", err));
}; };
// Handle cancel button // Handle cancel button correctly
const handleCancel = () => { const handleCancel = () => {
Navigate("/etudiants"); // Redirect back to candidacy list navigate("/etudiants"); // Redirect back to student list
}; };
return ( return (
......
...@@ -9,7 +9,7 @@ function UnivSupervisorForm() { ...@@ -9,7 +9,7 @@ function UnivSupervisorForm() {
const newSupervisor = { name }; const newSupervisor = { name };
fetch("http://localhost:8080/api/univsupervisors", { fetch("http://localhost:8080/api/univsupervisors/add", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(newSupervisor), body: JSON.stringify(newSupervisor),
......
...@@ -22,7 +22,7 @@ function UpdateUnivSupervisorForm() { ...@@ -22,7 +22,7 @@ function UpdateUnivSupervisorForm() {
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
fetch(`http://localhost:8080/api/univsupervisors/${id}`, { fetch(`http://localhost:8080/api/univsupervisors/update/${id}`, {
method: "PUT", method: "PUT",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(supervisor), body: JSON.stringify(supervisor),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment