Merge branch 'main' of https://github.com/Charles40130/Projet-Dev-Web-Ing1 into Ruben
This commit is contained in:
commit
db3fe4d167
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"liveServer.settings.port": 8081,
|
"liveServer.settings.port": 8081,
|
||||||
"java.configuration.updateBuildConfiguration": "interactive"
|
"java.configuration.updateBuildConfiguration": "automatic"
|
||||||
}
|
}
|
||||||
@ -88,10 +88,10 @@
|
|||||||
<version>0.9.0</version>
|
<version>0.9.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.vertx</groupId>
|
<groupId>io.vertx</groupId>
|
||||||
<artifactId>vertx-auth-jwt</artifactId>
|
<artifactId>vertx-auth-jwt</artifactId>
|
||||||
<version>4.5.13</version>
|
<version>4.5.13</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import io.vertx.core.json.JsonObject;
|
|||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import at.favre.lib.crypto.bcrypt.BCrypt;
|
import at.favre.lib.crypto.bcrypt.BCrypt;
|
||||||
import io.vertx.ext.auth.jwt.JWTAuth;
|
import io.vertx.ext.auth.jwt.JWTAuth;
|
||||||
import com.example.starter.auth.JwtAuthProvider;
|
|
||||||
import io.vertx.sqlclient.Tuple;
|
import io.vertx.sqlclient.Tuple;
|
||||||
|
|
||||||
public class AuthHandler {
|
public class AuthHandler {
|
||||||
@ -78,7 +77,7 @@ public class AuthHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("SELECT password FROM users WHERE email = ?")
|
.preparedQuery("SELECT password,points FROM users WHERE email = ?")
|
||||||
.execute(Tuple.of(email))
|
.execute(Tuple.of(email))
|
||||||
.onSuccess(result -> {
|
.onSuccess(result -> {
|
||||||
if (result.rowCount() == 0) {
|
if (result.rowCount() == 0) {
|
||||||
@ -89,10 +88,20 @@ public class AuthHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String storedHashedPassword = result.iterator().next().getString("password");
|
String storedHashedPassword = result.iterator().next().getString("password");
|
||||||
|
Integer nbPointsUser = result.iterator().next().getInteger("points");
|
||||||
|
|
||||||
BCrypt.Result verification = BCrypt.verifyer().verify(password.toCharArray(), storedHashedPassword);
|
BCrypt.Result verification = BCrypt.verifyer().verify(password.toCharArray(), storedHashedPassword);
|
||||||
|
|
||||||
if (verification.verified) {
|
if (verification.verified) {
|
||||||
JsonObject claims = new JsonObject().put("sub", email).put("role", "user");
|
JsonObject claims = new JsonObject().put("sub", email);
|
||||||
|
if(nbPointsUser<=30){
|
||||||
|
claims.put("role", "user");
|
||||||
|
}else if(nbPointsUser<=60){
|
||||||
|
claims.put("role", "complexe");
|
||||||
|
}else if(nbPointsUser>=100){
|
||||||
|
claims.put("role", "admin");
|
||||||
|
}
|
||||||
|
|
||||||
String token = jwtAuth.generateToken(claims);
|
String token = jwtAuth.generateToken(claims);
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(200)
|
.setStatusCode(200)
|
||||||
|
|||||||
@ -3,8 +3,7 @@ package com.example.starter;
|
|||||||
import io.vertx.core.Vertx;
|
import io.vertx.core.Vertx;
|
||||||
import io.vertx.jdbcclient.JDBCConnectOptions;
|
import io.vertx.jdbcclient.JDBCConnectOptions;
|
||||||
import io.vertx.jdbcclient.JDBCPool;
|
import io.vertx.jdbcclient.JDBCPool;
|
||||||
import io.vertx.ext.auth.jwt.JWTAuth;
|
|
||||||
import io.vertx.ext.auth.jwt.JWTAuthOptions;
|
|
||||||
import io.vertx.sqlclient.PoolOptions;
|
import io.vertx.sqlclient.PoolOptions;
|
||||||
|
|
||||||
public class DatabaseService {
|
public class DatabaseService {
|
||||||
@ -13,7 +12,7 @@ public class DatabaseService {
|
|||||||
public DatabaseService(Vertx vertx) {
|
public DatabaseService(Vertx vertx) {
|
||||||
pool = JDBCPool.pool(vertx,
|
pool = JDBCPool.pool(vertx,
|
||||||
new JDBCConnectOptions()
|
new JDBCConnectOptions()
|
||||||
.setJdbcUrl("jdbc:postgresql://localhost:5432/users?useUnicode=true&characterEncoding=UTF-8") //Url de la bdd
|
.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=UTF-8") //Url de la bdd
|
||||||
.setUser("postgres") // Nom d'utilisateur PostgreSQL
|
.setUser("postgres") // Nom d'utilisateur PostgreSQL
|
||||||
.setPassword("admin"), // Mot de passe PostgreSQL
|
.setPassword("admin"), // Mot de passe PostgreSQL
|
||||||
new PoolOptions()
|
new PoolOptions()
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
package com.example.starter.auth;
|
package com.example.starter;
|
||||||
|
|
||||||
import io.vertx.core.Vertx;
|
import io.vertx.core.Vertx;
|
||||||
import io.vertx.ext.auth.jwt.JWTAuth;
|
import io.vertx.ext.auth.jwt.JWTAuth;
|
||||||
import io.vertx.ext.auth.jwt.JWTAuthOptions;
|
import io.vertx.ext.auth.jwt.JWTAuthOptions;
|
||||||
import io.vertx.ext.auth.KeyStoreOptions;
|
import io.vertx.ext.auth.KeyStoreOptions;
|
||||||
import com.example.starter.auth.JwtAuthProvider;
|
import com.example.starter.JwtAuthProvider;
|
||||||
|
|
||||||
|
|
||||||
public class JwtAuthProvider {
|
public class JwtAuthProvider {
|
||||||
|
|||||||
@ -7,10 +7,8 @@ import io.vertx.ext.web.Router;
|
|||||||
import io.vertx.ext.web.handler.BodyHandler;
|
import io.vertx.ext.web.handler.BodyHandler;
|
||||||
import io.vertx.ext.web.handler.CorsHandler;
|
import io.vertx.ext.web.handler.CorsHandler;
|
||||||
import io.vertx.ext.auth.jwt.JWTAuth;
|
import io.vertx.ext.auth.jwt.JWTAuth;
|
||||||
import com.example.starter.auth.JwtAuthProvider;
|
|
||||||
import io.vertx.ext.web.handler.JWTAuthHandler;
|
import io.vertx.ext.web.handler.JWTAuthHandler;
|
||||||
|
|
||||||
|
|
||||||
public class MainVerticle extends AbstractVerticle {
|
public class MainVerticle extends AbstractVerticle {
|
||||||
private DatabaseService databaseService;
|
private DatabaseService databaseService;
|
||||||
private Router router;
|
private Router router;
|
||||||
@ -18,32 +16,32 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
@Override
|
@Override
|
||||||
public void start(Promise<Void> startPromise) throws Exception {
|
public void start(Promise<Void> startPromise) throws Exception {
|
||||||
databaseService = new DatabaseService(vertx);
|
databaseService = new DatabaseService(vertx);
|
||||||
|
|
||||||
// Initialisation du fournisseur JWT
|
// Initialisation du fournisseur JWT
|
||||||
JWTAuth jwtAuth = JwtAuthProvider.createJwtAuth(vertx);
|
JWTAuth jwtAuth = JwtAuthProvider.createJwtAuth(vertx);
|
||||||
|
|
||||||
|
|
||||||
// Initialisation du routeur
|
// Initialisation du routeur
|
||||||
router = Router.router(vertx);
|
router = Router.router(vertx);
|
||||||
router.route().handler(BodyHandler.create());
|
router.route().handler(BodyHandler.create());
|
||||||
router.route().handler(CorsHandler.create()
|
router.route().handler(CorsHandler.create()
|
||||||
.addOrigin("*")
|
.addOrigin("*")
|
||||||
.allowedMethod(HttpMethod.GET)
|
.allowedMethod(HttpMethod.GET)
|
||||||
.allowedMethod(HttpMethod.POST)
|
.allowedMethod(HttpMethod.POST)
|
||||||
.allowedHeader("Content-Type")
|
.allowedHeader("Content-Type")
|
||||||
.allowedHeader("Authorization"));
|
.allowedHeader("Authorization"));
|
||||||
|
|
||||||
// Protéger toutes les routes commençant par "/api/"
|
// Protéger toutes les routes commençant par "/api/"
|
||||||
router.route("/api/*").handler(JWTAuthHandler.create(jwtAuth));
|
router.route("/api/*").handler(JWTAuthHandler.create(jwtAuth));
|
||||||
|
|
||||||
|
|
||||||
// Initialisation des handlers de requêtes
|
// Initialisation des handlers de requêtes
|
||||||
QueryObjects queryObjects = new QueryObjects(databaseService);
|
QueryObjects queryObjects = new QueryObjects(databaseService);
|
||||||
QueryWeatherData queryWeather = new QueryWeatherData(databaseService);
|
QueryWeatherData queryWeather = new QueryWeatherData(databaseService);
|
||||||
SetObjects setObjects = new SetObjects(databaseService);
|
SetObjects setObjects = new SetObjects(databaseService);
|
||||||
SetWeatherData setWeatherData = new SetWeatherData(databaseService);
|
SetWeatherData setWeatherData = new SetWeatherData(databaseService);
|
||||||
AuthHandler authHandler = new AuthHandler(databaseService, jwtAuth);
|
AuthHandler authHandler = new AuthHandler(databaseService, jwtAuth);
|
||||||
|
QueryUsers queryUsers = new QueryUsers(databaseService);
|
||||||
|
SetUser setUser = new SetUser(databaseService);
|
||||||
|
|
||||||
// Déclaration des routes
|
// Déclaration des routes
|
||||||
router.get("/objets").handler(queryObjects::getObjects);
|
router.get("/objets").handler(queryObjects::getObjects);
|
||||||
router.get("/objet").handler(queryObjects::getParticularObject);
|
router.get("/objet").handler(queryObjects::getParticularObject);
|
||||||
@ -53,22 +51,24 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
router.post("/addObject").handler(setObjects::newObject);
|
router.post("/addObject").handler(setObjects::newObject);
|
||||||
router.get("/getRange").handler(queryWeather::getRangeData);
|
router.get("/getRange").handler(queryWeather::getRangeData);
|
||||||
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
|
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
|
||||||
|
router.post("/deleteObject").handler(setObjects::deleteObject);
|
||||||
|
router.get("/users").handler(queryUsers::getUsers);
|
||||||
|
router.post("/setUserPoints").handler(setUser::setUserPoints);
|
||||||
// Routes d'authentification
|
// Routes d'authentification
|
||||||
router.post("/signup").handler(authHandler::handleSignup);
|
router.post("/signup").handler(authHandler::handleSignup);
|
||||||
router.post("/login").handler(authHandler::handleLogin);
|
router.post("/login").handler(authHandler::handleLogin);
|
||||||
|
|
||||||
// Création du serveur HTTP
|
// Création du serveur HTTP
|
||||||
vertx.createHttpServer()
|
vertx.createHttpServer()
|
||||||
.requestHandler(router)
|
.requestHandler(router)
|
||||||
.listen(8888)
|
.listen(8888)
|
||||||
.onSuccess(server -> {
|
.onSuccess(server -> {
|
||||||
System.out.println("HTTP server started on port " + server.actualPort());
|
System.out.println("HTTP server started on port " + server.actualPort());
|
||||||
startPromise.complete();
|
startPromise.complete();
|
||||||
})
|
})
|
||||||
.onFailure(throwable -> {
|
.onFailure(throwable -> {
|
||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
startPromise.fail(throwable);
|
startPromise.fail(throwable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,7 +78,8 @@ public class QueryObjects {
|
|||||||
.put("last_update", row.getLocalDateTime("last_update").format(formatter))
|
.put("last_update", row.getLocalDateTime("last_update").format(formatter))
|
||||||
.put("status", row.getString("status"))
|
.put("status", row.getString("status"))
|
||||||
.put("batterie",row.getInteger("batterie"))
|
.put("batterie",row.getInteger("batterie"))
|
||||||
.put("type_batterie",row.getString("type_batterie"));
|
.put("type_batterie",row.getString("type_batterie"))
|
||||||
|
.put("proprio",row.getString("proprio"));
|
||||||
objects.add(object);
|
objects.add(object);
|
||||||
}
|
}
|
||||||
return objects;
|
return objects;
|
||||||
|
|||||||
51
Back-end/src/main/java/com/example/starter/QueryUsers.java
Normal file
51
Back-end/src/main/java/com/example/starter/QueryUsers.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package com.example.starter;
|
||||||
|
|
||||||
|
import io.vertx.core.json.JsonArray;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import io.vertx.sqlclient.Row;
|
||||||
|
|
||||||
|
public class QueryUsers {
|
||||||
|
private DatabaseService databaseService;
|
||||||
|
|
||||||
|
public QueryUsers(DatabaseService dtbS) {
|
||||||
|
this.databaseService = dtbS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getUsers(RoutingContext context) {
|
||||||
|
databaseService.pool
|
||||||
|
.query("SELECT * FROM users;")
|
||||||
|
.execute()
|
||||||
|
.onFailure(e -> {
|
||||||
|
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(500)
|
||||||
|
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
|
||||||
|
})
|
||||||
|
.onSuccess(rows -> {
|
||||||
|
JsonArray users = new JsonArray();
|
||||||
|
for (Row row : rows) {
|
||||||
|
int points=row.getInteger("points");
|
||||||
|
JsonObject user = new JsonObject()
|
||||||
|
.put("id", row.getInteger("id"))
|
||||||
|
.put("name", row.getString("name"))
|
||||||
|
.put("surname", row.getString("surname"))
|
||||||
|
.put("email", row.getString("email"))
|
||||||
|
.put("gender", row.getString("gender"))
|
||||||
|
.put("points",points);
|
||||||
|
if(points<=30){
|
||||||
|
user.put("role", "user");
|
||||||
|
}else if(points<=60){
|
||||||
|
user.put("role", "complexe");
|
||||||
|
}else if(points>=100){
|
||||||
|
user.put("role", "admin");
|
||||||
|
}
|
||||||
|
users.add(user);
|
||||||
|
}
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json; charset=UTF-8")
|
||||||
|
.end(users.encode());
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -48,7 +48,38 @@ public class SetObjects {
|
|||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public void deleteObject(RoutingContext context){
|
||||||
|
JsonObject body = context.body().asJsonObject();
|
||||||
|
if(body== null){
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(400)
|
||||||
|
.end(new JsonObject().put("error","Corps de la requête manquant").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String id = body.getString("id");
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery("DELETE FROM weather_objects WHERE id=?")
|
||||||
|
.execute(Tuple.of(Integer.parseInt(id)))
|
||||||
|
.onFailure(e->{
|
||||||
|
System.err.println("Erreur de récupération de la BDD :"+e.getMessage());
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(500)
|
||||||
|
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
|
||||||
|
})
|
||||||
|
.onSuccess(rows -> {
|
||||||
|
if(rows.rowCount()==0){
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(404)
|
||||||
|
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type","application/json: charset=UTF-8")
|
||||||
|
.end(new JsonObject().put("success", "L'objet à bien été supprimé").encode());
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
public void newObject(RoutingContext context){
|
public void newObject(RoutingContext context){
|
||||||
JsonObject body = context.body().asJsonObject();
|
JsonObject body = context.body().asJsonObject();
|
||||||
if(body== null){
|
if(body== null){
|
||||||
@ -62,9 +93,11 @@ public class SetObjects {
|
|||||||
String type = body.getString("type");
|
String type = body.getString("type");
|
||||||
String location = body.getString("location");
|
String location = body.getString("location");
|
||||||
String status = body.getString("status");
|
String status = body.getString("status");
|
||||||
|
String batterieType = body.getString("batterieType");
|
||||||
|
String proprio = body.getString("proprio");
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("INSERT INTO weather_objects (name,description,type,location,status) VALUES (?,?,?,?,?)")
|
.preparedQuery("INSERT INTO weather_objects (name,description,type,location,status,type_batterie,proprio) VALUES (?,?,?,?,?,?,?)")
|
||||||
.execute(Tuple.of(name,description,type,location,status))
|
.execute(Tuple.of(name,description,type,location,status,batterieType,proprio))
|
||||||
.onFailure(e->{
|
.onFailure(e->{
|
||||||
System.err.println("Erreur de récupération de la BDD :"+e.getMessage());
|
System.err.println("Erreur de récupération de la BDD :"+e.getMessage());
|
||||||
context.response()
|
context.response()
|
||||||
|
|||||||
48
Back-end/src/main/java/com/example/starter/SetUser.java
Normal file
48
Back-end/src/main/java/com/example/starter/SetUser.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package com.example.starter;
|
||||||
|
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import io.vertx.sqlclient.Tuple;
|
||||||
|
|
||||||
|
public class SetUser {
|
||||||
|
private DatabaseService databaseService;
|
||||||
|
|
||||||
|
public SetUser(DatabaseService ddbs) {
|
||||||
|
this.databaseService = ddbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserPoints(RoutingContext context) {
|
||||||
|
JsonObject body = context.body().asJsonObject();
|
||||||
|
if (body == null) {
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(400)
|
||||||
|
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Integer id = body.getInteger("id");
|
||||||
|
Integer points = body.getInteger("points");
|
||||||
|
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery(
|
||||||
|
"UPDATE users SET points=? WHERE id=?")
|
||||||
|
.execute(Tuple.of(points,id))
|
||||||
|
.onFailure(e -> {
|
||||||
|
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(500)
|
||||||
|
.end(new JsonObject().put("Erreur", "Erreur de récupération de la BDD").encode());
|
||||||
|
})
|
||||||
|
.onSuccess(rows -> {
|
||||||
|
if (rows.rowCount() == 0) {
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(404)
|
||||||
|
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
|
.end(new JsonObject().put("success", "Les points de l'utilisateur ont bien été mis à jour").encode());
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="icon" href="./src/img/cloud-alert.svg"/>
|
<link rel="icon" href="./src/img/cloud-sun-rain.svg"/>
|
||||||
<title>Projet Dev Web</title>
|
<title>Projet Dev Web</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@ -18,8 +18,6 @@ import AdminObjet from "./pages/Admin/AdminObjet.jsx";
|
|||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
{" "}
|
|
||||||
{/* Enveloppe l'application avec AuthProvider */}
|
|
||||||
<Router>
|
<Router>
|
||||||
<div>
|
<div>
|
||||||
<Header />
|
<Header />
|
||||||
|
|||||||
257
Front-end/src/components/FormNewObject.jsx
Normal file
257
Front-end/src/components/FormNewObject.jsx
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { BadgePlus } from "lucide-react";
|
||||||
|
import axios from "axios";
|
||||||
|
import { API_BASE_URL } from "../config";
|
||||||
|
|
||||||
|
function FormNewObject({ isAdmin }) {
|
||||||
|
const [description, setDescription] = useState("");
|
||||||
|
const [type, setType] = useState("");
|
||||||
|
const [location, setLocalisation] = useState("");
|
||||||
|
const [proprio,setProprio] = useState("");
|
||||||
|
const [batterieType,setBatterieType] = useState("");
|
||||||
|
/*TODO*/
|
||||||
|
/*Definir proprio avec le nom de l'user qui ajoute*/
|
||||||
|
const [status, setStatus] = useState("active");
|
||||||
|
const [nom, setNom] = useState("");
|
||||||
|
const [Response, setResponse] = useState(null);
|
||||||
|
const [isActive, setActive] = useState(true);
|
||||||
|
const [verif, setVerif] = useState(false);
|
||||||
|
const [enregistre, setEnregistre] = useState(false);
|
||||||
|
const [messRequete, setMessRequete] = useState("");
|
||||||
|
function handleSubmit(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (verif) {
|
||||||
|
console.log("Envoi requete");
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/addObject`, {
|
||||||
|
nom,
|
||||||
|
description,
|
||||||
|
type,
|
||||||
|
location,
|
||||||
|
status,
|
||||||
|
batterieType,
|
||||||
|
proprio
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setMessRequete("Votre objet à bien été enregistré !");
|
||||||
|
setEnregistre(true);
|
||||||
|
console.log("Ajout de l'objet réussit :", response.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setMessRequete("Il y a eu une erreur dans l'ajout de votre objet !");
|
||||||
|
console.error("Erreur lors de l'ajout de l'objet :", error);
|
||||||
|
});
|
||||||
|
setVerif(false);
|
||||||
|
resetForm();
|
||||||
|
} else {
|
||||||
|
setVerif(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function resetForm() {
|
||||||
|
setNom("");
|
||||||
|
setStatus("active");
|
||||||
|
setDescription("");
|
||||||
|
setType("");
|
||||||
|
setLocalisation("");
|
||||||
|
setBatterieType("");
|
||||||
|
if(isAdmin)setProprio("");
|
||||||
|
setActive(true);
|
||||||
|
}
|
||||||
|
function handleCancel() {
|
||||||
|
if (verif) {
|
||||||
|
setVerif(false);
|
||||||
|
} else {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleStatusChange() {
|
||||||
|
setActive((prevIsActive) => {
|
||||||
|
const newIsActive = !prevIsActive;
|
||||||
|
setStatus(newIsActive ? "active" : "inactive");
|
||||||
|
return newIsActive;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit} className="bg-white p-6 rounded-xl min-w-5xl">
|
||||||
|
<div className="flex align-items gap-9">
|
||||||
|
{isAdmin ? (
|
||||||
|
<h2 className="text-2xl font-semibold mb-3">
|
||||||
|
Ajouter un nouvel objet
|
||||||
|
</h2>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<BadgePlus className="text-indigo-600" size={24} />
|
||||||
|
</div>
|
||||||
|
<h1 className="text-black text-2xl font-bold mb-1">
|
||||||
|
{!verif
|
||||||
|
? "Entrez les données de votre nouvel objet"
|
||||||
|
: "Êtes-vous sûr de ces données ?"}
|
||||||
|
</h1>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="mb-5">
|
||||||
|
<label
|
||||||
|
htmlFor="nom"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
Nom :
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="nom"
|
||||||
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
|
type="text"
|
||||||
|
value={nom}
|
||||||
|
onChange={(e) => setNom(e.target.value)}
|
||||||
|
required
|
||||||
|
disabled={verif}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-5">
|
||||||
|
<label
|
||||||
|
htmlFor="description"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
Description :
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="description"
|
||||||
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
|
type="text"
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
required
|
||||||
|
disabled={verif}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<label
|
||||||
|
htmlFor="type"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
Type :
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="type"
|
||||||
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
|
type="text"
|
||||||
|
value={type}
|
||||||
|
onChange={(e) => setType(e.target.value)}
|
||||||
|
required
|
||||||
|
disabled={verif}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<label
|
||||||
|
htmlFor="location"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
Localisation :
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="location"
|
||||||
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
|
type="text"
|
||||||
|
value={location}
|
||||||
|
onChange={(e) => setLocalisation(e.target.value)}
|
||||||
|
required
|
||||||
|
disabled={verif}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-5">
|
||||||
|
<label
|
||||||
|
htmlFor="batterieType"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
Type de batterie :
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="batterieType"
|
||||||
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
|
type="text"
|
||||||
|
value={batterieType}
|
||||||
|
onChange={(e) => setBatterieType(e.target.value)}
|
||||||
|
required
|
||||||
|
disabled={verif}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-5">
|
||||||
|
<label
|
||||||
|
htmlFor="proprio"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
Propriétaire :
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="proprio"
|
||||||
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
|
type="text"
|
||||||
|
value={proprio}
|
||||||
|
onChange={(e) => setProprio(e.target.value)}
|
||||||
|
required
|
||||||
|
disabled={verif||!isAdmin}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<label className="block mb-2 text-sm font-medium text-gray-900">
|
||||||
|
Status :
|
||||||
|
</label>
|
||||||
|
<div className="inline-flex items-center gap-2">
|
||||||
|
<label
|
||||||
|
htmlFor="switch-component-on"
|
||||||
|
className="text-slate-600 text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
Inactive
|
||||||
|
</label>
|
||||||
|
<div className="relative inline-block w-11 h-5">
|
||||||
|
<input
|
||||||
|
id="switch-component-on"
|
||||||
|
type="checkbox"
|
||||||
|
checked={isActive}
|
||||||
|
onChange={handleStatusChange}
|
||||||
|
className="peer appearance-none w-11 h-5 bg-slate-100 rounded-full checked:bg-slate-800 cursor-pointer transition-colors duration-300"
|
||||||
|
disabled={verif}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="switch-component-on"
|
||||||
|
className="absolute top-0 left-0 w-5 h-5 bg-white rounded-full border border-slate-300 shadow-sm transition-transform duration-300 peer-checked:translate-x-6 peer-checked:border-slate-800 cursor-pointer"
|
||||||
|
></label>
|
||||||
|
</div>
|
||||||
|
<label
|
||||||
|
htmlFor="switch-component-on"
|
||||||
|
className="text-slate-600 text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
Active
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col mb-5 ">
|
||||||
|
<button
|
||||||
|
type={"submit"}
|
||||||
|
className="text-blue-500 hover:cursor-pointer hover:underline mb-2"
|
||||||
|
>
|
||||||
|
{!verif ? "Confirmer les informations" : "Oui je suis sûr !"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-red-500 hover:cursor-pointer hover:underline"
|
||||||
|
onClick={handleCancel}
|
||||||
|
>
|
||||||
|
{!verif ? "Supprimer les informations" : "Non je veux changer !"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p className={enregistre ? "text-green-700" : "text-red-700"}>
|
||||||
|
{messRequete}
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormNewObject;
|
||||||
@ -1,125 +1,202 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { LogIn, UserPlus, LogOut, Settings } from "lucide-react";
|
import { X, Menu, LogIn, UserPlus, LogOut, Settings } from "lucide-react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useAuth } from "../AuthContext";
|
import { useAuth } from "../AuthContext";
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
const { token, logout } = useAuth();
|
const { token, logout } = useAuth();
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [showAdminDropdown, setShowAdminDropdown] = useState(false);
|
const [showAdminDropdown, setShowAdminDropdown] = useState(false);
|
||||||
|
|
||||||
|
// La fonction toggleAdminDropdown permet d'ouvrir/fermer le menu déroulant
|
||||||
const toggleAdminDropdown = () => {
|
const toggleAdminDropdown = () => {
|
||||||
setShowAdminDropdown((prev) => !prev);
|
setShowAdminDropdown((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Pour l'instant, le menu "Admin" est toujours affiché.
|
||||||
|
// TODO: Par la suite, ajoutez une vérification du rôle utilisateur (ex: token && user.role === "admin")
|
||||||
|
// afin d'afficher ce menu uniquement aux administrateurs.
|
||||||
return (
|
return (
|
||||||
<header className="bg-white shadow-sm relative">
|
<header className="bg-white shadow-md sticky top-0 z-50">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
<div className="mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
|
||||||
<div className="flex justify-between items-center">
|
<Link to="/" className="text-2xl font-bold text-indigo-600">
|
||||||
<h1 className="text-2xl font-bold text-indigo-600">VigiMétéo</h1>
|
VigiMétéo
|
||||||
<nav>
|
</Link>
|
||||||
<ul className="flex gap-4 relative">
|
<button
|
||||||
<li>
|
className="sm:hidden text-gray-600 hover:text-indigo-600"
|
||||||
<Link to="/" className="text-gray-600 hover:text-indigo-600">
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||||
Accueil
|
>
|
||||||
</Link>
|
{isMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
||||||
</li>
|
</button>
|
||||||
<li>
|
|
||||||
<Link
|
{/* Navigation */}
|
||||||
to="/about"
|
<nav
|
||||||
className="text-gray-600 hover:text-indigo-600"
|
className={`${
|
||||||
|
isMenuOpen ? "block" : "hidden"
|
||||||
|
} absolute top-16 left-0 w-full bg-white shadow-md sm:static sm:w-auto sm:flex sm:gap-6 sm:shadow-none z-50`}
|
||||||
|
>
|
||||||
|
<ul className="flex flex-col sm:flex-row gap-4 sm:gap-6 text-gray-600 p-4 sm:p-0">
|
||||||
|
<li>
|
||||||
|
<Link to="/" className="hover:text-indigo-600">
|
||||||
|
Accueil
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/about" className="hover:text-indigo-600">
|
||||||
|
À propos
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/gestion" className="hover:text-indigo-600">
|
||||||
|
Gestion
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
{/* Menu déroulant Admin toujours affiché */}
|
||||||
|
<li className="relative">
|
||||||
|
<button
|
||||||
|
onClick={toggleAdminDropdown}
|
||||||
|
className="flex items-center text-gray-600 hover:text-indigo-600 focus:outline-none"
|
||||||
|
>
|
||||||
|
Admin
|
||||||
|
<svg
|
||||||
|
className="ml-1 h-4 w-4 fill-current"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
>
|
>
|
||||||
A propos
|
<path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
|
||||||
</Link>
|
</svg>
|
||||||
</li>
|
</button>
|
||||||
<li>
|
{showAdminDropdown && (
|
||||||
<Link
|
<div className="absolute top-full left-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-50">
|
||||||
to="/gestion"
|
<Link
|
||||||
className="text-gray-600 hover:text-indigo-600"
|
to="/dashboard"
|
||||||
>
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
Gestion
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
{/* Onglet déroulant "Admin" */}
|
|
||||||
<li className="relative">
|
|
||||||
<button
|
|
||||||
onClick={toggleAdminDropdown}
|
|
||||||
className="flex items-center text-gray-600 hover:text-indigo-600 focus:outline-none"
|
|
||||||
>
|
|
||||||
Admin
|
|
||||||
<svg
|
|
||||||
className="ml-1 h-4 w-4 fill-current"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
>
|
||||||
<path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
|
Dashboard
|
||||||
</svg>
|
</Link>
|
||||||
</button>
|
<Link
|
||||||
{showAdminDropdown && (
|
to="/user"
|
||||||
<div className="absolute top-full left-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-50">
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
{/* En cliquant sur le lien "Dashboard", on ferme le menu */}
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
<Link
|
>
|
||||||
to="/dashboard"
|
Gestion des Utilisateurs
|
||||||
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
</Link>
|
||||||
onClick={() => setShowAdminDropdown(false)}
|
<Link
|
||||||
>
|
to="/adminobjet"
|
||||||
Dashboard
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
</Link>
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
<Link
|
>
|
||||||
to="/user"
|
Gestion des Objets Connectés
|
||||||
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
</Link>
|
||||||
onClick={() => setShowAdminDropdown(false)}
|
</div>
|
||||||
>
|
)}
|
||||||
Gestion des Utilisateurs
|
</li>
|
||||||
</Link>
|
{!token ? (
|
||||||
<Link
|
|
||||||
to="/adminobjet"
|
|
||||||
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
|
||||||
onClick={() => setShowAdminDropdown(false)}
|
|
||||||
>
|
|
||||||
Gestion des Objets Connectés
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<div className="flex gap-4">
|
|
||||||
{token ? (
|
|
||||||
<>
|
<>
|
||||||
<Link
|
<li className="sm:hidden">
|
||||||
to="/settings"
|
<Link
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
to="/login"
|
||||||
>
|
className="flex items-center gap-2 hover:text-indigo-600"
|
||||||
<Settings size={20} />
|
>
|
||||||
<span></span>
|
<LogIn size={20} />
|
||||||
</Link>
|
Connexion
|
||||||
<button
|
</Link>
|
||||||
onClick={logout}
|
</li>
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
<li className="sm:hidden">
|
||||||
>
|
<Link
|
||||||
<LogOut size={20} />
|
to="/signup"
|
||||||
<span>Déconnexion</span>
|
className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700"
|
||||||
</button>
|
>
|
||||||
|
<UserPlus size={20} />
|
||||||
|
Inscription
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Link
|
<li className="sm:hidden">
|
||||||
to="/login"
|
<Link
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
to="/settings"
|
||||||
>
|
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
||||||
<LogIn size={20} />
|
>
|
||||||
<span>Connexion</span>
|
<Settings size={20} />
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
</li>
|
||||||
to="/signup"
|
<li className="sm:hidden">
|
||||||
className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700"
|
<button
|
||||||
>
|
onClick={logout}
|
||||||
<UserPlus size={20} />
|
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
||||||
<span>Inscription</span>
|
>
|
||||||
</Link>
|
<LogOut size={20} />
|
||||||
|
Déconnexion
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{!token ? (
|
||||||
|
<div className="hidden sm:flex gap-4">
|
||||||
|
<Link to="/login" className="flex items-center gap-2 hover:text-indigo-600">
|
||||||
|
<LogIn size={20} />
|
||||||
|
Connexion
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/signup"
|
||||||
|
className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700"
|
||||||
|
>
|
||||||
|
<UserPlus size={20} />
|
||||||
|
Inscription
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
|
<div className="hidden sm:flex gap-4 items-center">
|
||||||
|
<Link to="/settings" className="flex items-center gap-2 text-gray-600 hover:text-indigo-600">
|
||||||
|
<Settings size={20} />
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
onClick={logout}
|
||||||
|
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
||||||
|
>
|
||||||
|
<LogOut size={20} />
|
||||||
|
Déconnexion
|
||||||
|
</button>
|
||||||
|
{/* Menu déroulant Admin visible sur sm+ */}
|
||||||
|
<div className="relative">
|
||||||
|
<button onClick={toggleAdminDropdown} className="flex items-center text-gray-600 hover:text-indigo-600 focus:outline-none">
|
||||||
|
Admin
|
||||||
|
<svg className="ml-1 h-4 w-4 fill-current" viewBox="0 0 20 20">
|
||||||
|
<path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{showAdminDropdown && (
|
||||||
|
<div className="absolute top-full left-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-50">
|
||||||
|
<Link
|
||||||
|
to="/dashboard"
|
||||||
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
|
>
|
||||||
|
Dashboard
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/user"
|
||||||
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
|
>
|
||||||
|
Gestion des Utilisateurs
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/adminobjet"
|
||||||
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
|
>
|
||||||
|
Gestion des Objets Connectés
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,7 +11,7 @@ function ModifObject({ object, defafficherModif }) {
|
|||||||
const [isActive, setActive] = useState(object.status === "active");
|
const [isActive, setActive] = useState(object.status === "active");
|
||||||
|
|
||||||
function handleSubmit(event) {
|
function handleSubmit(event) {
|
||||||
event.preventDefault(); // Empêche le rechargement de la page
|
event.preventDefault();
|
||||||
axios
|
axios
|
||||||
.post(`${API_BASE_URL}/modifObjet`, {
|
.post(`${API_BASE_URL}/modifObjet`, {
|
||||||
id: object.id,
|
id: object.id,
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cloud-alert-icon lucide-cloud-alert"><path d="M12 12v4"/><path d="M12 20h.01"/><path d="M17 18h.5a1 1 0 0 0 0-9h-1.79A7 7 0 1 0 7 17.708"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 347 B |
1
Front-end/src/img/cloud-sun-rain.svg
Normal file
1
Front-end/src/img/cloud-sun-rain.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cloud-sun-rain-icon lucide-cloud-sun-rain"><path d="M12 2v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="M20 12h2"/><path d="m19.07 4.93-1.41 1.41"/><path d="M15.947 12.65a4 4 0 0 0-5.925-4.128"/><path d="M3 20a5 5 0 1 1 8.9-4H13a3 3 0 0 1 2 5.24"/><path d="M11 20v2"/><path d="M7 19v2"/></svg>
|
||||||
|
After Width: | Height: | Size: 494 B |
@ -1,10 +1,20 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Sidebar from "./sidebar.jsx";
|
import Sidebar from "./sidebar.jsx";
|
||||||
|
import axios from "axios";
|
||||||
|
import { API_BASE_URL } from "../../config";
|
||||||
|
import AddObject from "../Gestion/AddObject.jsx";
|
||||||
|
import FormNewObject from "../../components/FormNewObject.jsx";
|
||||||
|
|
||||||
function AdminObjet() {
|
function AdminObjet() {
|
||||||
// Gestion des catégories
|
|
||||||
const [categories, setCategories] = useState(["Catégorie 1", "Catégorie 2"]);
|
const [categories, setCategories] = useState(["Catégorie 1", "Catégorie 2"]);
|
||||||
const [newCategory, setNewCategory] = useState("");
|
const [newCategory, setNewCategory] = useState("");
|
||||||
|
const [objects, setObjects] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get(`${API_BASE_URL}/objets`).then((response) => {
|
||||||
|
setObjects(response.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleAddCategory = () => {
|
const handleAddCategory = () => {
|
||||||
const trimmed = newCategory.trim();
|
const trimmed = newCategory.trim();
|
||||||
@ -13,23 +23,16 @@ function AdminObjet() {
|
|||||||
setNewCategory("");
|
setNewCategory("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteCategory = (categoryToDelete) => {
|
const handleDeleteCategory = (categoryToDelete) => {
|
||||||
setCategories(categories.filter((cat) => cat !== categoryToDelete));
|
setCategories(categories.filter((cat) => cat !== categoryToDelete));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Gestion des objets et outils/services
|
const [name, setName] = useState("");
|
||||||
// On ajoute maintenant le champ "propriétaire"
|
|
||||||
const [objects, setObjects] = useState([]);
|
|
||||||
|
|
||||||
// Champs du formulaire d'ajout d'objet (inspiré de AddObject.jsx)
|
|
||||||
const [nom, setNom] = useState("");
|
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [type, setType] = useState("");
|
const [type, setType] = useState("");
|
||||||
const [localisation, setLocalisation] = useState("");
|
const [location, setLocation] = useState("");
|
||||||
const [proprietaire, setProprietaire] = useState("");
|
const [proprietaire, setProprietaire] = useState("");
|
||||||
const [status, setStatus] = useState("active");
|
const [status, setStatus] = useState("active");
|
||||||
const [isActive, setIsActive] = useState(true);
|
|
||||||
const [verif, setVerif] = useState(false);
|
const [verif, setVerif] = useState(false);
|
||||||
const [enregistre, setEnregistre] = useState(false);
|
const [enregistre, setEnregistre] = useState(false);
|
||||||
const [messRequete, setMessRequete] = useState("");
|
const [messRequete, setMessRequete] = useState("");
|
||||||
@ -39,10 +42,10 @@ function AdminObjet() {
|
|||||||
if (verif) {
|
if (verif) {
|
||||||
const newObj = {
|
const newObj = {
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
nom: nom.trim(),
|
name: name.trim(),
|
||||||
description: description.trim(),
|
description: description.trim(),
|
||||||
type: type.trim(),
|
type: type.trim(),
|
||||||
localisation: localisation.trim(),
|
location: location.trim(),
|
||||||
proprietaire: proprietaire.trim(),
|
proprietaire: proprietaire.trim(),
|
||||||
status: status,
|
status: status,
|
||||||
};
|
};
|
||||||
@ -51,42 +54,29 @@ function AdminObjet() {
|
|||||||
setEnregistre(true);
|
setEnregistre(true);
|
||||||
setVerif(false);
|
setVerif(false);
|
||||||
resetForm();
|
resetForm();
|
||||||
|
window.location.reload();
|
||||||
} else {
|
} else {
|
||||||
setVerif(true);
|
setVerif(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetForm = () => {
|
|
||||||
setNom("");
|
|
||||||
setDescription("");
|
|
||||||
setType("");
|
|
||||||
setLocalisation("");
|
|
||||||
setProprietaire("");
|
|
||||||
setStatus("active");
|
|
||||||
setIsActive(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
if (verif) {
|
|
||||||
setVerif(false);
|
|
||||||
} else {
|
|
||||||
resetForm();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStatusChange = () => {
|
|
||||||
setIsActive((prev) => {
|
|
||||||
const newIsActive = !prev;
|
|
||||||
setStatus(newIsActive ? "active" : "inactive");
|
|
||||||
return newIsActive;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteObject = (id) => {
|
const handleDeleteObject = (id) => {
|
||||||
setObjects(objects.filter((obj) => obj.id !== id));
|
axios
|
||||||
|
.post(`${API_BASE_URL}/deleteObject`, {
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setMessRequete("Votre objet à bien été supprimé !");
|
||||||
|
console.log("Votre objet à été supprimé :", response.data);
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setMessRequete(
|
||||||
|
"Il y a eu une erreur dans la suppression de votre objet !"
|
||||||
|
);
|
||||||
|
console.error("Erreur lors de la suppression de l'objet :", error);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tri des objets en fonction d'une catégorie sélectionnée
|
|
||||||
const [sortCriteria, setSortCriteria] = useState("");
|
const [sortCriteria, setSortCriteria] = useState("");
|
||||||
|
|
||||||
const sortedObjects = [...objects].sort((a, b) => {
|
const sortedObjects = [...objects].sort((a, b) => {
|
||||||
@ -96,7 +86,6 @@ function AdminObjet() {
|
|||||||
return fieldA.localeCompare(fieldB);
|
return fieldA.localeCompare(fieldB);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Règles globales
|
|
||||||
const [energyPriority, setPriority] = useState("");
|
const [energyPriority, setPriority] = useState("");
|
||||||
const [alertSettings, setAlertSettings] = useState("");
|
const [alertSettings, setAlertSettings] = useState("");
|
||||||
|
|
||||||
@ -154,138 +143,11 @@ function AdminObjet() {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
{/*Formulaire d'ajout d'objet*/}
|
||||||
|
<FormNewObject isAdmin={true} />
|
||||||
|
|
||||||
{/* Formulaire d'ajout d'objet */}
|
{/* Tri des objets */}
|
||||||
<section className="bg-white p-6 rounded-xl shadow-md mb-12">
|
<section className="bg-white p-6 rounded-xl shadow-md mt-12 mb-12">
|
||||||
<div className="flex items-center gap-4 mb-5">
|
|
||||||
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center">
|
|
||||||
<span className="text-indigo-600 text-xl">+</span>
|
|
||||||
</div>
|
|
||||||
<h2 className="text-2xl font-bold text-gray-900">
|
|
||||||
{!verif
|
|
||||||
? "Entrez les données de votre nouvel objet"
|
|
||||||
: "Êtes-vous sûr de ces données ?"}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-5">
|
|
||||||
<div>
|
|
||||||
<label htmlFor="nom" className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Nom :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="nom"
|
|
||||||
type="text"
|
|
||||||
value={nom}
|
|
||||||
onChange={(e) => setNom(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="description" className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Description :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="description"
|
|
||||||
type="text"
|
|
||||||
value={description}
|
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="type" className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Type :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="type"
|
|
||||||
type="text"
|
|
||||||
value={type}
|
|
||||||
onChange={(e) => setType(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="localisation" className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Localisation :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="localisation"
|
|
||||||
type="text"
|
|
||||||
value={localisation}
|
|
||||||
onChange={(e) => setLocalisation(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="proprietaire" className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Propriétaire :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="proprietaire"
|
|
||||||
type="text"
|
|
||||||
value={proprietaire}
|
|
||||||
onChange={(e) => setProprietaire(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Status :
|
|
||||||
</label>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<label
|
|
||||||
htmlFor="switch-component-on"
|
|
||||||
className="text-slate-600 text-sm cursor-pointer"
|
|
||||||
>
|
|
||||||
Inactive
|
|
||||||
</label>
|
|
||||||
<div className="relative inline-block w-11 h-5">
|
|
||||||
<input
|
|
||||||
id="switch-component-on"
|
|
||||||
type="checkbox"
|
|
||||||
checked={isActive}
|
|
||||||
onChange={handleStatusChange}
|
|
||||||
disabled={verif}
|
|
||||||
className="peer appearance-none w-11 h-5 bg-slate-100 rounded-full cursor-pointer transition-colors duration-300"
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
htmlFor="switch-component-on"
|
|
||||||
className="absolute top-0 left-0 w-5 h-5 bg-white rounded-full border border-slate-300 shadow-sm transition-transform duration-300 peer-checked:translate-x-6 peer-checked:border-slate-800 cursor-pointer"
|
|
||||||
></label>
|
|
||||||
</div>
|
|
||||||
<label
|
|
||||||
htmlFor="switch-component-on"
|
|
||||||
className="text-slate-600 text-sm cursor-pointer"
|
|
||||||
>
|
|
||||||
Active
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<button type="submit" className="text-blue-500 hover:underline mb-2">
|
|
||||||
{!verif ? "Confirmer les informations" : "Oui je suis sûr !"}
|
|
||||||
</button>
|
|
||||||
<button type="button" onClick={handleCancel} className="text-red-500 hover:underline">
|
|
||||||
{!verif ? "Supprimer les informations" : "Non je veux changer !"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p className={enregistre ? "text-green-700" : "text-red-700"}>
|
|
||||||
{messRequete}
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
{/* TRI DES OBJETS */}
|
|
||||||
<section className="bg-white p-6 rounded-xl shadow-md mb-12">
|
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h2 className="text-2xl font-semibold">
|
<h2 className="text-2xl font-semibold">
|
||||||
Liste des Objets et Outils/Services
|
Liste des Objets et Outils/Services
|
||||||
@ -297,7 +159,7 @@ function AdminObjet() {
|
|||||||
>
|
>
|
||||||
<option value="">-- Trier par --</option>
|
<option value="">-- Trier par --</option>
|
||||||
<option value="proprietaire">Propriétaire</option>
|
<option value="proprietaire">Propriétaire</option>
|
||||||
<option value="localisation">Lieux</option>
|
<option value="location">Lieux</option>
|
||||||
<option value="type">Type</option>
|
<option value="type">Type</option>
|
||||||
<option value="status">Status</option>
|
<option value="status">Status</option>
|
||||||
</select>
|
</select>
|
||||||
@ -332,7 +194,7 @@ function AdminObjet() {
|
|||||||
{sortedObjects.map((obj) => (
|
{sortedObjects.map((obj) => (
|
||||||
<tr key={obj.id}>
|
<tr key={obj.id}>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
{obj.nom}
|
{obj.name}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{obj.description}
|
{obj.description}
|
||||||
@ -341,10 +203,10 @@ function AdminObjet() {
|
|||||||
{obj.type}
|
{obj.type}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{obj.localisation}
|
{obj.location}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{obj.proprietaire}
|
{obj.proprio}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{obj.status}
|
{obj.status}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Sidebar from "./sidebar.jsx";
|
import Sidebar from "./sidebar.jsx";
|
||||||
import { RadioTower, ArrowRight, BadgePlus, Settings } from "lucide-react";
|
import { RadioTower, ArrowRight, BadgePlus, Settings } from "lucide-react";
|
||||||
|
import { API_BASE_URL } from "../../config.js";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
// Widgets initiaux pour le dashboard
|
// Widgets initiaux pour le dashboard
|
||||||
const initialWidgets = [
|
const initialWidgets = [
|
||||||
@ -109,7 +111,13 @@ function Dashboard() {
|
|||||||
setWidgets([...widgets, newWidget]);
|
setWidgets([...widgets, newWidget]);
|
||||||
setShowAddWidgetModal(false);
|
setShowAddWidgetModal(false);
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get(`${API_BASE_URL}/users`).then((response) => {
|
||||||
|
setUsers(response.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
*/
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen">
|
<div className="flex min-h-screen">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
@ -148,10 +156,10 @@ function Dashboard() {
|
|||||||
{widget.type === "summary" && (
|
{widget.type === "summary" && (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold mb-4">
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
Dashboard Summary
|
Résumé du tableau de bord
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<h3 className="text-lg font-medium">Total Users</h3>
|
<h3 className="text-lg font-medium">Total Utilisateur</h3>
|
||||||
<p className="text-2xl">{users.length}</p>
|
<p className="text-2xl">{users.length}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -167,6 +175,7 @@ function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{widget.type === "users" && (
|
{widget.type === "users" && (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold mb-4">
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
@ -222,6 +231,7 @@ function Dashboard() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{widget.type === "objects" && (
|
{widget.type === "objects" && (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold mb-4">
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
@ -339,4 +349,4 @@ function Dashboard() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Dashboard;
|
export default Dashboard;
|
||||||
@ -1,10 +1,16 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Sidebar from "./sidebar.jsx";
|
import Sidebar from "./sidebar.jsx";
|
||||||
|
import { API_BASE_URL } from "../../config.js";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
// Définition de styles utilisés (si nécessaire – vous pouvez convertir ces styles en classes Tailwind)
|
||||||
|
const thTd = "p-2 border border-gray-300 text-left";
|
||||||
|
const th = `${thTd} bg-gray-100`;
|
||||||
|
|
||||||
function User() {
|
function User() {
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
const [logs, setLogs] = useState([]);
|
const [logs, setLogs] = useState([]);
|
||||||
const [username, setUsername] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [pointsInput, setPointsInput] = useState({});
|
const [pointsInput, setPointsInput] = useState({});
|
||||||
|
|
||||||
@ -12,70 +18,113 @@ function User() {
|
|||||||
const handleAddUser = (e) => {
|
const handleAddUser = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const newUser = {
|
const newUser = {
|
||||||
id: Date.now(),
|
id: Date.now(), // ID généré temporairement ; en production, il sera géré par la BDD.
|
||||||
username,
|
name,
|
||||||
email,
|
email,
|
||||||
accessLevel: "User", // Niveau d'accès par défaut
|
accessLevel: "User",
|
||||||
points: 0,
|
points: 0,
|
||||||
};
|
};
|
||||||
setUsers([...users, newUser]);
|
setUsers([...users, newUser]);
|
||||||
logAction(username, "User added");
|
logAction(name, "User added");
|
||||||
setUsername("");
|
setName("");
|
||||||
setEmail("");
|
setEmail("");
|
||||||
|
// TODO : Envoyer newUser à l'API si nécessaire.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Chargement des utilisateurs depuis l'API au montage du composant
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.get(`${API_BASE_URL}/users`)
|
||||||
|
.then((response) => setUsers(response.data))
|
||||||
|
.catch((error) =>
|
||||||
|
console.error("Erreur lors de la récupération des utilisateurs:", error)
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Suppression d'un utilisateur
|
// Suppression d'un utilisateur
|
||||||
const handleDeleteUser = (userId) => {
|
const handleDeleteUser = (userId) => {
|
||||||
const user = users.find((u) => u.id === userId);
|
const user = users.find((u) => u.id === userId);
|
||||||
if (user) {
|
if (user) {
|
||||||
logAction(user.username, "User deleted");
|
logAction(user.name, "User deleted");
|
||||||
}
|
}
|
||||||
setUsers(users.filter((u) => u.id !== userId));
|
setUsers(users.filter((u) => u.id !== userId));
|
||||||
|
// TODO : Envoyer la suppression au backend.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Changement du niveau d'accès via le menu déroulant
|
// Changement du niveau d'accès
|
||||||
const handleChangeAccessLevel = (userId, newLevel) => {
|
const handleChangeAccessLevel = (userId, newLevel) => {
|
||||||
setUsers(
|
setUsers(
|
||||||
users.map((user) => {
|
users.map((user) => {
|
||||||
if (user.id === userId) {
|
if (user.id === userId && newLevel !== user.accessLevel) {
|
||||||
const oldLevel = user.accessLevel;
|
const oldLevel = user.accessLevel;
|
||||||
user.accessLevel = newLevel;
|
user.accessLevel = newLevel;
|
||||||
logAction(
|
// Exemple de remise à zéro ou affectation de points en fonction du rôle :
|
||||||
user.username,
|
if (newLevel === "user") {
|
||||||
`Access level changed from ${oldLevel} to ${newLevel}`
|
user.points = 0;
|
||||||
);
|
} else if (newLevel === "complexe") {
|
||||||
|
user.points = 60;
|
||||||
|
} else if (newLevel === "admin") {
|
||||||
|
user.points = 100;
|
||||||
|
}
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/setUserPoints`, {
|
||||||
|
id: user.id,
|
||||||
|
points: user.points,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
alert("Le changement de niveau a bien été enregistré !");
|
||||||
|
console.log("Niveau changé:", response.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
alert("Erreur lors du changement de niveau !");
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
logAction(user.name, `Access level changed from ${oldLevel} to ${newLevel}`);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ajustement des points d'un utilisateur
|
// Ajustement des points : additionne les points saisis aux points existants
|
||||||
const handleAdjustPoints = (userId) => {
|
const handleAdjustPoints = (userId) => {
|
||||||
const pointsToAdd = parseInt(pointsInput[userId]) || 0;
|
const pointsToAdd = parseInt(pointsInput[userId]) || 0;
|
||||||
setUsers(
|
setUsers(
|
||||||
users.map((user) => {
|
users.map((user) => {
|
||||||
if (user.id === userId) {
|
if (user.id === userId) {
|
||||||
user.points += pointsToAdd;
|
// On additionne au lieu de remplacer
|
||||||
logAction(user.username, `Points adjusted by ${pointsToAdd}`);
|
user.points = (user.points || 0) + pointsToAdd;
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/setUserPoints`, {
|
||||||
|
id: user.id,
|
||||||
|
points: user.points,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
alert("Les points ont bien été enregistrés !");
|
||||||
|
console.log("Points mis à jour :", response.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
alert("Erreur lors de l'ajustement des points !");
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
logAction(user.name, `Points adjusted by ${pointsToAdd}, new total: ${user.points}`);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// Réinitialiser l'input pour cet utilisateur
|
|
||||||
setPointsInput({ ...pointsInput, [userId]: "" });
|
setPointsInput({ ...pointsInput, [userId]: "" });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fonction de journalisation des actions
|
// Fonction de journalisation des actions
|
||||||
const logAction = (username, action) => {
|
const logAction = (name, action) => {
|
||||||
const timestamp = new Date().toLocaleString();
|
const timestamp = new Date().toLocaleString();
|
||||||
setLogs([...logs, { id: Date.now(), username, action, timestamp }]);
|
setLogs([...logs, { id: Date.now(), name, action, timestamp }]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fonction pour générer et télécharger le fichier txt des logs
|
// Fonction pour générer et télécharger les logs dans un fichier texte
|
||||||
const downloadLogs = () => {
|
const downloadLogs = () => {
|
||||||
const logText = logs
|
const logText = logs
|
||||||
.map((log) => `${log.timestamp} - ${log.username} - ${log.action}`)
|
.map((log) => `${log.timestamp} - ${log.name} - ${log.action}`)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
const blob = new Blob([logText], { type: "text/plain;charset=utf-8" });
|
const blob = new Blob([logText], { type: "text/plain;charset=utf-8" });
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
@ -95,17 +144,17 @@ function User() {
|
|||||||
<p className="mb-5">Gérez les utilisateurs à partir de ce panneau.</p>
|
<p className="mb-5">Gérez les utilisateurs à partir de ce panneau.</p>
|
||||||
{/* Formulaire d'ajout d'utilisateur */}
|
{/* Formulaire d'ajout d'utilisateur */}
|
||||||
<form
|
<form
|
||||||
className="grid grid-cols-[1fr_1fr_auto] gap-[10px] mb-5"
|
className="grid grid-cols-[1fr_1fr_auto] gap-2 mb-5"
|
||||||
onSubmit={handleAddUser}
|
onSubmit={handleAddUser}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="username"
|
id="name"
|
||||||
placeholder="Username"
|
placeholder="Name"
|
||||||
value={username}
|
value={name}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
required
|
required
|
||||||
className="p-2.5 border border-gray-300 rounded-md"
|
className="p-2 border border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
@ -114,46 +163,32 @@ function User() {
|
|||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
required
|
required
|
||||||
className="p-2.5 border border-gray-300 rounded-md"
|
className="p-2 border border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="p-2.5 bg-green-600 text-white rounded-md cursor-pointer"
|
className="p-2 bg-green-600 text-white rounded-md cursor-pointer"
|
||||||
>
|
>
|
||||||
Add User
|
Add User
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{/* Tableau des utilisateurs */}
|
{/* Tableau des utilisateurs */}
|
||||||
<table className="w-full border-collapse">
|
<table className="w-full border-collapse mb-6">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
<th className={th}>Nom</th>
|
||||||
Username
|
<th className={th}>Email</th>
|
||||||
</th>
|
<th className={th}>Niveau d'accès</th>
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
<th className={th}>Points</th>
|
||||||
Email
|
<th className={th}>Actions</th>
|
||||||
</th>
|
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
|
||||||
Access Level
|
|
||||||
</th>
|
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
|
||||||
Points
|
|
||||||
</th>
|
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
|
||||||
Actions
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{users.map((user) => (
|
{users.map((user) => (
|
||||||
<tr key={user.id}>
|
<tr key={user.id}>
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
<td className={thTd}>{user.name}</td>
|
||||||
{user.username}
|
<td className={thTd}>{user.email}</td>
|
||||||
</td>
|
<td className={thTd}>
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
|
||||||
{user.email}
|
|
||||||
</td>
|
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
|
||||||
<select
|
<select
|
||||||
value={user.accessLevel}
|
value={user.accessLevel}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@ -161,39 +196,37 @@ function User() {
|
|||||||
}
|
}
|
||||||
className="p-1 rounded-md border border-gray-300"
|
className="p-1 rounded-md border border-gray-300"
|
||||||
>
|
>
|
||||||
<option value="Admin">Admin</option>
|
<option value="admin">Admin</option>
|
||||||
<option value="User">User</option>
|
<option value="user">User</option>
|
||||||
<option value="Guest">Guest</option>
|
<option value="complexe">Complexe</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
<td className={thTd}>
|
||||||
<span>{user.points}</span>
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
placeholder="Adjust"
|
value={pointsInput[user.id] ?? user.points}
|
||||||
value={pointsInput[user.id] || ""}
|
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setPointsInput({
|
setPointsInput({
|
||||||
...pointsInput,
|
...pointsInput,
|
||||||
[user.id]: e.target.value,
|
[user.id]: e.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="w-[60px] ml-2.5 p-1 border border-gray-300 rounded-md"
|
className="w-16 ml-2 p-1 border border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleAdjustPoints(user.id)}
|
onClick={() => handleAdjustPoints(user.id)}
|
||||||
className="py-1 px-2.5 ml-2 bg-green-600 text-white rounded-md cursor-pointer"
|
className="p-2 bg-green-600 text-white rounded-md ml-2"
|
||||||
>
|
>
|
||||||
Adjust
|
Changer
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
<td className={thTd}>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDeleteUser(user.id)}
|
onClick={() => handleDeleteUser(user.id)}
|
||||||
className="py-1 px-2.5 bg-red-600 text-white rounded-md cursor-pointer"
|
className="p-2 bg-red-600 text-white rounded-md"
|
||||||
>
|
>
|
||||||
Delete
|
Supprimer
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -203,40 +236,27 @@ function User() {
|
|||||||
</section>
|
</section>
|
||||||
{/* Tableau des logs */}
|
{/* Tableau des logs */}
|
||||||
<section className="mt-10">
|
<section className="mt-10">
|
||||||
<h2 className="text-xl font-bold mb-4">
|
<h2 className="text-2xl font-bold mb-4">
|
||||||
Login History and Action Logs
|
Historique des connexions et journal des logs
|
||||||
</h2>
|
</h2>
|
||||||
<table className="w-full border-collapse">
|
<table className="w-full border-collapse mb-4">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
<th className={th}>Nom</th>
|
||||||
Username
|
<th className={th}>Action</th>
|
||||||
</th>
|
<th className={th}>Timestamp</th>
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
|
||||||
Action
|
|
||||||
</th>
|
|
||||||
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
|
||||||
Timestamp
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{logs.map((log) => (
|
{logs.map((log) => (
|
||||||
<tr key={log.id}>
|
<tr key={log.id}>
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
<td className={thTd}>{log.name}</td>
|
||||||
{log.username}
|
<td className={thTd}>{log.action}</td>
|
||||||
</td>
|
<td className={thTd}>{log.timestamp}</td>
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
|
||||||
{log.action}
|
|
||||||
</td>
|
|
||||||
<td className="p-2.5 border border-gray-300 text-left">
|
|
||||||
{log.timestamp}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{/* Bouton de téléchargement des logs */}
|
|
||||||
<button
|
<button
|
||||||
onClick={downloadLogs}
|
onClick={downloadLogs}
|
||||||
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md"
|
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md"
|
||||||
|
|||||||
@ -29,12 +29,12 @@ function Sidebar({ isOpen, toggleSidebar }) {
|
|||||||
className="text-white no-underline hover:underline"
|
className="text-white no-underline hover:underline"
|
||||||
href="/dashboard"
|
href="/dashboard"
|
||||||
>
|
>
|
||||||
Dashboard
|
Tableau de bord
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="mb-3">
|
<li className="mb-3">
|
||||||
<a className="text-white no-underline hover:underline" href="/user">
|
<a className="text-white no-underline hover:underline" href="/user">
|
||||||
Users
|
Utilisateurs
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="mb-3">
|
<li className="mb-3">
|
||||||
@ -42,17 +42,17 @@ function Sidebar({ isOpen, toggleSidebar }) {
|
|||||||
className="text-white no-underline hover:underline"
|
className="text-white no-underline hover:underline"
|
||||||
href="/adminobjet"
|
href="/adminobjet"
|
||||||
>
|
>
|
||||||
AdminObjet
|
Gestion des objets
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="mb-3">
|
<li className="mb-3">
|
||||||
<a className="text-white no-underline hover:underline" href="#">
|
<a className="text-white no-underline hover:underline" href="#">
|
||||||
Settings
|
Paramètres
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="mb-3">
|
<li className="mb-3">
|
||||||
<a className="text-white no-underline hover:underline" href="#">
|
<a className="text-white no-underline hover:underline" href="#">
|
||||||
Reports
|
Rapports
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -1,71 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { BadgePlus } from "lucide-react";
|
import FormNewObject from "../../components/FormNewObject";
|
||||||
import axios from "axios";
|
|
||||||
import { API_BASE_URL } from "../../config";
|
|
||||||
|
|
||||||
function AddObject() {
|
function AddObject() {
|
||||||
const [description, setDescription] = useState("");
|
|
||||||
const [type, setType] = useState("");
|
|
||||||
const [location, setLocalisation] = useState("");
|
|
||||||
const [status, setStatus] = useState("active");
|
|
||||||
const [nom, setNom] = useState("");
|
|
||||||
const [Response, setResponse] = useState(null);
|
|
||||||
const [isActive, setActive] = useState(true);
|
|
||||||
const [verif, setVerif] = useState(false);
|
|
||||||
const [enregistre, setEnregistre] = useState(false);
|
|
||||||
const [messRequete, setMessRequete] = useState("");
|
|
||||||
function handleSubmit(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (verif) {
|
|
||||||
console.log("Envoi requete");
|
|
||||||
axios
|
|
||||||
.post(`${API_BASE_URL}/addObject`, {
|
|
||||||
nom,
|
|
||||||
description,
|
|
||||||
type,
|
|
||||||
location,
|
|
||||||
status,
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
setMessRequete("Votre objet à bien été enregistré !");
|
|
||||||
setEnregistre(true);
|
|
||||||
console.log("Ajout de l'objet réussit :", response.data);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setMessRequete("Il y a eu une erreur dans l'ajout de votre objet !");
|
|
||||||
console.error("Erreur lors de l'ajout de l'objet :", error);
|
|
||||||
});
|
|
||||||
setVerif(false);
|
|
||||||
resetForm();
|
|
||||||
} else {
|
|
||||||
setVerif(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function resetForm() {
|
|
||||||
setNom("");
|
|
||||||
setStatus("");
|
|
||||||
setDescription("");
|
|
||||||
setType("");
|
|
||||||
setLocalisation("");
|
|
||||||
setActive(true);
|
|
||||||
}
|
|
||||||
function handleCancel() {
|
|
||||||
if (verif) {
|
|
||||||
setVerif(false);
|
|
||||||
} else {
|
|
||||||
resetForm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleStatusChange() {
|
|
||||||
setActive((prevIsActive) => {
|
|
||||||
const newIsActive = !prevIsActive;
|
|
||||||
setStatus(newIsActive ? "active" : "inactive");
|
|
||||||
return newIsActive;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50">
|
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50">
|
||||||
<div className=" max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
<div className=" max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||||
@ -74,144 +10,7 @@ function AddObject() {
|
|||||||
Nouvel objet
|
Nouvel objet
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<form
|
<FormNewObject />
|
||||||
onSubmit={handleSubmit}
|
|
||||||
className="bg-white p-6 rounded-xl min-w-5xl"
|
|
||||||
>
|
|
||||||
<div className="flex align-items gap-9">
|
|
||||||
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4">
|
|
||||||
<BadgePlus className="text-indigo-600" size={24} />
|
|
||||||
</div>
|
|
||||||
<h1 className="text-black text-2xl font-bold mb-1">
|
|
||||||
{!verif
|
|
||||||
? "Entrez les données de votre nouvel objet"
|
|
||||||
: "Êtes-vous sûr de ces données ?"}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div className="mb-5">
|
|
||||||
<label
|
|
||||||
htmlFor="nom"
|
|
||||||
className="block mb-2 text-sm font-medium text-gray-900"
|
|
||||||
>
|
|
||||||
Nom :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="nom"
|
|
||||||
className="text-gray-600 border rounded-lg p-2 w-full"
|
|
||||||
type="text"
|
|
||||||
value={nom}
|
|
||||||
onChange={(e) => setNom(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-5">
|
|
||||||
<label
|
|
||||||
htmlFor="description"
|
|
||||||
className="block mb-2 text-sm font-medium text-gray-900"
|
|
||||||
>
|
|
||||||
Description :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="description"
|
|
||||||
className="text-gray-600 border rounded-lg p-2 w-full"
|
|
||||||
type="text"
|
|
||||||
value={description}
|
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-5">
|
|
||||||
<label
|
|
||||||
htmlFor="type"
|
|
||||||
className="block mb-2 text-sm font-medium text-gray-900"
|
|
||||||
>
|
|
||||||
Type :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="type"
|
|
||||||
className="text-gray-600 border rounded-lg p-2 w-full"
|
|
||||||
type="text"
|
|
||||||
value={type}
|
|
||||||
onChange={(e) => setType(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-5">
|
|
||||||
<label
|
|
||||||
htmlFor="location"
|
|
||||||
className="block mb-2 text-sm font-medium text-gray-900"
|
|
||||||
>
|
|
||||||
Localisation :
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="location"
|
|
||||||
className="text-gray-600 border rounded-lg p-2 w-full"
|
|
||||||
type="text"
|
|
||||||
value={location}
|
|
||||||
onChange={(e) => setLocalisation(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={verif}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-5">
|
|
||||||
<label className="block mb-2 text-sm font-medium text-gray-900">
|
|
||||||
Status :
|
|
||||||
</label>
|
|
||||||
<div className="inline-flex items-center gap-2">
|
|
||||||
<label
|
|
||||||
htmlFor="switch-component-on"
|
|
||||||
className="text-slate-600 text-sm cursor-pointer"
|
|
||||||
>
|
|
||||||
Inactive
|
|
||||||
</label>
|
|
||||||
<div className="relative inline-block w-11 h-5">
|
|
||||||
<input
|
|
||||||
id="switch-component-on"
|
|
||||||
type="checkbox"
|
|
||||||
checked={isActive}
|
|
||||||
onChange={handleStatusChange}
|
|
||||||
className="peer appearance-none w-11 h-5 bg-slate-100 rounded-full checked:bg-slate-800 cursor-pointer transition-colors duration-300"
|
|
||||||
disabled={verif}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
htmlFor="switch-component-on"
|
|
||||||
className="absolute top-0 left-0 w-5 h-5 bg-white rounded-full border border-slate-300 shadow-sm transition-transform duration-300 peer-checked:translate-x-6 peer-checked:border-slate-800 cursor-pointer"
|
|
||||||
></label>
|
|
||||||
</div>
|
|
||||||
<label
|
|
||||||
htmlFor="switch-component-on"
|
|
||||||
className="text-slate-600 text-sm cursor-pointer"
|
|
||||||
>
|
|
||||||
Active
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col mb-5 ">
|
|
||||||
<button
|
|
||||||
type={"submit"}
|
|
||||||
className="text-blue-500 hover:cursor-pointer hover:underline mb-2"
|
|
||||||
>
|
|
||||||
{!verif ? "Confirmer les informations" : "Oui je suis sûr !"}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="text-red-500 hover:cursor-pointer hover:underline"
|
|
||||||
onClick={handleCancel}
|
|
||||||
>
|
|
||||||
{!verif ? "Supprimer les informations" : "Non je veux changer !"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p className={(enregistre)?("text-green-700"):("text-red-700")}>
|
|
||||||
{messRequete}
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user