diff --git a/package-lock.json b/package-lock.json index b9258ce766250cc7253b5a4de872a4d861268e34..ace88a7f9caaf0c7c19c5a4ba649b3d338e90491 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "gestion-stages-front", "version": "0.1.0", "dependencies": { + "@fortawesome/fontawesome-free": "^6.7.2", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", @@ -2314,6 +2315,14 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", + "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==", + "engines": { + "node": ">=6" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -17775,6 +17784,11 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==" }, + "@fortawesome/fontawesome-free": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", + "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==" + }, "@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", diff --git a/package.json b/package.json index 62e6ee271279835b4d8359636bc2f4b07c8f3a24..56b157fbc996fa7042a1b0add313f58f3a64808e 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-free": "^6.7.2", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", diff --git a/src/components/CandidacyList.jsx b/src/components/CandidacyList.jsx index 4b2b25c1292535d08e0a8e66189b8fb5373d40f2..b360b224a1d869a37c8c4f857fa86741871dc58b 100644 --- a/src/components/CandidacyList.jsx +++ b/src/components/CandidacyList.jsx @@ -1,40 +1,40 @@ -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect } from "react"; -const CandidacyList = () => { +function CandidacyList() { const [candidacies, setCandidacies] = useState([]); - const [error, setError] = useState(null); useEffect(() => { fetch("http://localhost:8080/api/candidacies") - .then((response) => { - if (!response.ok) { - throw new Error("Erreur lors de la récupération des candidatures !"); - } - return response.json(); - }) + .then((response) => response.json()) .then((data) => setCandidacies(data)) - .catch((err) => setError(err.message)); + .catch((error) => console.error("Error fetching candidacies:", error)); }, []); return ( - <div> - <h2>Liste des Candidatures</h2> - {error && <p style={{ color: "red" }}>{error}</p>} - <ul> - {candidacies.length > 0 ? ( - candidacies.map((candidacy) => ( - <li key={candidacy.id}> - Étudiant: {candidacy.student.firstname} {candidacy.student.lastname} - - Stage: {candidacy.stage.name} - - Superviseur: {candidacy.univSupervisor.name} - </li> - )) - ) : ( - <p>Aucune candidature trouvée.</p> - )} - </ul> + <div className="container mt-4"> + <h2 className="mb-4">Liste des Candidatures</h2> + <table className="table table-striped table-hover"> + <thead className="table-warning"> + <tr> + <th>ID</th> + <th>Étudiant</th> + <th>Stage</th> + <th>Superviseur Universitaire</th> + </tr> + </thead> + <tbody> + {candidacies.map((candidacy) => ( + <tr key={candidacy.id}> + <td>{candidacy.id}</td> + <td>{candidacy.student?.firstname} {candidacy.student?.lastname}</td> + <td>{candidacy.stage?.name}</td> + <td>{candidacy.univSupervisor?.name}</td> + </tr> + ))} + </tbody> + </table> </div> ); -}; +} export default CandidacyList; diff --git a/src/components/EnterpriseList.jsx b/src/components/EnterpriseList.jsx index f2291b3f77694d5e706a56076d6b73a7dab028e4..d5b393c18132810a297dadd3c20be25a22f46fc2 100644 --- a/src/components/EnterpriseList.jsx +++ b/src/components/EnterpriseList.jsx @@ -1,38 +1,38 @@ -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect } from "react"; -const EnterpriseList = () => { +function EnterpriseList() { const [enterprises, setEnterprises] = useState([]); - const [error, setError] = useState(null); useEffect(() => { fetch("http://localhost:8080/api/enterprises") - .then((response) => { - if (!response.ok) { - throw new Error("Erreur lors de la récupération des entreprises !"); - } - return response.json(); - }) + .then((response) => response.json()) .then((data) => setEnterprises(data)) - .catch((err) => setError(err.message)); + .catch((error) => console.error("Error fetching enterprises:", error)); }, []); return ( - <div> - <h2>Liste des Entreprises</h2> - {error && <p style={{ color: "red" }}>{error}</p>} - <ul> - {enterprises.length > 0 ? ( - enterprises.map((enterprise) => ( - <li key={enterprise.id}> - <strong>{enterprise.name}</strong> - {enterprise.address} - </li> - )) - ) : ( - <p>Aucune entreprise trouvée.</p> - )} - </ul> + <div className="container mt-4"> + <h2 className="mb-4">Liste des Entreprises</h2> + <table className="table table-striped table-hover"> + <thead className="table-primary"> + <tr> + <th>ID</th> + <th>Nom</th> + <th>Adresse</th> + </tr> + </thead> + <tbody> + {enterprises.map((enterprise) => ( + <tr key={enterprise.id}> + <td>{enterprise.id}</td> + <td>{enterprise.name}</td> + <td>{enterprise.address}</td> + </tr> + ))} + </tbody> + </table> </div> ); -}; +} export default EnterpriseList; diff --git a/src/components/Navbar.css b/src/components/Navbar.css new file mode 100644 index 0000000000000000000000000000000000000000..936953c34825401b9369fe9767335bb98b20f902 --- /dev/null +++ b/src/components/Navbar.css @@ -0,0 +1,39 @@ +/* Navbar styling */ +.navbar { + padding: 12px 20px; + font-size: 16px; + background: #ffffff; + border-bottom: 2px solid #007bff; +} + +/* Brand */ +.navbar-brand { + font-size: 20px; + font-weight: bold; + color: #007bff !important; +} + +/* Navbar Links */ +.navbar-nav .nav-link { + color: #333 !important; + font-weight: 500; + padding: 10px 15px; + transition: all 0.3s ease-in-out; +} + +/* Highlight the active link */ +.navbar-nav .nav-link:hover, +.navbar-nav .nav-link.active { + color: #007bff !important; + border-bottom: 2px solid #007bff; +} + +/* Responsive styles */ +@media (max-width: 992px) { + .navbar-nav { + text-align: center; + } + .navbar-nav .nav-item { + margin-bottom: 5px; + } +} diff --git a/src/components/Navbar.js b/src/components/Navbar.js deleted file mode 100644 index 276436b47fd05092335a011ac12c94c6c0cfc468..0000000000000000000000000000000000000000 --- a/src/components/Navbar.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; - -function Navbar() { - return ( - <nav className="navbar navbar-expand-lg navbar-dark bg-dark"> - <div className="container"> - <Link className="navbar-brand" to="/">Gestion Stages</Link> - <button - className="navbar-toggler" - type="button" - data-bs-toggle="collapse" - data-bs-target="#navbarNav" - aria-controls="navbarNav" - aria-expanded="false" - aria-label="Toggle navigation" - > - <span className="navbar-toggler-icon"></span> - </button> - <div className="collapse navbar-collapse" id="navbarNav"> - <ul className="navbar-nav"> - <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> - </li> - <li className="nav-item"> - <Link className="nav-link" to="/entreprises">Entreprises</Link> - </li> - <li className="nav-item"> - <Link className="nav-link" to="/candidatures">Candidatures</Link> - </li> - <li className="nav-item"> - <Link className="nav-link" to="/superviseurs">Superviseurs</Link> - </li> - </ul> - </div> - </div> - </nav> - ); -} - -export default Navbar; diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx new file mode 100644 index 0000000000000000000000000000000000000000..86ce3bea11a9b8b47e9fdf8f79b81595d888a569 --- /dev/null +++ b/src/components/Navbar.jsx @@ -0,0 +1,83 @@ +import React from "react"; +import { Link, useLocation } from "react-router-dom"; +import "./Navbar.css"; // Optional: Add this for extra styling + +function Navbar() { + const location = useLocation(); + + return ( + <nav className="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm"> + <div className="container"> + <Link className="navbar-brand fw-bold" to="/"> + <i className="fas fa-graduation-cap"></i> Gestion Stages + </Link> + <button + className="navbar-toggler" + type="button" + data-bs-toggle="collapse" + data-bs-target="#navbarNav" + aria-controls="navbarNav" + aria-expanded="false" + aria-label="Toggle navigation" + > + <span className="navbar-toggler-icon"></span> + </button> + + <div className="collapse navbar-collapse" id="navbarNav"> + <ul className="navbar-nav ms-auto"> + <li className="nav-item"> + <Link + className={`nav-link ${location.pathname === "/login" ? "active" : ""}`} + to="/login" + > + <i className="fas fa-sign-in-alt"></i> Login + </Link> + </li> + <li className="nav-item"> + <Link + className={`nav-link ${location.pathname === "/stages" ? "active" : ""}`} + to="/stages" + > + <i className="fas fa-book"></i> Stages + </Link> + </li> + <li className="nav-item"> + <Link + className={`nav-link ${location.pathname === "/etudiants" ? "active" : ""}`} + to="/etudiants" + > + <i className="fas fa-user-graduate"></i> Étudiants + </Link> + </li> + <li className="nav-item"> + <Link + className={`nav-link ${location.pathname === "/entreprises" ? "active" : ""}`} + to="/entreprises" + > + <i className="fas fa-building"></i> Entreprises + </Link> + </li> + <li className="nav-item"> + <Link + className={`nav-link ${location.pathname === "/candidatures" ? "active" : ""}`} + to="/candidatures" + > + <i className="fas fa-file-alt"></i> Candidatures + </Link> + </li> + <li className="nav-item"> + <Link + className={`nav-link ${location.pathname === "/superviseurs" ? "active" : ""}`} + to="/superviseurs" + > + <i className="fas fa-chalkboard-teacher"></i> Superviseurs + </Link> + </li> + </ul> + </div> + </div> + </nav> + ); +} + +export default Navbar; diff --git a/src/components/StageList.jsx b/src/components/StageList.jsx index 44167dffb0ab6317370aac95084a078352d3ee6a..f1bcb1bf16fc14ab04b518a68f88c59b36c62bff 100644 --- a/src/components/StageList.jsx +++ b/src/components/StageList.jsx @@ -1,39 +1,40 @@ -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect } from "react"; -const StageList = () => { - const [stages, setStages] = useState([]); // État pour stocker les stages - const [error, setError] = useState(null); // État pour gérer les erreurs +function StageList() { + const [stages, setStages] = useState([]); useEffect(() => { - fetch("http://localhost:8080/api/stages") // Appel API - .then((response) => { - if (!response.ok) { - throw new Error("Erreur lors de la récupération des stages !"); - } - return response.json(); - }) - .then((data) => setStages(data)) // Mettre à jour l'état avec les données reçues - .catch((err) => setError(err.message)); // Gestion des erreurs - }, []); // Le tableau vide signifie que ça s'exécute une seule fois au chargement + fetch("http://localhost:8080/api/stages") + .then((response) => response.json()) + .then((data) => setStages(data)) + .catch((error) => console.error("Error fetching stages:", error)); + }, []); return ( - <div> - <h2>Liste des Stages</h2> - {error && <p style={{ color: "red" }}>{error}</p>} {/* Affichage des erreurs */} - - <ul> - {stages.length > 0 ? ( - stages.map((stage) => ( - <li key={stage.id}> - <strong>{stage.name}</strong> - {stage.description} - </li> - )) - ) : ( - <p>Aucun stage trouvé.</p> - )} - </ul> + <div className="container mt-4"> + <h2 className="mb-4">Liste des Stages</h2> + <table className="table table-striped table-hover"> + <thead className="table-success"> + <tr> + <th>ID</th> + <th>Nom</th> + <th>Description</th> + <th>Entreprise</th> + </tr> + </thead> + <tbody> + {stages.map((stage) => ( + <tr key={stage.id}> + <td>{stage.id}</td> + <td>{stage.name}</td> + <td>{stage.description}</td> + <td>{stage.enterprise?.name}</td> + </tr> + ))} + </tbody> + </table> </div> ); -}; +} export default StageList; diff --git a/src/components/StudentList.jsx b/src/components/StudentList.jsx index b55cae112b4cab398e6422ef44a82b8f70eea315..359b0d1db2be44436f7c9ce30630b9db30788ec5 100644 --- a/src/components/StudentList.jsx +++ b/src/components/StudentList.jsx @@ -1,38 +1,38 @@ -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect } from "react"; -const StudentList = () => { +function StudentList() { const [students, setStudents] = useState([]); - const [error, setError] = useState(null); useEffect(() => { fetch("http://localhost:8080/api/students") - .then((response) => { - if (!response.ok) { - throw new Error("Erreur lors de la récupération des étudiants !"); - } - return response.json(); - }) + .then((response) => response.json()) .then((data) => setStudents(data)) - .catch((err) => setError(err.message)); + .catch((error) => console.error("Error fetching students:", error)); }, []); return ( - <div> - <h2>Liste des Étudiants</h2> - {error && <p style={{ color: "red" }}>{error}</p>} - <ul> - {students.length > 0 ? ( - students.map((student) => ( - <li key={student.id}> - <strong>{student.firstname} {student.lastname}</strong> - </li> - )) - ) : ( - <p>Aucun étudiant trouvé.</p> - )} - </ul> + <div className="container mt-4"> + <h2 className="mb-4">Liste des Étudiants</h2> + <table className="table table-striped table-hover"> + <thead className="table-info"> + <tr> + <th>ID</th> + <th>Prénom</th> + <th>Nom</th> + </tr> + </thead> + <tbody> + {students.map((student) => ( + <tr key={student.id}> + <td>{student.id}</td> + <td>{student.firstname}</td> + <td>{student.lastname}</td> + </tr> + ))} + </tbody> + </table> </div> ); -}; +} export default StudentList; diff --git a/src/components/UnivSupervisorList.jsx b/src/components/UnivSupervisorList.jsx index 21bc4a840f329ddefaab5551501e4240b907ea33..86aeb5f06201882539a6ab77461f378f536dc110 100644 --- a/src/components/UnivSupervisorList.jsx +++ b/src/components/UnivSupervisorList.jsx @@ -1,38 +1,36 @@ -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect } from "react"; -const UnivSupervisorList = () => { - const [supervisors, setSupervisors] = useState([]); - const [error, setError] = useState(null); +function UnivSupervisorList() { + const [univSupervisors, setUnivSupervisors] = useState([]); useEffect(() => { - fetch("http://localhost:8080/api/univsupervisors") - .then((response) => { - if (!response.ok) { - throw new Error("Erreur lors de la récupération des superviseurs !"); - } - return response.json(); - }) - .then((data) => setSupervisors(data)) - .catch((err) => setError(err.message)); + fetch("http://localhost:8080/api/univSupervisors") + .then((response) => response.json()) + .then((data) => setUnivSupervisors(data)) + .catch((error) => console.error("Error fetching university supervisors:", error)); }, []); return ( - <div> - <h2>Liste des Superviseurs</h2> - {error && <p style={{ color: "red" }}>{error}</p>} - <ul> - {supervisors.length > 0 ? ( - supervisors.map((supervisor) => ( - <li key={supervisor.id}> - <strong>{supervisor.name}</strong> - </li> - )) - ) : ( - <p>Aucun superviseur trouvé.</p> - )} - </ul> + <div className="container mt-4"> + <h2 className="mb-4">Liste des Superviseurs Universitaires</h2> + <table className="table table-striped table-hover"> + <thead className="table-danger"> + <tr> + <th>ID</th> + <th>Nom du Superviseur Universitaire</th> + </tr> + </thead> + <tbody> + {univSupervisors.map((supervisor) => ( + <tr key={supervisor.id}> + <td>{supervisor.id}</td> + <td>{supervisor.name}</td> + </tr> + ))} + </tbody> + </table> </div> ); -}; +} export default UnivSupervisorList; diff --git a/src/index.js b/src/index.js index d563c0fb10ba0e42724b21286eb546ee4e5734fc..e4ae0fc301bbe4f7b93ee00fff9daddf418eb21d 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,10 @@ import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; +import "@fortawesome/fontawesome-free/css/all.min.css"; +import "bootstrap/dist/css/bootstrap.min.css"; +import "bootstrap/dist/js/bootstrap.bundle.min"; + const root = ReactDOM.createRoot(document.getElementById('root')); root.render(