diff --git a/src/App.js b/src/App.js index 299b45eb803e330557e233c1a746c653bdd32f76..311dfa22942594d3a662b34701b21c61799b32a4 100644 --- a/src/App.js +++ b/src/App.js @@ -22,6 +22,7 @@ import UpdateStudentForm from "./components/Students/UpdateStudentForm.jsx"; import UpdateUnivSupervisorForm from "./components/Supervisors/UpdateUnivSupervisorForm.jsx"; import Login from "./components/Login.jsx"; import Logout from "./components/Logout.jsx"; +import CandidacyFormPrerempli from "./components/Candidatures/CandidacyFormPrerempli.jsx"; function App() { return ( @@ -44,6 +45,7 @@ function App() { <Route path="/ajouter-etudiant" element={<StudentForm />} /> <Route path="/ajouter-candidature" element={<CandidacyForm />} /> <Route path="/ajouter-univsuperviseur" element={<UnivSupervisorForm />} /> + <Route path="/ajouter-ma-candidature" element={<CandidacyFormPrerempli />} /> {/* Routes for Updating */} <Route path="/modifier-candidature/:id" element={<UpdateCandidacyForm />} /> diff --git a/src/components/Candidatures/CandidacyFormPrerempli.jsx b/src/components/Candidatures/CandidacyFormPrerempli.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c0a2e2b42ef0132198d22a0b8381fe32564f10f0 --- /dev/null +++ b/src/components/Candidatures/CandidacyFormPrerempli.jsx @@ -0,0 +1,137 @@ +import React, { useState, useEffect } from "react"; +import { Navigate } from "react-router-dom"; + +const CandidacyFormPrerempli = () => { + const [students, setStudents] = useState([]); + const [stages, setStages] = useState([]); + const [supervisors, setSupervisors] = useState([]); + + // ✅ Initialise formData avec un studentId vide (sera mis à jour ensuite) + const [formData, setFormData] = useState({ + studentId: "", + stageId: "", + univSupervisorId: "", + }); + + /** 🔹 Charge le studentId à partir du localStorage */ + useEffect(() => { + const storedUser = JSON.parse(localStorage.getItem("user")); + if (storedUser && storedUser.username && storedUser.familyname) { + setFormData((prevFormData) => ({ + ...prevFormData, + studentId: storedUser.id || "", // ✅ Vérifie que l'ID existe + })); + } + }, []); + + /** 🔹 Charge les étudiants avec rôle ETUDIANT (si besoin) */ + useEffect(() => { + fetch("http://localhost:8080/api/students/with-role") + .then((res) => res.json()) + .then((data) => setStudents(data)) + .catch((err) => console.error("❌ Erreur lors du chargement des étudiants :", err)); + }, []); + + /** 🔹 Charge les stages */ + useEffect(() => { + fetch("http://localhost:8080/api/stages") + .then((res) => res.json()) + .then((data) => setStages(data)); + }, []); + + /** 🔹 Charge les superviseurs */ + useEffect(() => { + fetch("http://localhost:8080/api/univsupervisors") + .then((res) => res.json()) + .then((data) => setSupervisors(data)); + }, []); + + const handleChange = (e) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + + const candidacyData = { + student: { id: formData.studentId }, + stage: { id: formData.stageId }, + univSupervisor: { id: formData.univSupervisorId }, + }; + + console.log("📌 Sending Candidacy Data:", JSON.stringify(candidacyData, null, 2)); + + fetch("http://localhost:8080/api/candidacies/add", { + method: "POST", + headers: { "Content-Type": "application/json" }, + credentials: "include", + body: JSON.stringify(candidacyData), + }) + .then((res) => { + console.log("📌 Response status:", res.status); + return res.json(); + }) + .then((data) => { + console.log("✅ Candidacy added successfully:", data); + alert("Candidature ajoutée avec succès !"); + }) + .catch((err) => console.error("❌ Error:", err.message)); + }; + + return ( + <div className="container mt-4"> + <h2>Ajouter ma Candidature</h2> + <form onSubmit={handleSubmit}> + {/* ✅ Student (prérempli, non modifiable) */} + <div className="mb-3"> + <label className="form-label">Étudiant:</label> + <input + type="text" + className="form-control" + value={`${localStorage.getItem("username") || ""} ${localStorage.getItem("familyname") || ""}`} + disabled + /> + </div> + + {/* Select Stage */} + <div className="mb-3"> + <label className="form-label">Stage:</label> + <select className="form-control" name="stageId" value={formData.stageId} onChange={handleChange} required> + <option value="">Sélectionnez un stage</option> + {stages.map((stage) => ( + <option key={stage.id} value={stage.id}> + {stage.name} - {stage.description} + </option> + ))} + </select> + </div> + + {/* Select UnivSupervisor */} + <div className="mb-3"> + <label className="form-label">Superviseur Universitaire:</label> + <select + className="form-control" + name="univSupervisorId" + value={formData.univSupervisorId} + onChange={handleChange} + required + > + <option value="">Sélectionnez un superviseur</option> + {supervisors.map((supervisor) => ( + <option key={supervisor.id} value={supervisor.id}> + {supervisor.name} + </option> + ))} + </select> + </div> + + <div className="d-flex gap-2"> + <button type="submit" className="btn btn-primary">Ajouter Candidature</button> + <button type="button" className="btn btn-secondary" onClick={() => Navigate("/candidatures")}>Annuler</button> + </div> + </form> + </div> + ); +}; + +export default CandidacyFormPrerempli; diff --git a/src/components/Login.jsx b/src/components/Login.jsx index 39b181ec792dbf287d32aa47e1fbf1a436726848..190b514e9cc528c385c3a368e99b194f32c6e5a5 100644 --- a/src/components/Login.jsx +++ b/src/components/Login.jsx @@ -16,7 +16,7 @@ const Login = () => { const handleLogin = async (e) => { e.preventDefault(); - + try { const response = await fetch("http://localhost:8080/api/auth/login", { method: "POST", @@ -30,22 +30,31 @@ const Login = () => { throw new Error("Invalid credentials"); } - const data = await response.json(); // ✅ Parse JSON properly + const data = await response.json(); console.log("✅ Login successful!", data); - localStorage.setItem("token", "dummy-token"); // Store token (if applicable) - - // ✅ Store roles properly if they exist - if (data.roles) { - localStorage.setItem("roles", JSON.stringify(data.roles)); + // ✅ Assure-toi que l'ID est bien récupéré + if (!data.id) { + throw new Error("User ID is missing from response!"); } + // ✅ Stocke correctement les informations utilisateur + localStorage.setItem("token", "dummy-token"); + localStorage.setItem("roles", JSON.stringify(data.roles)); + localStorage.setItem("user", JSON.stringify({ + id: data.id, // Ajout de l'ID ici ✅ + username: data.username, + familyname: data.familyname + })); + navigate("/"); // Redirect after login } catch (error) { console.error("❌ Login failed:", error.message); setError("Invalid username or password"); } - }; +}; + + return ( diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 099bf49bf715365217dcc498e29e569469adac0f..4bfa1576a927a3186a17276d92394dd187f8d19c 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -3,9 +3,10 @@ import { Link } from "react-router-dom"; function Navbar() { const [roles, setRoles] = useState([]); + const [user, setUser] = useState({ username: "", familyname: "" }); useEffect(() => { - // ✅ Ensure roles are properly fetched + // ✅ Get roles from localStorage const storedRoles = localStorage.getItem("roles"); if (storedRoles) { try { @@ -14,8 +15,17 @@ function Navbar() { console.error("❌ Error parsing roles from localStorage", error); setRoles([]); // Fallback if parsing fails } - } else { - setRoles([]); // Ensure empty roles if none exist + } + + // ✅ Get user info (username & familyname) + const storedUser = localStorage.getItem("user"); + if (storedUser) { + try { + setUser(JSON.parse(storedUser)); + } catch (error) { + console.error("❌ Error parsing user data from localStorage", error); + setUser({ username: "", familyname: "" }); // Fallback if parsing fails + } } }, []); @@ -40,6 +50,14 @@ function Navbar() { <div className="collapse navbar-collapse" id="navbarNav"> <ul className="navbar-nav ms-auto"> + + {/* ✅ Display Logged-in User Info */} + {user.username && ( + <li className="nav-item"> + <span className="nav-link">👤 {user.username} {user.familyname}</span> + </li> + )} + {/* 📚 Stages */} {(hasRole("ROLE_ETUDIANT") || hasRole("ROLE_ENTREPRISE") || hasRole("ROLE_SUPERVISEUR") || hasRole("ROLE_ADMIN")) && ( <li className="nav-item dropdown"> @@ -104,6 +122,8 @@ function Navbar() { )} {/* ALL Étudiants CAN apply */} <li><Link className="dropdown-item" to="/ajouter-candidature">➕ Ajouter une Candidature</Link></li> + {/* ALL Étudiants CAN apply */} + <li><Link className="dropdown-item" to="/ajouter-ma-candidature">➕ Ajouter ma candidature</Link></li> </ul> </li> )}