From 5b875a20827a1186022fe112188e5b4a7370e7bc Mon Sep 17 00:00:00 2001
From: fatima ezzahra majidi <fatima-ezzahra.majidi.etu@univ-lille.fr>
Date: Fri, 7 Mar 2025 04:35:48 +0000
Subject: [PATCH] ajout de roles

---
 src/App.js                                  |   5 +
 src/components/CandidacyForm.jsx            |   2 +-
 src/components/CandidacyList.jsx            |   2 +-
 src/components/EnterpriseForm.jsx           |   2 +-
 src/components/EnterpriseList.jsx           |   2 +-
 src/components/Login.jsx                    |  73 ++++++++++++
 src/components/Logout.jsx                   |  36 ++++++
 src/components/Navbar.jsx                   |  78 +++++++++----
 src/components/StageForm.jsx                | 119 ++++++++++++++------
 src/components/StudentForm.jsx              |  12 +-
 src/components/UnivSupervisorForm.jsx       |   2 +-
 src/components/UpdateUnivSupervisorForm.jsx |   2 +-
 12 files changed, 269 insertions(+), 66 deletions(-)
 create mode 100644 src/components/Login.jsx
 create mode 100644 src/components/Logout.jsx

diff --git a/src/App.js b/src/App.js
index d40c687..e1ae369 100644
--- a/src/App.js
+++ b/src/App.js
@@ -20,6 +20,8 @@ import UpdateEnterpriseForm from "./components/UpdateEnterpriseForm.jsx";
 import UpdateStageForm from "./components/UpdateStageForm.jsx";
 import UpdateStudentForm from "./components/UpdateStudentForm.jsx";
 import UpdateUnivSupervisorForm from "./components/UpdateUnivSupervisorForm.jsx";
+import Login from "./components/Login.jsx";
+import Logout from "./components/Logout.jsx";
 
 function App() {
   return (
@@ -32,6 +34,9 @@ function App() {
           <Route path="/entreprises" element={<EnterpriseList />} />
           <Route path="/candidatures" element={<CandidacyList />} />
           <Route path="/superviseurs" element={<UnivSupervisorList />} />
+          <Route path="/login" element={<Login />} />
+          <Route path="/logout" element={<Logout />} />
+
 
           {/* Routes for Forms */}
           <Route path="/ajouter-stage" element={<StageForm />} />
diff --git a/src/components/CandidacyForm.jsx b/src/components/CandidacyForm.jsx
index 6a7bb6a..79953db 100644
--- a/src/components/CandidacyForm.jsx
+++ b/src/components/CandidacyForm.jsx
@@ -33,7 +33,7 @@ const CandidacyForm = () => {
   const handleSubmit = (e) => {
     e.preventDefault();
 
-    fetch("http://localhost:8080/api/candidacies", {
+    fetch("http://localhost:8080/api/candidacies/add", {
       method: "POST",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify({
diff --git a/src/components/CandidacyList.jsx b/src/components/CandidacyList.jsx
index cfc2733..1e39ddb 100644
--- a/src/components/CandidacyList.jsx
+++ b/src/components/CandidacyList.jsx
@@ -15,7 +15,7 @@ function CandidacyList() {
   // Function to delete candidacy
   const handleDelete = (id) => {
     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(() => {
           alert("Candidature supprimée avec succès !");
           setCandidacies(candidacies.filter((candidacy) => candidacy.id !== id));
diff --git a/src/components/EnterpriseForm.jsx b/src/components/EnterpriseForm.jsx
index 08249a2..01a66f4 100644
--- a/src/components/EnterpriseForm.jsx
+++ b/src/components/EnterpriseForm.jsx
@@ -10,7 +10,7 @@ function EnterpriseForm() {
 
     const newEnterprise = { name, address };
 
-    fetch("http://localhost:8080/api/enterprises", {
+    fetch("http://localhost:8080/api/enterprises/add", {
       method: "POST",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify(newEnterprise)
diff --git a/src/components/EnterpriseList.jsx b/src/components/EnterpriseList.jsx
index 3546fb2..6bcdfcb 100644
--- a/src/components/EnterpriseList.jsx
+++ b/src/components/EnterpriseList.jsx
@@ -20,7 +20,7 @@ function EnterpriseList() {
   // Handle Delete
   const handleDelete = (id) => {
     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",
       })
         .then(() => {
diff --git a/src/components/Login.jsx b/src/components/Login.jsx
new file mode 100644
index 0000000..d6eb8c5
--- /dev/null
+++ b/src/components/Login.jsx
@@ -0,0 +1,73 @@
+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;
diff --git a/src/components/Logout.jsx b/src/components/Logout.jsx
new file mode 100644
index 0000000..fb00d82
--- /dev/null
+++ b/src/components/Logout.jsx
@@ -0,0 +1,36 @@
+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;
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index 9f0dbc6..4274267 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -19,38 +19,70 @@ function Navbar() {
         </button>
         <div className="collapse navbar-collapse" id="navbarNav">
           <ul className="navbar-nav ms-auto">
-            <li className="nav-item">
-              <Link className="nav-link" to="/login">🔑 Login</Link>
-            </li>
-            <li className="nav-item">
-              <Link className="nav-link" to="/stages">📚 Stages</Link>
-            </li>
-            <li className="nav-item">
-              <Link className="nav-link" to="/etudiants">👨‍🎓 Étudiants</Link>
+
+            {/* Stages Dropdown */}
+            <li className="nav-item dropdown">
+              <a className="nav-link dropdown-toggle" href="#" id="stagesDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
+                📚 Stages
+              </a>
+              <ul className="dropdown-menu" aria-labelledby="stagesDropdown">
+                <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 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 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 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>
 
-            {/* Dropdown for adding new entries */}
+            {/* Superviseurs Dropdown */}
             <li className="nav-item dropdown">
-              <a className="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
-                ➕ Ajouter
+              <a className="nav-link dropdown-toggle" href="#" id="superviseursDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
+                👨‍🏫 Superviseurs
               </a>
-              <ul className="dropdown-menu" aria-labelledby="navbarDropdown">
-                <li><Link className="dropdown-item" to="/ajouter-stage">Ajouter Stage</Link></li>
-                <li><Link className="dropdown-item" to="/ajouter-entreprise">Ajouter Entreprise</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 className="dropdown-menu" aria-labelledby="superviseursDropdown">
+                <li><Link className="dropdown-item" to="/superviseurs">📜 Liste des Superviseurs</Link></li>
+                <li><Link className="dropdown-item" to="/ajouter-univsuperviseur">➕ Ajouter un Superviseur</Link></li>
               </ul>
             </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>
         </div>
       </div>
diff --git a/src/components/StageForm.jsx b/src/components/StageForm.jsx
index 07f669f..ce4841c 100644
--- a/src/components/StageForm.jsx
+++ b/src/components/StageForm.jsx
@@ -1,45 +1,79 @@
 import React, { useState, useEffect } from "react";
-import { Navigate } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
 
 function StageForm() {
-  const [name, setName] = useState("");
+  const [title, setTitle] = useState("");
   const [description, setDescription] = useState("");
-  const [enterpriseId, setEnterpriseId] = useState("");
-  const [enterprises, setEnterprises] = useState([]);
+  const [enterpriseId, setEnterpriseId] = useState(""); // Stores selected enterprise ID
+  const [enterprises, setEnterprises] = useState([]); // List of enterprises for dropdown
+  const navigate = useNavigate();
 
+  /** Fetch the list of enterprises from the backend **/
   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((data) => setEnterprises(data))
-      .catch((err) => console.error("Error fetching enterprises:", err));
+      .then((data) => {
+        console.log("📌 Enterprises loaded:", data);
+        setEnterprises(data);
+      })
+      .catch((err) => console.error("❌ Erreur lors du chargement des entreprises :", err));
   }, []);
 
+  /** Handle form submission **/
   const handleSubmit = (e) => {
     e.preventDefault();
-
+  
+    // Ensure enterpriseId is selected
+    if (!enterpriseId || enterpriseId === "none") {
+      alert("❌ Veuillez sélectionner une entreprise !");
+      return;
+    }
+  
     const newStage = {
-      name,
+      title,
       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",
       headers: { "Content-Type": "application/json" },
-      body: JSON.stringify(newStage)
+      credentials: "include",
+      body: JSON.stringify(newStage), // Ensure correct format
     })
-      .then((res) => res.json())
-      .then(() => {
-        alert("Stage added successfully!");
-        setName("");
+      .then((res) => {
+        console.log("📌 Response status:", res.status);
+  
+        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("");
-        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 (
@@ -47,28 +81,49 @@ function StageForm() {
       <h2>Ajouter un Stage</h2>
       <form onSubmit={handleSubmit}>
         <div className="mb-3">
-          <label className="form-label">Nom du Stage</label>
-          <input type="text" className="form-control" value={name} onChange={(e) => setName(e.target.value)} required />
+          <label className="form-label">Titre du Stage</label>
+          <input
+            type="text"
+            className="form-control"
+            value={title}
+            onChange={(e) => setTitle(e.target.value)}
+            required
+          />
         </div>
         <div className="mb-3">
           <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 className="mb-3">
           <label className="form-label">Entreprise</label>
-          <select className="form-select" value={enterpriseId} onChange={(e) => setEnterpriseId(e.target.value)} required>
-            <option value="">Sélectionner une entreprise</option>
+          <select
+            className="form-control"
+            value={enterpriseId}
+            onChange={(e) => setEnterpriseId(e.target.value)}
+            required
+          >
+            <option value="none">Sélectionnez une entreprise</option>
             {enterprises.map((enterprise) => (
-              <option key={enterprise.id} value={enterprise.id}>{enterprise.name}</option>
+              <option key={enterprise.id} value={enterprise.id}>
+                {enterprise.name}
+              </option>
             ))}
           </select>
         </div>
         <div className="d-flex gap-2">
-            <button type="submit" className="btn btn-primary">
+          <button type="submit" className="btn btn-primary">
             Ajouter
-            </button>
-            <button type="button" className="btn btn-secondary" onClick={handleCancel}>Annuler</button>
-        </div>      </form>
+          </button>
+          <button type="button" className="btn btn-secondary" onClick={handleCancel}>
+            Annuler
+          </button>
+        </div>
+      </form>
     </div>
   );
 }
diff --git a/src/components/StudentForm.jsx b/src/components/StudentForm.jsx
index 1332107..b6977f1 100644
--- a/src/components/StudentForm.jsx
+++ b/src/components/StudentForm.jsx
@@ -1,16 +1,18 @@
 import React, { useState } from "react";
-import { Navigate } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
 
 function StudentForm() {
   const [firstname, setFirstname] = useState("");
   const [lastname, setLastname] = useState("");
+  const navigate = useNavigate(); // Correct use of useNavigate
+
 
   const handleSubmit = (e) => {
     e.preventDefault();
 
     const newStudent = { firstname, lastname };
 
-    fetch("http://localhost:8080/api/students", {
+    fetch("http://localhost:8080/api/students/add", {
       method: "POST",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify(newStudent)
@@ -23,9 +25,9 @@ function StudentForm() {
       })
       .catch((err) => console.error("Erreur lors de l'ajout de l'étudiant :", err));
   };
-   // Handle cancel button
-   const handleCancel = () => {
-    Navigate("/etudiants"); // Redirect back to candidacy list
+   // Handle cancel button correctly
+    const handleCancel = () => {
+    navigate("/etudiants"); // Redirect back to student list
   };
 
   return (
diff --git a/src/components/UnivSupervisorForm.jsx b/src/components/UnivSupervisorForm.jsx
index 03c2fab..eb78757 100644
--- a/src/components/UnivSupervisorForm.jsx
+++ b/src/components/UnivSupervisorForm.jsx
@@ -9,7 +9,7 @@ function UnivSupervisorForm() {
 
     const newSupervisor = { name };
 
-    fetch("http://localhost:8080/api/univsupervisors", {
+    fetch("http://localhost:8080/api/univsupervisors/add", {
       method: "POST",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify(newSupervisor),
diff --git a/src/components/UpdateUnivSupervisorForm.jsx b/src/components/UpdateUnivSupervisorForm.jsx
index f86fb81..20df9cc 100644
--- a/src/components/UpdateUnivSupervisorForm.jsx
+++ b/src/components/UpdateUnivSupervisorForm.jsx
@@ -22,7 +22,7 @@ function UpdateUnivSupervisorForm() {
 
   const handleSubmit = (e) => {
     e.preventDefault();
-    fetch(`http://localhost:8080/api/univsupervisors/${id}`, {
+    fetch(`http://localhost:8080/api/univsupervisors/update/${id}`, {
       method: "PUT",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify(supervisor),
-- 
GitLab