Merge remote-tracking branch 'origin/main' into ruben
This commit is contained in:
commit
40249d000e
@ -30,8 +30,9 @@ public class AuthHandler {
|
|||||||
String email = body.getString("email");
|
String email = body.getString("email");
|
||||||
String gender = body.getString("gender");
|
String gender = body.getString("gender");
|
||||||
String password = body.getString("password");
|
String password = body.getString("password");
|
||||||
|
String pseudo = body.getString("pseudo");
|
||||||
|
|
||||||
if (name == null || surname == null || email == null || gender == null || password == null) {
|
if (name == null || surname == null || email == null || gender == null || password == null || pseudo == null) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(400)
|
.setStatusCode(400)
|
||||||
.end(new JsonObject().put("error", "Tous les champs sont requis").encode());
|
.end(new JsonObject().put("error", "Tous les champs sont requis").encode());
|
||||||
@ -41,8 +42,8 @@ public class AuthHandler {
|
|||||||
String hashedPassword = BCrypt.withDefaults().hashToString(12, password.toCharArray());
|
String hashedPassword = BCrypt.withDefaults().hashToString(12, password.toCharArray());
|
||||||
|
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("INSERT INTO users (name, surname, email, gender, password) VALUES (?, ?, ?, ?, ?)")
|
.preparedQuery("INSERT INTO users (name, surname, email, gender, password, pseudo) VALUES (?, ?, ?, ?, ?, ?)")
|
||||||
.execute(Tuple.of(name, surname, email, gender, hashedPassword))
|
.execute(Tuple.of(name, surname, email, gender, hashedPassword,pseudo))
|
||||||
.onSuccess(result -> {
|
.onSuccess(result -> {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(201)
|
.setStatusCode(201)
|
||||||
@ -77,7 +78,7 @@ public class AuthHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("SELECT password,points FROM users WHERE email = ?")
|
.preparedQuery("SELECT id,name, surname, password, points FROM users WHERE email = ?") // Ajout de name et surname
|
||||||
.execute(Tuple.of(email))
|
.execute(Tuple.of(email))
|
||||||
.onSuccess(result -> {
|
.onSuccess(result -> {
|
||||||
if (result.rowCount() == 0) {
|
if (result.rowCount() == 0) {
|
||||||
@ -87,22 +88,32 @@ public class AuthHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String storedHashedPassword = result.iterator().next().getString("password");
|
var row = result.iterator().next();
|
||||||
Integer nbPointsUser = result.iterator().next().getInteger("points");
|
Integer id = row.getInteger("id");
|
||||||
|
String storedHashedPassword = row.getString("password");
|
||||||
|
Integer nbPointsUser = row.getInteger("points");
|
||||||
|
String name = row.getString("name");
|
||||||
|
String surname = row.getString("surname");
|
||||||
|
|
||||||
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);
|
JsonObject claims = new JsonObject()
|
||||||
if(nbPointsUser<=60){
|
.put("sub", email)
|
||||||
|
.put("name", name)
|
||||||
|
.put("surname", surname)
|
||||||
|
.put("id", id);
|
||||||
|
|
||||||
|
if (nbPointsUser <= 60) {
|
||||||
claims.put("role", "user");
|
claims.put("role", "user");
|
||||||
}else if(nbPointsUser<=100){
|
} else if (nbPointsUser <= 100) {
|
||||||
claims.put("role", "complexe");
|
claims.put("role", "complexe");
|
||||||
}else if(nbPointsUser>=200){
|
} else if (nbPointsUser >= 200) {
|
||||||
claims.put("role", "admin");
|
claims.put("role", "admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
String token = jwtAuth.generateToken(claims);
|
String token = jwtAuth.generateToken(claims);
|
||||||
|
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(200)
|
.setStatusCode(200)
|
||||||
.end(new JsonObject().put("token", token).encode());
|
.end(new JsonObject().put("token", token).encode());
|
||||||
@ -118,5 +129,4 @@ public class AuthHandler {
|
|||||||
.setStatusCode(500)
|
.setStatusCode(500)
|
||||||
.end(new JsonObject().put("error", "Erreur serveur").encode());
|
.end(new JsonObject().put("error", "Erreur serveur").encode());
|
||||||
});
|
});
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
@ -43,11 +43,12 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
SetUser setUser = new SetUser(databaseService);
|
SetUser setUser = new SetUser(databaseService);
|
||||||
setObjects.setUserHandler(setUser);
|
setObjects.setUserHandler(setUser);
|
||||||
queryObjects.setUserHandler(setUser);
|
queryObjects.setUserHandler(setUser);
|
||||||
|
setWeatherData.setUserHandler(setUser);
|
||||||
|
|
||||||
|
|
||||||
// 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.post("/objet").handler(queryObjects::getParticularObject);
|
||||||
router.post("/modifObjet").handler(setObjects::setInfoObjet);
|
router.post("/modifObjet").handler(setObjects::setInfoObjet);
|
||||||
router.get("/wind").handler(queryWeather::getWindInfos);
|
router.get("/wind").handler(queryWeather::getWindInfos);
|
||||||
router.get("/meteo").handler(queryWeather::getMeteoInfos);
|
router.get("/meteo").handler(queryWeather::getMeteoInfos);
|
||||||
@ -56,13 +57,18 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
|
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
|
||||||
router.post("/deleteObject").handler(setObjects::deleteObject);
|
router.post("/deleteObject").handler(setObjects::deleteObject);
|
||||||
router.get("/users").handler(queryUsers::getUsers);
|
router.get("/users").handler(queryUsers::getUsers);
|
||||||
|
router.post("/user").handler(queryUsers::getUser);
|
||||||
router.post("/setUserPoints").handler(setUser::setUserPoints);
|
router.post("/setUserPoints").handler(setUser::setUserPoints);
|
||||||
router.post("/deleteUser").handler(setUser::deleteUser);
|
router.post("/deleteUser").handler(setUser::deleteUser);
|
||||||
|
router.post("/updateProfil").handler(setUser::updateUserProfile);
|
||||||
|
router.post("/changePassword").handler(setUser::changeUserPassword);
|
||||||
|
router.post("/publicUser").handler(queryUsers::getPublicUser);
|
||||||
|
router.get("/getCategories").handler(queryObjects::getCategories);
|
||||||
// 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)
|
||||||
|
|||||||
@ -40,10 +40,37 @@ public class QueryObjects {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void getCategories(RoutingContext context) {
|
||||||
|
databaseService.pool
|
||||||
|
.query("SELECT DISTINCT type FROM weather_objects;")
|
||||||
|
.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 types = new JsonArray();
|
||||||
|
rows.forEach(row -> types.add(row.getString("type")));
|
||||||
|
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json; charset=UTF-8")
|
||||||
|
.end(types.encode());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void getParticularObject(RoutingContext context) {
|
public void getParticularObject(RoutingContext context) {
|
||||||
String id = context.request().getParam("id");
|
JsonObject body = context.body().asJsonObject();
|
||||||
// Integer idUser = body.getInteger("idUser");
|
if (body == null) {
|
||||||
Integer idUser = 4;
|
context.response()
|
||||||
|
.setStatusCode(400)
|
||||||
|
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String id = body.getString("id");
|
||||||
|
|
||||||
|
String idUser = body.getString("userId");
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(400)
|
.setStatusCode(400)
|
||||||
@ -66,10 +93,13 @@ public class QueryObjects {
|
|||||||
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (idUser != null) {
|
System.out.println(idUser);
|
||||||
setUser.updateUserPoints(idUser, 1);
|
|
||||||
|
Boolean shouldUpdatePoints = body.getBoolean("shouldUpdatePoints", false);
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(shouldUpdatePoints) && idUser != null) {
|
||||||
|
setUser.updateUserPoints(Integer.parseInt(idUser), 1);
|
||||||
}
|
}
|
||||||
;
|
|
||||||
context.response()
|
context.response()
|
||||||
.putHeader("content-type", "application/json: charset=UTF-8")
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
.end(getInfosObjects(rows).encode());
|
.end(getInfosObjects(rows).encode());
|
||||||
@ -91,7 +121,7 @@ public class QueryObjects {
|
|||||||
.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"));
|
.put("proprio_id", row.getInteger("proprio_id"));
|
||||||
objects.add(object);
|
objects.add(object);
|
||||||
}
|
}
|
||||||
return objects;
|
return objects;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import io.vertx.core.json.JsonArray;
|
|||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.sqlclient.Row;
|
import io.vertx.sqlclient.Row;
|
||||||
|
import io.vertx.sqlclient.Tuple;
|
||||||
|
|
||||||
public class QueryUsers {
|
public class QueryUsers {
|
||||||
private DatabaseService databaseService;
|
private DatabaseService databaseService;
|
||||||
@ -25,19 +26,20 @@ public class QueryUsers {
|
|||||||
.onSuccess(rows -> {
|
.onSuccess(rows -> {
|
||||||
JsonArray users = new JsonArray();
|
JsonArray users = new JsonArray();
|
||||||
for (Row row : rows) {
|
for (Row row : rows) {
|
||||||
int points=row.getInteger("points");
|
int points = row.getInteger("points");
|
||||||
JsonObject user = new JsonObject()
|
JsonObject user = new JsonObject()
|
||||||
.put("id", row.getInteger("id"))
|
.put("id", row.getInteger("id"))
|
||||||
.put("name", row.getString("name"))
|
.put("name", row.getString("name"))
|
||||||
.put("surname", row.getString("surname"))
|
.put("surname", row.getString("surname"))
|
||||||
.put("email", row.getString("email"))
|
.put("email", row.getString("email"))
|
||||||
.put("gender", row.getString("gender"))
|
.put("gender", row.getString("gender"))
|
||||||
.put("points",points);
|
.put("pseudo",row.getString("pseudo"))
|
||||||
if(points<=60){
|
.put("points", points);
|
||||||
|
if (points <= 60) {
|
||||||
user.put("role", "user");
|
user.put("role", "user");
|
||||||
}else if(points<=100){
|
} else if (points <= 100) {
|
||||||
user.put("role", "complexe");
|
user.put("role", "complexe");
|
||||||
}else if(points>=200){
|
} else if (points >= 200) {
|
||||||
user.put("role", "admin");
|
user.put("role", "admin");
|
||||||
}
|
}
|
||||||
users.add(user);
|
users.add(user);
|
||||||
@ -48,4 +50,102 @@ public class QueryUsers {
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void getUser(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 idUser = body.getInteger("id");
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery("SELECT * FROM users WHERE id=?;")
|
||||||
|
.execute(Tuple.of(idUser))
|
||||||
|
.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.size() == 0) {
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(404)
|
||||||
|
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row row = rows.iterator().next();
|
||||||
|
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("pseudo",row.getString("pseudo"))
|
||||||
|
.put("points", points);
|
||||||
|
|
||||||
|
if (points <= 60) {
|
||||||
|
user.put("role", "user");
|
||||||
|
} else if (points <= 100) {
|
||||||
|
user.put("role", "complexe");
|
||||||
|
} else if (points >= 200) {
|
||||||
|
user.put("role", "admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json; charset=UTF-8")
|
||||||
|
.end(user.encode());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public void getPublicUser(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 idUser = body.getInteger("id");
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery("SELECT * FROM users WHERE id=?;")
|
||||||
|
.execute(Tuple.of(idUser))
|
||||||
|
.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.size() == 0) {
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(404)
|
||||||
|
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row row = rows.iterator().next();
|
||||||
|
int points = row.getInteger("points");
|
||||||
|
JsonObject user = new JsonObject()
|
||||||
|
.put("id", row.getInteger("id"))
|
||||||
|
.put("gender", row.getString("gender"))
|
||||||
|
.put("pseudo",row.getString("pseudo"))
|
||||||
|
.put("points", points);
|
||||||
|
|
||||||
|
if (points <= 60) {
|
||||||
|
user.put("role", "user");
|
||||||
|
} else if (points <= 100) {
|
||||||
|
user.put("role", "complexe");
|
||||||
|
} else if (points >= 200) {
|
||||||
|
user.put("role", "admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json; charset=UTF-8")
|
||||||
|
.end(user.encode());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,12 +7,15 @@ import io.vertx.sqlclient.Tuple;
|
|||||||
public class SetObjects {
|
public class SetObjects {
|
||||||
private DatabaseService databaseService;
|
private DatabaseService databaseService;
|
||||||
private SetUser setUser;
|
private SetUser setUser;
|
||||||
|
|
||||||
public SetObjects(DatabaseService ddbs) {
|
public SetObjects(DatabaseService ddbs) {
|
||||||
this.databaseService = ddbs;
|
this.databaseService = ddbs;
|
||||||
}
|
}
|
||||||
public void setUserHandler(SetUser setUser){
|
|
||||||
|
public void setUserHandler(SetUser setUser) {
|
||||||
this.setUser = setUser;
|
this.setUser = setUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInfoObjet(RoutingContext context) {
|
public void setInfoObjet(RoutingContext context) {
|
||||||
JsonObject body = context.body().asJsonObject();
|
JsonObject body = context.body().asJsonObject();
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
@ -22,8 +25,7 @@ public class SetObjects {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Integer id = body.getInteger("id");
|
Integer id = body.getInteger("id");
|
||||||
// Integer idUser = body.getInteger("idUser");
|
Integer idUser = body.getInteger("idUser");
|
||||||
Integer idUser = 4;
|
|
||||||
String description = body.getString("description");
|
String description = body.getString("description");
|
||||||
String type = body.getString("type");
|
String type = body.getString("type");
|
||||||
String location = body.getString("location");
|
String location = body.getString("location");
|
||||||
@ -46,85 +48,90 @@ public class SetObjects {
|
|||||||
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(idUser!=null){
|
Boolean shouldUpdatePoints = body.getBoolean("shouldUpdatePoints", false);
|
||||||
setUser.updateUserPoints(idUser,1);
|
|
||||||
};
|
if (Boolean.TRUE.equals(shouldUpdatePoints) && idUser != null) {
|
||||||
|
setUser.updateUserPoints(idUser, 1);
|
||||||
|
}
|
||||||
context.response()
|
context.response()
|
||||||
.putHeader("content-type", "application/json: charset=UTF-8")
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
.end(new JsonObject().put("success", "L'objet à bien été mis à jour").encode());
|
.end(new JsonObject().put("success", "L'objet à bien été mis à jour").encode());
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public void deleteObject(RoutingContext context){
|
|
||||||
|
public void deleteObject(RoutingContext context) {
|
||||||
JsonObject body = context.body().asJsonObject();
|
JsonObject body = context.body().asJsonObject();
|
||||||
if(body== null){
|
if (body == null) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(400)
|
.setStatusCode(400)
|
||||||
.end(new JsonObject().put("error","Corps de la requête manquant").encode());
|
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String id = body.getString("id");
|
String id = body.getString("id");
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("DELETE FROM weather_objects WHERE id=?")
|
.preparedQuery("DELETE FROM weather_objects WHERE id=?")
|
||||||
.execute(Tuple.of(Integer.parseInt(id)))
|
.execute(Tuple.of(Integer.parseInt(id)))
|
||||||
.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()
|
||||||
.setStatusCode(500)
|
.setStatusCode(500)
|
||||||
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
|
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
|
||||||
})
|
})
|
||||||
.onSuccess(rows -> {
|
.onSuccess(rows -> {
|
||||||
if(rows.rowCount()==0){
|
if (rows.rowCount() == 0) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(404)
|
.setStatusCode(404)
|
||||||
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.response()
|
context.response()
|
||||||
.putHeader("content-type","application/json: charset=UTF-8")
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
.end(new JsonObject().put("success", "L'objet à bien été supprimé").encode());
|
.end(new JsonObject().put("success", "L'objet à bien été supprimé").encode());
|
||||||
return;
|
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) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(400)
|
.setStatusCode(400)
|
||||||
.end(new JsonObject().put("error","Corps de la requête manquant").encode());
|
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Integer idUser = body.getInteger("idUser");
|
Integer idUser = body.getInteger("proprio_id");
|
||||||
Integer idUser = 4;
|
|
||||||
String name = body.getString("nom");
|
String name = body.getString("nom");
|
||||||
String description = body.getString("description");
|
String description = body.getString("description");
|
||||||
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 batterieType = body.getString("batterieType");
|
||||||
String proprio = body.getString("proprio");
|
Integer proprio_id = body.getInteger("proprio_id");
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("INSERT INTO weather_objects (name,description,type,location,status,type_batterie,proprio) VALUES (?,?,?,?,?,?,?)")
|
.preparedQuery(
|
||||||
.execute(Tuple.of(name,description,type,location,status,batterieType,proprio))
|
"INSERT INTO weather_objects (name,description,type,location,status,type_batterie,proprio_id) VALUES (?,?,?,?,?,?,?)")
|
||||||
.onFailure(e->{
|
.execute(Tuple.of(name, description, type, location, status, batterieType, proprio_id))
|
||||||
System.err.println("Erreur de récupération de la BDD :"+e.getMessage());
|
.onFailure(e -> {
|
||||||
|
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(500)
|
.setStatusCode(500)
|
||||||
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
|
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
|
||||||
})
|
})
|
||||||
.onSuccess(rows -> {
|
.onSuccess(rows -> {
|
||||||
if(rows.rowCount()==0){
|
if (rows.rowCount() == 0) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(404)
|
.setStatusCode(404)
|
||||||
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
.end(new JsonObject().put("error", "Objet non trouvé").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(idUser!=null){
|
if (idUser != null) {
|
||||||
setUser.updateUserPoints(idUser,2);
|
setUser.updateUserPoints(idUser, 2);
|
||||||
};
|
}
|
||||||
|
;
|
||||||
context.response()
|
context.response()
|
||||||
.putHeader("content-type","application/json: charset=UTF-8")
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
.end(new JsonObject().put("success", "L'objet à bien été ajouté").encode());
|
.end(new JsonObject().put("success", "L'objet à bien été ajouté").encode());
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.example.starter;
|
package com.example.starter;
|
||||||
|
|
||||||
|
import at.favre.lib.crypto.bcrypt.BCrypt;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.sqlclient.Tuple;
|
import io.vertx.sqlclient.Tuple;
|
||||||
@ -10,6 +11,7 @@ public class SetUser {
|
|||||||
public SetUser(DatabaseService ddbs) {
|
public SetUser(DatabaseService ddbs) {
|
||||||
this.databaseService = ddbs;
|
this.databaseService = ddbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateUserPoints(Integer userId, Integer points) {
|
public void updateUserPoints(Integer userId, Integer points) {
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("UPDATE users SET points=points+? WHERE id=?")
|
.preparedQuery("UPDATE users SET points=points+? WHERE id=?")
|
||||||
@ -25,6 +27,105 @@ public class SetUser {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void changeUserPassword(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");
|
||||||
|
String oldPassword = body.getString("oldPassword");
|
||||||
|
String newPassword = body.getString("newPassword");
|
||||||
|
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery("SELECT password FROM users WHERE id=?")
|
||||||
|
.execute(Tuple.of(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", "Utilisateur non trouvé").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentPassword = rows.iterator().next().getString("password");
|
||||||
|
BCrypt.Result verification = BCrypt.verifyer().verify(oldPassword.toCharArray(), currentPassword);
|
||||||
|
|
||||||
|
if (!verification.verified) {
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(401)
|
||||||
|
.end(new JsonObject().put("error", "Ancien mot de passe incorrect").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String hashedPassword = BCrypt.withDefaults().hashToString(12, newPassword.toCharArray());
|
||||||
|
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery("UPDATE users SET password=? WHERE id=?")
|
||||||
|
.execute(Tuple.of(hashedPassword, id))
|
||||||
|
.onFailure(e -> {
|
||||||
|
System.err.println("Erreur lors de la mise à jour du mot de passe :" + e.getMessage());
|
||||||
|
context.response()
|
||||||
|
.setStatusCode(500)
|
||||||
|
.end(new JsonObject()
|
||||||
|
.put("error", "Erreur lors de la mise à jour du mot de passe")
|
||||||
|
.encode());
|
||||||
|
})
|
||||||
|
.onSuccess(updateRows -> {
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
|
.end(new JsonObject().put("success", "Le mot de passe a bien été mis à jour")
|
||||||
|
.encode());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUserProfile(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");
|
||||||
|
String name = body.getString("name");
|
||||||
|
String surname = body.getString("surname");
|
||||||
|
String pseudo = body.getString("pseudo");
|
||||||
|
|
||||||
|
databaseService.pool
|
||||||
|
.preparedQuery("UPDATE users SET name=?, surname=?, pseudo=? WHERE id=?")
|
||||||
|
.execute(Tuple.of(name, surname,pseudo, 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", "Utilisateur non trouvé").encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.response()
|
||||||
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
|
.end(new JsonObject()
|
||||||
|
.put("success", "Les informations de l'utilisateur ont bien été mises à jour")
|
||||||
|
.encode());
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void setUserPoints(RoutingContext context) {
|
public void setUserPoints(RoutingContext context) {
|
||||||
JsonObject body = context.body().asJsonObject();
|
JsonObject body = context.body().asJsonObject();
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
@ -59,33 +160,34 @@ public class SetUser {
|
|||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public void deleteUser(RoutingContext context){
|
|
||||||
|
public void deleteUser(RoutingContext context) {
|
||||||
JsonObject body = context.body().asJsonObject();
|
JsonObject body = context.body().asJsonObject();
|
||||||
if(body== null){
|
if (body == null) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(400)
|
.setStatusCode(400)
|
||||||
.end(new JsonObject().put("error","Corps de la requête manquant").encode());
|
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Integer id = body.getInteger("id");
|
Integer id = body.getInteger("id");
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery("DELETE FROM users WHERE id=?")
|
.preparedQuery("DELETE FROM users WHERE id=?")
|
||||||
.execute(Tuple.of(id))
|
.execute(Tuple.of(id))
|
||||||
.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()
|
||||||
.setStatusCode(500)
|
.setStatusCode(500)
|
||||||
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
|
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
|
||||||
})
|
})
|
||||||
.onSuccess(rows -> {
|
.onSuccess(rows -> {
|
||||||
if(rows.rowCount()==0){
|
if (rows.rowCount() == 0) {
|
||||||
context.response()
|
context.response()
|
||||||
.setStatusCode(404)
|
.setStatusCode(404)
|
||||||
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
|
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.response()
|
context.response()
|
||||||
.putHeader("content-type","application/json: charset=UTF-8")
|
.putHeader("content-type", "application/json: charset=UTF-8")
|
||||||
.end(new JsonObject().put("success", "L'utilisateur à bien été supprimé").encode());
|
.end(new JsonObject().put("success", "L'utilisateur à bien été supprimé").encode());
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -41,8 +41,8 @@ public class SetWeatherData {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String query = String.format("UPDATE range_data SET %s_min=?, %s_max=? WHERE station_id=?", type, type);
|
String query = String.format("UPDATE range_data SET %s_min=?, %s_max=? WHERE station_id=?", type, type);
|
||||||
// Integer idUser = body.getInteger("idUser");
|
Integer idUser = body.getInteger("idUser");
|
||||||
Integer idUser = 4;
|
System.out.println("User : "+idUser);
|
||||||
databaseService.pool
|
databaseService.pool
|
||||||
.preparedQuery(
|
.preparedQuery(
|
||||||
query)
|
query)
|
||||||
|
|||||||
127
Front-end/package-lock.json
generated
127
Front-end/package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@mui/material": "^7.0.1",
|
"@mui/material": "^7.0.1",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"lucide-react": "^0.427.0",
|
"lucide-react": "^0.427.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-charts": "^3.0.0-beta.57",
|
"react-charts": "^3.0.0-beta.57",
|
||||||
@ -2070,7 +2071,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||||
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
|
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
@ -2819,6 +2819,71 @@
|
|||||||
"is-arrayish": "^0.2.1"
|
"is-arrayish": "^0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-abstract": {
|
||||||
|
"version": "1.23.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
|
||||||
|
"integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"array-buffer-byte-length": "^1.0.2",
|
||||||
|
"arraybuffer.prototype.slice": "^1.0.4",
|
||||||
|
"available-typed-arrays": "^1.0.7",
|
||||||
|
"call-bind": "^1.0.8",
|
||||||
|
"call-bound": "^1.0.3",
|
||||||
|
"data-view-buffer": "^1.0.2",
|
||||||
|
"data-view-byte-length": "^1.0.2",
|
||||||
|
"data-view-byte-offset": "^1.0.1",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.0.0",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"es-to-primitive": "^1.3.0",
|
||||||
|
"function.prototype.name": "^1.1.8",
|
||||||
|
"get-intrinsic": "^1.2.7",
|
||||||
|
"get-proto": "^1.0.0",
|
||||||
|
"get-symbol-description": "^1.1.0",
|
||||||
|
"globalthis": "^1.0.4",
|
||||||
|
"gopd": "^1.2.0",
|
||||||
|
"has-property-descriptors": "^1.0.2",
|
||||||
|
"has-proto": "^1.2.0",
|
||||||
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"internal-slot": "^1.1.0",
|
||||||
|
"is-array-buffer": "^3.0.5",
|
||||||
|
"is-callable": "^1.2.7",
|
||||||
|
"is-data-view": "^1.0.2",
|
||||||
|
"is-regex": "^1.2.1",
|
||||||
|
"is-shared-array-buffer": "^1.0.4",
|
||||||
|
"is-string": "^1.1.1",
|
||||||
|
"is-typed-array": "^1.1.15",
|
||||||
|
"is-weakref": "^1.1.0",
|
||||||
|
"math-intrinsics": "^1.1.0",
|
||||||
|
"object-inspect": "^1.13.3",
|
||||||
|
"object-keys": "^1.1.1",
|
||||||
|
"object.assign": "^4.1.7",
|
||||||
|
"own-keys": "^1.0.1",
|
||||||
|
"regexp.prototype.flags": "^1.5.3",
|
||||||
|
"safe-array-concat": "^1.1.3",
|
||||||
|
"safe-push-apply": "^1.0.0",
|
||||||
|
"safe-regex-test": "^1.1.0",
|
||||||
|
"set-proto": "^1.0.0",
|
||||||
|
"string.prototype.trim": "^1.2.10",
|
||||||
|
"string.prototype.trimend": "^1.0.9",
|
||||||
|
"string.prototype.trimstart": "^1.0.8",
|
||||||
|
"typed-array-buffer": "^1.0.3",
|
||||||
|
"typed-array-byte-length": "^1.0.3",
|
||||||
|
"typed-array-byte-offset": "^1.0.4",
|
||||||
|
"typed-array-length": "^1.0.7",
|
||||||
|
"unbox-primitive": "^1.1.0",
|
||||||
|
"which-typed-array": "^1.1.18"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/es-define-property": {
|
"node_modules/es-define-property": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
@ -3788,12 +3853,63 @@
|
|||||||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
|
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-array-buffer": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.8",
|
||||||
|
"call-bound": "^1.0.3",
|
||||||
|
"get-intrinsic": "^1.2.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
|
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-async-function": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"async-function": "^1.0.0",
|
||||||
|
"call-bound": "^1.0.3",
|
||||||
|
"get-proto": "^1.0.1",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"safe-regex-test": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-bigint": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"has-bigints": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@ -4269,6 +4385,15 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jwt-decode": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@mui/material": "^7.0.1",
|
"@mui/material": "^7.0.1",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"lucide-react": "^0.427.0",
|
"lucide-react": "^0.427.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-charts": "^3.0.0-beta.57",
|
"react-charts": "^3.0.0-beta.57",
|
||||||
|
|||||||
@ -9,12 +9,12 @@ import Objet from "./pages/Gestion/Objet.jsx";
|
|||||||
import AddObject from "./pages/Gestion/AddObject.jsx";
|
import AddObject from "./pages/Gestion/AddObject.jsx";
|
||||||
import Signup from "./pages/Signup.jsx";
|
import Signup from "./pages/Signup.jsx";
|
||||||
import Login from "./pages/Login.jsx";
|
import Login from "./pages/Login.jsx";
|
||||||
import Settings from "./pages/Settings.jsx";
|
import Profil from "./pages/Profil.jsx";
|
||||||
import Sidebar from "./pages/Admin/sidebar.jsx";
|
import Sidebar from "./pages/Admin/sidebar.jsx";
|
||||||
import User from "./pages/Admin/User.jsx";
|
import User from "./pages/Admin/User.jsx";
|
||||||
import Dashboard from "./pages/Admin/Dashboard.jsx";
|
import Dashboard from "./pages/Admin/Dashboard.jsx";
|
||||||
import AdminObjet from "./pages/Admin/AdminObjet.jsx";
|
import AdminObjet from "./pages/Admin/AdminObjet.jsx";
|
||||||
import ProtectedRoute from './ProtectedRoute.jsx'; // Correction de l'import
|
import ProtectedRoute from "./ProtectedRoute.jsx";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
@ -23,19 +23,27 @@ function App() {
|
|||||||
<div>
|
<div>
|
||||||
<Header />
|
<Header />
|
||||||
<Routes>
|
<Routes>
|
||||||
|
{/* Routes publiques */}
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/about" element={<About />} />
|
<Route path="/about" element={<About />} />
|
||||||
<Route path="/gestion" element={<ProtectedRoute element={<Gestion />} />} />
|
|
||||||
<Route path="/gestionObjets" element={<ProtectedRoute element={<ObjectManagement />} />} />
|
|
||||||
<Route path="/objet" element={<ProtectedRoute element={<Objet />} />} />
|
|
||||||
<Route path="/signup" element={<Signup />} />
|
<Route path="/signup" element={<Signup />} />
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
<Route path="/ajouterObjet" element={<ProtectedRoute element={<AddObject />} />} />
|
|
||||||
<Route path="/settings" element={<Settings />} />
|
{/* Routes protégées pour tous les utilisateurs connectés */}
|
||||||
<Route path="/sidebar" element={<Sidebar />} />
|
<Route path="/gestion" element={<ProtectedRoute element={<Gestion />} allowedRoles={['admin', 'complexe', 'user']} />} />
|
||||||
<Route path="/user" element={<User />} />
|
<Route path="/gestionObjets" element={<ProtectedRoute element={<ObjectManagement />} allowedRoles={['admin', 'complexe', 'user']} />} />
|
||||||
<Route path="/dashboard" element={<Dashboard />} />
|
<Route path="/objet" element={<ProtectedRoute element={<Objet />} allowedRoles={['admin', 'complexe', 'user']} />} />
|
||||||
<Route path="/adminobjet" element={<ProtectedRoute element={<AdminObjet />} />} />
|
|
||||||
|
{/* Routes protégées pour les admins et complexes */}
|
||||||
|
<Route path="/ajouterObjet" element={<ProtectedRoute element={<AddObject />} allowedRoles={['admin', 'complexe']} />} />
|
||||||
|
<Route path="/profil" element={<ProtectedRoute element={<Profil />} allowedRoles={['admin', 'complexe','user']} />} />
|
||||||
|
|
||||||
|
{/* Routes protégées pour tous les utilisateurs connectés */}
|
||||||
|
<Route path="/sidebar" element={<ProtectedRoute element={<Sidebar />} allowedRoles={['admin', 'complexe', 'user']} />} />
|
||||||
|
<Route path="/user" element={<ProtectedRoute element={<User />} allowedRoles={['admin', 'complexe', 'user']} />} />
|
||||||
|
{/* Routes protégées pour les admins uniquement */}
|
||||||
|
<Route path="/dashboard" element={<ProtectedRoute element={<Dashboard />} allowedRoles={['admin']} />} />
|
||||||
|
<Route path="/adminobjet" element={<ProtectedRoute element={<AdminObjet />} allowedRoles={['admin']} />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
</Router>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// src/AuthContext.js
|
|
||||||
import React, { createContext, useContext, useState, useEffect } from "react";
|
import React, { createContext, useContext, useState, useEffect } from "react";
|
||||||
|
import { jwtDecode } from "jwt-decode";
|
||||||
|
|
||||||
|
|
||||||
// Créer le contexte
|
// Créer le contexte
|
||||||
const AuthContext = createContext();
|
const AuthContext = createContext();
|
||||||
@ -7,22 +8,25 @@ const AuthContext = createContext();
|
|||||||
// Hook pour accéder facilement au contexte
|
// Hook pour accéder facilement au contexte
|
||||||
export const useAuth = () => useContext(AuthContext);
|
export const useAuth = () => useContext(AuthContext);
|
||||||
|
|
||||||
// Fournisseur de contexte qui gère l'état du token
|
// Fournisseur de contexte qui gère l'état du token et de l'utilisateur
|
||||||
export const AuthProvider = ({ children }) => {
|
export const AuthProvider = ({ children }) => {
|
||||||
const [token, setToken] = useState(localStorage.getItem("token"));
|
const [token, setToken] = useState(localStorage.getItem("token"));
|
||||||
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
// Met à jour le token lorsque localStorage change
|
// Met à jour le token et décode l'utilisateur
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleStorageChange = () => {
|
if (token) {
|
||||||
setToken(localStorage.getItem("token"));
|
try {
|
||||||
};
|
const decoded = jwtDecode(token);
|
||||||
|
setUser(decoded);
|
||||||
window.addEventListener("storage", handleStorageChange);
|
} catch (error) {
|
||||||
|
console.error("Erreur lors du décodage du token:", error);
|
||||||
return () => {
|
setUser(null);
|
||||||
window.removeEventListener("storage", handleStorageChange);
|
}
|
||||||
};
|
} else {
|
||||||
}, []);
|
setUser(null);
|
||||||
|
}
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
const login = (newToken) => {
|
const login = (newToken) => {
|
||||||
localStorage.setItem("token", newToken);
|
localStorage.setItem("token", newToken);
|
||||||
@ -32,10 +36,11 @@ export const AuthProvider = ({ children }) => {
|
|||||||
const logout = () => {
|
const logout = () => {
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
setToken(null);
|
setToken(null);
|
||||||
|
setUser(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider value={{ token, login, logout }}>
|
<AuthContext.Provider value={{ token, user, login, logout }}>
|
||||||
{children}
|
{children}
|
||||||
</AuthContext.Provider>
|
</AuthContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
import { useAuth } from './AuthContext'; // Utilisation du contexte d'authentification
|
import React from "react";
|
||||||
import { Navigate } from 'react-router-dom'; // Utilisation de React Router pour la redirection
|
import { Navigate } from "react-router-dom";
|
||||||
|
import { useAuth } from "./AuthContext"; // Utilisation du contexte d'authentification
|
||||||
|
|
||||||
function ProtectedRoute({ element }) {
|
function ProtectedRoute({ element, allowedRoles }) {
|
||||||
const { token } = useAuth(); // Vérifier si un token existe, donc si l'utilisateur est authentifié
|
const { token, user } = useAuth(); // Vérifier si un token existe, donc si l'utilisateur est authentifié
|
||||||
|
|
||||||
// Si l'utilisateur n'est pas authentifié, redirigez-le vers la page de login
|
// Si l'utilisateur n'est pas authentifié, redirigez-le vers la page de login
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return <Navigate to="/login" />;
|
return <Navigate to="/login" />;
|
||||||
}
|
}
|
||||||
|
if(user){
|
||||||
// Si l'utilisateur est authentifié, permettez l'accès à la route
|
if (allowedRoles && !allowedRoles.includes(user?.role)) {
|
||||||
|
return <Navigate to="/" />;
|
||||||
|
}
|
||||||
return element;
|
return element;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProtectedRoute; // Export de la fonction
|
export default ProtectedRoute;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import { TriangleAlert,X } from "lucide-react";
|
import { TriangleAlert,X } from "lucide-react";
|
||||||
|
import { useAuth } from "../AuthContext";
|
||||||
|
|
||||||
function AlertInactive({affAlert,setAffAlert}) {
|
function AlertInactive({affAlert,setAffAlert}) {
|
||||||
|
const { user } = useAuth();
|
||||||
return (
|
return (
|
||||||
(affAlert&&(
|
(affAlert&&(user?.role!=="user")&&(
|
||||||
<div className="flex flex-col md:flex-row bg-slate-600 w-full md:w-1/2 lg:w-1/3 fixed top-20 right-1 sm:right-4 rounded-lg p-4 md:p-5 items-center gap-4 md:gap-6 shadow-lg opacity-90">
|
<div className="flex flex-col md:flex-row bg-slate-600 w-full md:w-1/2 lg:w-1/3 fixed top-20 right-1 sm:right-4 rounded-lg p-4 md:p-5 items-center gap-4 md:gap-6 shadow-lg opacity-90">
|
||||||
<button onClick={()=>setAffAlert(false)}className="absolute top-2 right-2 text-white hover:text-gray-300">
|
<button onClick={()=>setAffAlert(false)}className="absolute top-2 right-2 text-white hover:text-gray-300">
|
||||||
<X/>
|
<X/>
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { BadgePlus } from "lucide-react";
|
import { BadgePlus } from "lucide-react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { API_BASE_URL } from "../config";
|
import { API_BASE_URL } from "../config";
|
||||||
|
import { useAuth } from "../AuthContext";
|
||||||
|
|
||||||
function FormNewObject({ isAdmin }) {
|
function FormNewObject({ isAdmin }) {
|
||||||
|
const { user } = useAuth();
|
||||||
|
const [categorie, setCategorie] = useState({});
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [type, setType] = useState("");
|
const [type, setType] = useState("");
|
||||||
const [location, setLocalisation] = useState("");
|
const [location, setLocalisation] = useState("");
|
||||||
const [proprio,setProprio] = useState("");
|
const [proprio_id, setProprio_id] = useState(user?.id);
|
||||||
const [batterieType,setBatterieType] = useState("");
|
const [batterieType, setBatterieType] = useState("");
|
||||||
/*TODO*/
|
|
||||||
/*Definir proprio avec le nom de l'user qui ajoute*/
|
|
||||||
const [status, setStatus] = useState("active");
|
const [status, setStatus] = useState("active");
|
||||||
const [nom, setNom] = useState("");
|
const [nom, setNom] = useState("");
|
||||||
const [Response, setResponse] = useState(null);
|
const [Response, setResponse] = useState(null);
|
||||||
@ -31,7 +32,7 @@ function FormNewObject({ isAdmin }) {
|
|||||||
location,
|
location,
|
||||||
status,
|
status,
|
||||||
batterieType,
|
batterieType,
|
||||||
proprio
|
proprio_id,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
setMessRequete("Votre objet à bien été enregistré !");
|
setMessRequete("Votre objet à bien été enregistré !");
|
||||||
@ -48,6 +49,12 @@ function FormNewObject({ isAdmin }) {
|
|||||||
setVerif(true);
|
setVerif(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
axios.get(`${API_BASE_URL}/getCategories`).then((response) => {
|
||||||
|
setCategorie(response.data);
|
||||||
|
console.log(response.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
setNom("");
|
setNom("");
|
||||||
setStatus("active");
|
setStatus("active");
|
||||||
@ -55,7 +62,7 @@ function FormNewObject({ isAdmin }) {
|
|||||||
setType("");
|
setType("");
|
||||||
setLocalisation("");
|
setLocalisation("");
|
||||||
setBatterieType("");
|
setBatterieType("");
|
||||||
if(isAdmin)setProprio("");
|
if (isAdmin) set_id("");
|
||||||
setActive(true);
|
setActive(true);
|
||||||
}
|
}
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
@ -135,15 +142,21 @@ function FormNewObject({ isAdmin }) {
|
|||||||
>
|
>
|
||||||
Type :
|
Type :
|
||||||
</label>
|
</label>
|
||||||
<input
|
<select
|
||||||
id="type"
|
id="type"
|
||||||
className="text-gray-600 border rounded-lg p-2 w-full"
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
type="text"
|
|
||||||
value={type}
|
value={type}
|
||||||
onChange={(e) => setType(e.target.value)}
|
onChange={(e) => setType(e.target.value)}
|
||||||
required
|
required
|
||||||
disabled={verif}
|
disabled={verif}
|
||||||
/>
|
>
|
||||||
|
<option value="">-- Sélectionner un type --</option>
|
||||||
|
{categorie.map((cat, index) => (
|
||||||
|
<option key={index} value={cat}>
|
||||||
|
{cat}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
@ -182,19 +195,19 @@ function FormNewObject({ isAdmin }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
<label
|
<label
|
||||||
htmlFor="proprio"
|
htmlFor="proprio_id"
|
||||||
className="block mb-2 text-sm font-medium text-gray-900"
|
className="block mb-2 text-sm font-medium text-gray-900"
|
||||||
>
|
>
|
||||||
Propriétaire :
|
Propriétaire :
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="proprio"
|
id="proprio_id"
|
||||||
className="text-gray-600 border rounded-lg p-2 w-full"
|
className="text-gray-600 border rounded-lg p-2 w-full"
|
||||||
type="text"
|
type="number"
|
||||||
value={proprio}
|
value={proprio_id}
|
||||||
onChange={(e) => setProprio(e.target.value)}
|
onChange={(e) => setProprio_id(e.target.value)}
|
||||||
required
|
required
|
||||||
disabled={verif||!isAdmin}
|
disabled={verif || !isAdmin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { X, Menu, LogIn, UserPlus, LogOut, Settings } from "lucide-react";
|
import { X, Menu, LogIn, UserPlus, LogOut, User } 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, user, logout } = useAuth();
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [showAdminDropdown, setShowAdminDropdown] = useState(false);
|
const [showAdminDropdown, setShowAdminDropdown] = useState(false);
|
||||||
|
|
||||||
@ -128,22 +128,44 @@ function Header() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
{user?.role === "user" ? (
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to="/gestionObjets"
|
||||||
|
onClick={() => setIsMenuOpen(false)}
|
||||||
|
className="text-gray-600 hover:text-indigo-600"
|
||||||
|
>
|
||||||
|
Visualisation
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
) : (
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to="/gestion"
|
||||||
|
onClick={() => setIsMenuOpen(false)}
|
||||||
|
className="text-gray-600 hover:text-indigo-600"
|
||||||
|
>
|
||||||
|
Gestion
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
<li className="sm:hidden">
|
<li className="sm:hidden">
|
||||||
<Link
|
<Link
|
||||||
to="/settings"
|
to="/profil"
|
||||||
onClick={()=>setIsMenuOpen(false)}
|
onClick={() => setIsMenuOpen(false)}
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
||||||
>
|
>
|
||||||
<Settings size={20} />
|
<User size={20} />
|
||||||
<span>Paramètres</span>
|
<span>Profil</span>
|
||||||
<span></span>
|
<span></span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className="sm:hidden">
|
<li className="sm:hidden">
|
||||||
<button
|
<button
|
||||||
onClick={()=>{
|
onClick={() => {
|
||||||
logout();
|
logout();
|
||||||
setIsMenuOpen(false)}}
|
setIsMenuOpen(false);
|
||||||
|
}}
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
||||||
>
|
>
|
||||||
<LogOut size={20} />
|
<LogOut size={20} />
|
||||||
@ -158,7 +180,7 @@ function Header() {
|
|||||||
<div className="hidden sm:flex gap-4 ">
|
<div className="hidden sm:flex gap-4 ">
|
||||||
<Link
|
<Link
|
||||||
to="/login"
|
to="/login"
|
||||||
onClick={()=>setIsMenuOpen(false)}
|
onClick={() => setIsMenuOpen(false)}
|
||||||
className="hover:text-indigo-600 flex items-center gap-2"
|
className="hover:text-indigo-600 flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<LogIn size={20} />
|
<LogIn size={20} />
|
||||||
@ -166,7 +188,7 @@ function Header() {
|
|||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
to="/signup"
|
to="/signup"
|
||||||
onClick={()=>setIsMenuOpen(false)}
|
onClick={() => setIsMenuOpen(false)}
|
||||||
className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700"
|
className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700"
|
||||||
>
|
>
|
||||||
<UserPlus size={20} />
|
<UserPlus size={20} />
|
||||||
@ -176,11 +198,12 @@ function Header() {
|
|||||||
) : (
|
) : (
|
||||||
<div className="hidden sm:flex gap-4">
|
<div className="hidden sm:flex gap-4">
|
||||||
<Link
|
<Link
|
||||||
to="/settings"
|
to="/profil"
|
||||||
onClick={()=>setIsMenuOpen(false)}
|
onClick={() => setIsMenuOpen(false)}
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
||||||
>
|
>
|
||||||
<Settings size={20} />
|
<User size={20} />
|
||||||
|
<span></span>
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
onClick={logout}
|
onClick={logout}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Info } from "lucide-react";
|
import { Info } from "lucide-react";
|
||||||
|
import { useAuth } from "../AuthContext";
|
||||||
|
|
||||||
function InfoObject({ object,defafficherModif }) {
|
function InfoObject({ object,defafficherModif }) {
|
||||||
|
const {user} = useAuth();
|
||||||
return (
|
return (
|
||||||
<div key={object.id} className="bg-white p-6 rounded-xl min-w-5xl">
|
<div key={object.id} className="bg-white p-6 rounded-xl min-w-5xl">
|
||||||
<div className="flex align-items gap-6 mb-6">
|
<div className="flex align-items gap-6 mb-6">
|
||||||
@ -36,9 +38,11 @@ function InfoObject({ object,defafficherModif }) {
|
|||||||
</p>
|
</p>
|
||||||
<p className="text-gray-600">{object.last_update}</p>
|
<p className="text-gray-600">{object.last_update}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{user?.role!=="user"&&(
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<a className="text-blue-500 hover:cursor-pointer" onClick={(()=>defafficherModif(true))}>Modifier ces infos</a>
|
<a className="text-blue-500 hover:cursor-pointer" onClick={(()=>defafficherModif(true))}>Modifier ces infos</a>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,10 @@ import React, { useState } from "react";
|
|||||||
import { Info } from "lucide-react";
|
import { Info } from "lucide-react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { API_BASE_URL } from "../config";
|
import { API_BASE_URL } from "../config";
|
||||||
|
import {useAuth} from "../AuthContext";
|
||||||
|
|
||||||
function ModifObject({ object, defafficherModif }) {
|
function ModifObject({ object, defafficherModif }) {
|
||||||
|
const {user}=useAuth();
|
||||||
const [description, setDescription] = useState(object.description || "");
|
const [description, setDescription] = useState(object.description || "");
|
||||||
const [type, setType] = useState(object.type || "");
|
const [type, setType] = useState(object.type || "");
|
||||||
const [location, setLocalisation] = useState(object.location || "");
|
const [location, setLocalisation] = useState(object.location || "");
|
||||||
@ -15,10 +17,12 @@ function ModifObject({ object, defafficherModif }) {
|
|||||||
axios
|
axios
|
||||||
.post(`${API_BASE_URL}/modifObjet`, {
|
.post(`${API_BASE_URL}/modifObjet`, {
|
||||||
id: object.id,
|
id: object.id,
|
||||||
|
idUser:user.id,
|
||||||
description,
|
description,
|
||||||
type,
|
type,
|
||||||
location,
|
location,
|
||||||
status,
|
status,
|
||||||
|
shouldUpdatePoints:true
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log("Modification réussie :", response.data);
|
console.log("Modification réussie :", response.data);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { Bell } from "lucide-react";
|
|||||||
import Slider from "@mui/material/Slider";
|
import Slider from "@mui/material/Slider";
|
||||||
import { API_BASE_URL } from "../config";
|
import { API_BASE_URL } from "../config";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { useAuth } from "../AuthContext";
|
||||||
|
|
||||||
const identifiant = new URLSearchParams(window.location.search).get("id");
|
const identifiant = new URLSearchParams(window.location.search).get("id");
|
||||||
function ParticularMeteo({
|
function ParticularMeteo({
|
||||||
@ -16,6 +17,7 @@ function ParticularMeteo({
|
|||||||
setGraphStates,
|
setGraphStates,
|
||||||
graphRefs,
|
graphRefs,
|
||||||
}) {
|
}) {
|
||||||
|
const {user} = useAuth();
|
||||||
const [affRegles, setAffRegles] = useState(false);
|
const [affRegles, setAffRegles] = useState(false);
|
||||||
const [rangeValue, setRangeValue] = useState([0, 0]);
|
const [rangeValue, setRangeValue] = useState([0, 0]);
|
||||||
const [alerteActive, setAlerteActive] = useState(false);
|
const [alerteActive, setAlerteActive] = useState(false);
|
||||||
@ -71,6 +73,7 @@ function ParticularMeteo({
|
|||||||
axios
|
axios
|
||||||
.post(`${API_BASE_URL}/modifRangeData`, {
|
.post(`${API_BASE_URL}/modifRangeData`, {
|
||||||
id: identifiant,
|
id: identifiant,
|
||||||
|
idUser:user.id,
|
||||||
min: parseFloat(rangeValue[0]),
|
min: parseFloat(rangeValue[0]),
|
||||||
max: parseFloat(rangeValue[1]),
|
max: parseFloat(rangeValue[1]),
|
||||||
type,
|
type,
|
||||||
@ -107,6 +110,7 @@ function ParticularMeteo({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
{user?.role!=="user" && (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAffRegles(!affRegles);
|
setAffRegles(!affRegles);
|
||||||
@ -117,7 +121,7 @@ function ParticularMeteo({
|
|||||||
size={30}
|
size={30}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
<BoutonGraphique
|
<BoutonGraphique
|
||||||
type={type}
|
type={type}
|
||||||
graphStates={graphStates}
|
graphStates={graphStates}
|
||||||
|
|||||||
50
Front-end/src/components/UserInfosObject.jsx
Normal file
50
Front-end/src/components/UserInfosObject.jsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React,{useEffect, useState} from "react";
|
||||||
|
import { User } from "lucide-react";
|
||||||
|
import axios from "axios";
|
||||||
|
import { API_BASE_URL } from "../config";
|
||||||
|
|
||||||
|
|
||||||
|
function UserInfosObject({ user}) {
|
||||||
|
const [userInfo,setuserInfo]=useState({});
|
||||||
|
useEffect(()=>{
|
||||||
|
console.log(user);
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/publicUser`, {
|
||||||
|
id: user,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setuserInfo(response.data);
|
||||||
|
console.log("Modification réussie :", response.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Erreur lors de la modification :", error);
|
||||||
|
});
|
||||||
|
},[user]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white p-6 rounded-xl min-w-5xl">
|
||||||
|
<div className="flex align-items gap-6 mb-6">
|
||||||
|
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-1">
|
||||||
|
<User className="text-indigo-600" size={24} />
|
||||||
|
</div>
|
||||||
|
<h1 className="text-black text-2xl font-bold mb-1 ">Propriétaire</h1>
|
||||||
|
</div>
|
||||||
|
<div className="mb-5">
|
||||||
|
<p className="text-black-900 font-bold">Pseudo :</p>
|
||||||
|
<p className="text-gray-600 capitalize">{userInfo.pseudo}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<p className="text-black-900 font-bold">Genre :</p>
|
||||||
|
<p className="text-gray-600 capitalize">{userInfo.gender}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<p className="text-black-900 font-bold">Nombre de points :</p>
|
||||||
|
<p className="text-gray-600">{userInfo.points}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserInfosObject;
|
||||||
@ -205,7 +205,7 @@ function AdminObjet() {
|
|||||||
{obj.location}
|
{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.proprio}
|
{obj.proprio_id}
|
||||||
</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}
|
||||||
|
|||||||
@ -9,19 +9,21 @@ import {
|
|||||||
UserPlus,
|
UserPlus,
|
||||||
RadioTower,
|
RadioTower,
|
||||||
Binoculars,
|
Binoculars,
|
||||||
Settings,
|
|
||||||
BadgePlus,
|
BadgePlus,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import { useAuth } from "../../AuthContext";
|
||||||
function Gestion() {
|
function Gestion() {
|
||||||
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">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
|
|
||||||
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
||||||
Bienvenue dans le module <b>Gestion</b>.
|
Bienvenue dans le module <b>Gestion</b>.
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||||
Ce module vous permet de gérer les capteur et stations connectés de France de manière simple et efficace.
|
Ce module vous permet de gérer les capteurs et stations connectés de France de manière simple et efficace.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ function Gestion() {
|
|||||||
Explorer les objets <ArrowRight size={16} className="ml-2" />
|
Explorer les objets <ArrowRight size={16} className="ml-2" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow">
|
<div className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow">
|
||||||
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4">
|
<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} />
|
<BadgePlus className="text-indigo-600" size={24} />
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Search, ArrowRight, RadioTower,Plus } from "lucide-react";
|
import { Search, ArrowRight, RadioTower, Plus } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { API_BASE_URL } from "../../config";
|
import { API_BASE_URL } from "../../config";
|
||||||
|
import { useAuth } from "../../AuthContext";
|
||||||
|
|
||||||
function ObjectManagement() {
|
function ObjectManagement() {
|
||||||
|
const {user} = useAuth();
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [activeFilter, setActiveFilter] = useState("");
|
const [activeFilter, setActiveFilter] = useState("");
|
||||||
const [objects, setObjects] = useState([]);
|
const [objects, setObjects] = useState([]);
|
||||||
const [nbAffObject,setnbAffObject] = useState(6);
|
const [nbAffObject, setnbAffObject] = useState(6);
|
||||||
|
|
||||||
const filteredDATA = objects.filter((node) => {
|
const filteredDATA = objects.filter((node) => {
|
||||||
const matchesSearchQuery =
|
const matchesSearchQuery =
|
||||||
searchQuery === "" ||
|
searchQuery === "" ||
|
||||||
@ -29,12 +32,13 @@ function ObjectManagement() {
|
|||||||
setObjects(response.data);
|
setObjects(response.data);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
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">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
||||||
Gestion des <b>Objets</b> connectés.
|
{(user?.role!=="user")?("Gestion"):("Visualisation")} des <b>Objets</b> connectés.
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="max-w-3xl mx-auto mb-12">
|
<div className="max-w-3xl mx-auto mb-12">
|
||||||
@ -51,10 +55,12 @@ function ObjectManagement() {
|
|||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-4 mt-4 justify-center">
|
|
||||||
|
{/* Filtres responsifs - utilisation de flex-wrap et responsive spacing */}
|
||||||
|
<div className="flex flex-wrap gap-2 mt-4 justify-center">
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("")}
|
onClick={() => setActiveFilter("")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg mb-2 ${
|
||||||
activeFilter === ""
|
activeFilter === ""
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
@ -64,7 +70,7 @@ function ObjectManagement() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("Station")}
|
onClick={() => setActiveFilter("Station")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg mb-2 ${
|
||||||
activeFilter === "Station"
|
activeFilter === "Station"
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
@ -74,7 +80,7 @@ function ObjectManagement() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("Capteur")}
|
onClick={() => setActiveFilter("Capteur")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg mb-2 ${
|
||||||
activeFilter === "Capteur"
|
activeFilter === "Capteur"
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
@ -84,7 +90,7 @@ function ObjectManagement() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("Active")}
|
onClick={() => setActiveFilter("Active")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg mb-2 ${
|
||||||
activeFilter === "Active"
|
activeFilter === "Active"
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
@ -94,7 +100,7 @@ function ObjectManagement() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("Inactive")}
|
onClick={() => setActiveFilter("Inactive")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg mb-2 ${
|
||||||
activeFilter === "Inactive"
|
activeFilter === "Inactive"
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
@ -104,14 +110,16 @@ function ObjectManagement() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid md:grid-cols-3 gap-8">
|
|
||||||
|
{/* Grille responsive pour les objets */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-8">
|
||||||
{filteredDATA.length === 0 ? (
|
{filteredDATA.length === 0 ? (
|
||||||
<p>Aucun objet trouvé</p>
|
<p className="text-center col-span-full">Aucun objet trouvé</p>
|
||||||
) : (
|
) : (
|
||||||
filteredDATA.slice(0,nbAffObject).map((object) => (
|
filteredDATA.slice(0, nbAffObject).map((object) => (
|
||||||
<div
|
<div
|
||||||
key={object.id}
|
key={object.id}
|
||||||
className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow "
|
className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow"
|
||||||
>
|
>
|
||||||
{object.status === "active" ? (
|
{object.status === "active" ? (
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
@ -143,14 +151,21 @@ function ObjectManagement() {
|
|||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{(nbAffObject<filteredDATA.length)&&(
|
|
||||||
|
{(nbAffObject < filteredDATA.length) && (
|
||||||
<div className="flex items-center flex-col mt-6">
|
<div className="flex items-center flex-col mt-6">
|
||||||
<button onClick={()=>{setnbAffObject((prev)=>prev+6 )}}><Plus size={40}/></button>
|
<button
|
||||||
<label>Voir plus</label>
|
onClick={() => {setnbAffObject((prev) => prev + 6)}}
|
||||||
|
className="hover:bg-indigo-50 p-2 rounded-full transition-colors"
|
||||||
|
>
|
||||||
|
<Plus size={40} className="text-indigo-600" />
|
||||||
|
</button>
|
||||||
|
<label className="text-indigo-600 font-medium">Voir plus</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ObjectManagement;
|
export default ObjectManagement;
|
||||||
@ -12,7 +12,10 @@ import WindInfo from "../../components/WindInfo";
|
|||||||
import MeteoInfos from "../../components/MeteoInfos";
|
import MeteoInfos from "../../components/MeteoInfos";
|
||||||
import MeteoGraph from "../../components/MeteoGraph";
|
import MeteoGraph from "../../components/MeteoGraph";
|
||||||
import BatterieInfo from "../../components/BatterieInfo";
|
import BatterieInfo from "../../components/BatterieInfo";
|
||||||
|
import { useAuth } from "../../AuthContext";
|
||||||
|
import UserInfosObject from "../../components/UserInfosObject";
|
||||||
function Objet() {
|
function Objet() {
|
||||||
|
const {user} =useAuth();
|
||||||
const identifiant = new URLSearchParams(window.location.search).get("id");
|
const identifiant = new URLSearchParams(window.location.search).get("id");
|
||||||
const [object, setObject] = useState({});
|
const [object, setObject] = useState({});
|
||||||
const [graphStates, setGraphStates] = useState({
|
const [graphStates, setGraphStates] = useState({
|
||||||
@ -28,12 +31,20 @@ function Objet() {
|
|||||||
humidity: useRef(null),
|
humidity: useRef(null),
|
||||||
wind: useRef(null),
|
wind: useRef(null),
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axios.get(`${API_BASE_URL}/objet?id=${identifiant}`).then((response) => {
|
axios
|
||||||
|
.post(`${API_BASE_URL}/objet`, {
|
||||||
|
id: identifiant,
|
||||||
|
userId:user.id,
|
||||||
|
shouldUpdatePoints:true,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
setObject(response.data[0]);
|
setObject(response.data[0]);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Erreur lors de la récupération :", error);
|
||||||
});
|
});
|
||||||
}, [identifiant]);
|
}, [user]);
|
||||||
return object && object.id ? (
|
return object && object.id ? (
|
||||||
<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">
|
||||||
@ -61,6 +72,8 @@ function Objet() {
|
|||||||
graphRefs={graphRefs}
|
graphRefs={graphRefs}
|
||||||
/>
|
/>
|
||||||
<BatterieInfo object={object} />
|
<BatterieInfo object={object} />
|
||||||
|
<UserInfosObject user={object.proprio_id}/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{graphStates.wind && <WindGraph object={object} reference={graphRefs.wind} />}
|
{graphStates.wind && <WindGraph object={object} reference={graphRefs.wind} />}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ function Home() {
|
|||||||
const [activeFilter, setActiveFilter] = useState('all');
|
const [activeFilter, setActiveFilter] = useState('all');
|
||||||
const [name, setName] = useState([]);
|
const [name, setName] = useState([]);
|
||||||
const { token, logout } = useAuth();
|
const { token, logout } = useAuth();
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
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">
|
||||||
@ -15,10 +16,15 @@ function Home() {
|
|||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
||||||
Bienvenue dans ta ville intelligente.</h2>
|
Bienvenue dans ta ville intelligente.</h2>
|
||||||
{token ? (
|
{user ? (
|
||||||
<><h2>Tu es connecté</h2>
|
<>
|
||||||
|
<h1>Bienvenue, {user.name} {user.surname}!</h1>
|
||||||
|
<p>Email : {user.sub}</p>
|
||||||
|
<p>Rôle : {user.role}</p>
|
||||||
|
<p>Rôle : {user.id}</p>
|
||||||
|
|
||||||
</>):(
|
</>
|
||||||
|
):(
|
||||||
<h2>Non connecté</h2>
|
<h2>Non connecté</h2>
|
||||||
)}
|
)}
|
||||||
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Mail, Lock } from "lucide-react";
|
import { Mail, Lock, AlertCircle } from "lucide-react";
|
||||||
import { useNavigate, Link } from "react-router-dom";
|
import { useNavigate, Link } from "react-router-dom";
|
||||||
import axios from "axios"; // Assurez-vous d'avoir axios importé
|
import axios from "axios";
|
||||||
import { useAuth } from "../AuthContext";
|
import { useAuth } from "../AuthContext";
|
||||||
import { API_BASE_URL } from "../config";
|
import { API_BASE_URL } from "../config";
|
||||||
|
|
||||||
@ -10,8 +10,9 @@ function Login() {
|
|||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
});
|
});
|
||||||
const { login } = useAuth(); // Utilisation du hook useAuth pour accéder à la fonction login
|
const [error, setError] = useState("");
|
||||||
const navigate = useNavigate(); // Initialisation de useNavigate
|
const { login } = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
@ -19,43 +20,68 @@ function Login() {
|
|||||||
...prev,
|
...prev,
|
||||||
[name]: value,
|
[name]: value,
|
||||||
}));
|
}));
|
||||||
|
if (error) setError("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
setError("");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/login`, {
|
const response = await axios.post(`${API_BASE_URL}/login`, formData, {
|
||||||
method: "POST",
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(formData),
|
|
||||||
});
|
});
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
// Récupérer les données JSON de la réponse
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
// Vérifiez que la réponse contient bien un token
|
|
||||||
if (data.token) {
|
if (data.token) {
|
||||||
// Appel de la fonction login du contexte pour stocker le token
|
|
||||||
login(data.token);
|
login(data.token);
|
||||||
|
|
||||||
// Rediriger vers la page d'accueil après la connexion
|
|
||||||
navigate("/");
|
navigate("/");
|
||||||
} else {
|
} else {
|
||||||
console.error("Token manquant dans la réponse");
|
setError("Authentification échouée : token manquant dans la réponse");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de la connexion", error);
|
console.error("Erreur lors de la connexion", error);
|
||||||
|
|
||||||
|
if (error.response) {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
setError("Email ou mot de passe incorrect");
|
||||||
|
} else if (error.response.status === 422) {
|
||||||
|
setError("Données de formulaire invalides");
|
||||||
|
} else if (error.response.status >= 500) {
|
||||||
|
setError("Erreur serveur. Veuillez réessayer plus tard.");
|
||||||
|
} else {
|
||||||
|
setError(
|
||||||
|
error.response.data.message ||
|
||||||
|
"Une erreur s'est produite lors de la connexion"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (error.request) {
|
||||||
|
setError(
|
||||||
|
"Impossible de joindre le serveur. Vérifiez votre connexion internet."
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setError("Une erreur s'est produite. Veuillez réessayer.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
|
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||||
<div className="md:w-96 w-full bg-white rounded-lg shadow-md p-6 mx-auto">
|
<div className="md:w-96 w-full bg-white rounded-lg shadow-md p-6 mx-auto">
|
||||||
<h2 className="text-2xl font-bold text-gray-800 mb-6 text-center">
|
<h2 className="text-2xl font-bold text-gray-800 mb-6 text-center">
|
||||||
Connexion
|
Connexion
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
{/* Message d'erreur */}
|
||||||
|
{error && (
|
||||||
|
<div className="mb-4 p-3 bg-red-50 border border-red-200 text-red-700 rounded-md flex items-start">
|
||||||
|
<AlertCircle className="h-5 w-5 mr-2 mt-0.5 flex-shrink-0" />
|
||||||
|
<span className="text-sm">{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
{/* Email */}
|
{/* Email */}
|
||||||
<div>
|
<div>
|
||||||
@ -94,6 +120,7 @@ function Login() {
|
|||||||
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
required
|
required
|
||||||
minLength="8"
|
minLength="8"
|
||||||
|
autoComplete="current-password"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
328
Front-end/src/pages/Profil.jsx
Normal file
328
Front-end/src/pages/Profil.jsx
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Mail, User, Lock, Edit, Save } from 'lucide-react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { API_BASE_URL } from "../config";
|
||||||
|
import { useAuth } from "../AuthContext";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
function Profil() {
|
||||||
|
const [userData, setUserData] = useState({});
|
||||||
|
|
||||||
|
const { user } = useAuth();
|
||||||
|
useEffect(() => {
|
||||||
|
if (user) {
|
||||||
|
console.log("user.role:", user.id);
|
||||||
|
}
|
||||||
|
}, [user]);
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const [editMode, setEditMode] = useState(false);
|
||||||
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
|
const [successMessage, setSuccessMessage] = useState('');
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/user`, {
|
||||||
|
id: user.id,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setUserData(response.data);
|
||||||
|
console.log("Infos récupérées :", response.data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Erreur lors de la récupération :", error);
|
||||||
|
});
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
[name]: value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProfileChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setUserData(prev => ({
|
||||||
|
...prev,
|
||||||
|
[name]: value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setErrorMessage('');
|
||||||
|
setSuccessMessage('');
|
||||||
|
|
||||||
|
if (formData.newPassword !== formData.confirmPassword) {
|
||||||
|
setErrorMessage("Les nouveaux mots de passe ne correspondent pas !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/changePassword`, {
|
||||||
|
id: userData.id,
|
||||||
|
oldPassword: formData.oldPassword,
|
||||||
|
newPassword: formData.newPassword
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
console.log("Modification du mot de passe réussie :", response.data);
|
||||||
|
setSuccessMessage("Mot de passe modifié avec succès !");
|
||||||
|
setFormData({
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Erreur lors de la modification du mot de passe :", error);
|
||||||
|
setErrorMessage(error.response?.data?.error || "Une erreur est survenue");
|
||||||
|
});
|
||||||
|
|
||||||
|
setSuccessMessage("Mot de passe modifié avec succès !");
|
||||||
|
setFormData({
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setErrorMessage(error.message || "Une erreur est survenue");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProfileSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setErrorMessage('');
|
||||||
|
setSuccessMessage('');
|
||||||
|
|
||||||
|
axios
|
||||||
|
.post(`${API_BASE_URL}/updateProfil`, {
|
||||||
|
id: userData.id,
|
||||||
|
name: userData.name,
|
||||||
|
surname: userData.surname,
|
||||||
|
pseudo:userData.pseudo,
|
||||||
|
email: userData.email
|
||||||
|
})
|
||||||
|
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Erreur lors de la mise à jour du profil :", error);
|
||||||
|
setErrorMessage(error.response?.data?.error || "Une erreur est survenue");
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
console.log("Mise à jour du profil réussie :", response.data);
|
||||||
|
setSuccessMessage("Profil mis à jour avec succès !");
|
||||||
|
setEditMode(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="max-w-3xl mx-auto">
|
||||||
|
<h1 className="text-3xl font-bold text-gray-900 mb-8 text-center">Mon Profil</h1>
|
||||||
|
|
||||||
|
{errorMessage && (
|
||||||
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4">
|
||||||
|
{errorMessage}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{successMessage && (
|
||||||
|
<div className="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4">
|
||||||
|
{successMessage}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-2 gap-8">
|
||||||
|
{/* Informations du profil */}
|
||||||
|
<div className="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<div className="flex justify-between items-center mb-4">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-800">Informations Personnelles</h2>
|
||||||
|
<button
|
||||||
|
onClick={() => setEditMode(!editMode)}
|
||||||
|
className="text-indigo-600 hover:text-indigo-800"
|
||||||
|
>
|
||||||
|
{editMode ? <Save className="h-5 w-5" /> : <Edit className="h-5 w-5" />}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleProfileSubmit} className="space-y-4">
|
||||||
|
<div className="flex items-center space-x-4 mb-4">
|
||||||
|
<div className="w-20 h-20 bg-indigo-100 rounded-full flex items-center justify-center">
|
||||||
|
<User className="h-10 w-10 text-indigo-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-medium">{userData.name} {userData.surname} ({userData.pseudo})</h3>
|
||||||
|
<p className="text-gray-500">{userData.email}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-indigo-50 p-3 rounded-lg mb-4">
|
||||||
|
<p className="text-sm text-gray-700">Points de fidélité: <span className="font-semibold">{userData.points}</span> ({userData.role})</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{editMode ? (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">Prénom:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value={userData.name}
|
||||||
|
onChange={handleProfileChange}
|
||||||
|
className="block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">Nom:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="surname"
|
||||||
|
value={userData.surname}
|
||||||
|
onChange={handleProfileChange}
|
||||||
|
className="block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">Pseudo:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="pseudo"
|
||||||
|
value={userData.pseudo}
|
||||||
|
onChange={handleProfileChange}
|
||||||
|
className="block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">Email:</label>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
|
<Mail className="h-5 w-5 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
value={userData.email}
|
||||||
|
disabled
|
||||||
|
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
Sauvegarder
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-gray-500">Prénom</p>
|
||||||
|
<p className="mt-1">{userData.name}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-gray-500">Nom</p>
|
||||||
|
<p className="mt-1">{userData.surname}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-gray-500">Pseudo</p>
|
||||||
|
<p className="mt-1">{userData.pseudo}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-gray-500">Email</p>
|
||||||
|
<p className="mt-1">{userData.email}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Changement de mot de passe */}
|
||||||
|
<div className="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-800 mb-4">Modifier le mot de passe</h2>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
|
Mot de passe actuel:
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
|
<Lock className="h-5 w-5 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="oldPassword"
|
||||||
|
value={formData.oldPassword}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
required
|
||||||
|
minLength="8"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
|
Nouveau mot de passe:
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
|
<Lock className="h-5 w-5 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="newPassword"
|
||||||
|
value={formData.newPassword}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
required
|
||||||
|
minLength="8"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
|
Confirmer le nouveau mot de passe:
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
|
<Lock className="h-5 w-5 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="confirmPassword"
|
||||||
|
value={formData.confirmPassword}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
required
|
||||||
|
minLength="8"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="w-full flex justify-center py-2.5 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
Modifier le mot de passe
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Profil;
|
||||||
@ -1,161 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Mail, User, Lock } from 'lucide-react';
|
|
||||||
import { useNavigate, Link} from 'react-router-dom'; // Importation du hook useNavigate
|
|
||||||
|
|
||||||
function Settings() {
|
|
||||||
const [formData, setFormData] = useState({
|
|
||||||
name: '',
|
|
||||||
surname: '',
|
|
||||||
email: '',
|
|
||||||
gender: '',
|
|
||||||
password: '',
|
|
||||||
confirmPassword: ''
|
|
||||||
});
|
|
||||||
const navigate = useNavigate(); // Initialisation de useNavigate
|
|
||||||
|
|
||||||
const handleChange = (e) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData(prev => ({
|
|
||||||
...prev,
|
|
||||||
[name]: value
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (formData.password !== formData.confirmPassword) {
|
|
||||||
alert("Les mots de passe ne correspondent pas !");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE_URL}/settings`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(formData),
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(data.error || "Erreur lors de la modification");
|
|
||||||
}
|
|
||||||
|
|
||||||
alert("Modification réussie !");
|
|
||||||
|
|
||||||
// Redirection vers la page d'accueil après une inscription réussie
|
|
||||||
navigate("/home"); // Remplace "/home" par l'URL de ta page d'accueil
|
|
||||||
} catch (error) {
|
|
||||||
alert(error.message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
|
|
||||||
<div className="w-96 bg-white rounded-lg shadow-md p-6 mx-auto">
|
|
||||||
<h2 className="text-2xl font-bold text-gray-800 mb-6 text-center">Settings</h2>
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
|
||||||
{/* (Formulaire changement Email, Mot de passe) */}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Email */}
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
||||||
Modifier votre email:
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
||||||
<Mail className="h-5 w-5 text-gray-400" />
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
name="email"
|
|
||||||
value={formData.email}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Mot de passe */}
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Ancien mot de passe:
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
||||||
<Lock className="h-5 w-5 text-gray-400" />
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
name="password"
|
|
||||||
value={formData.password}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
required
|
|
||||||
minLength="8"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* nouveau mot de passe */}
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Nouveau mot de passe:
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
||||||
<Lock className="h-5 w-5 text-gray-400" />
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
name="confirmPassword"
|
|
||||||
value={formData.confirmPassword}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
required
|
|
||||||
minLength="8"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Confirmer le nouveau mot de passe:
|
|
||||||
</label>
|
|
||||||
<div className="relative">
|
|
||||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
||||||
<Lock className="h-5 w-5 text-gray-400" />
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
name="confirmPassword"
|
|
||||||
value={formData.confirmPassword}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
required
|
|
||||||
minLength="8"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Bouton d'inscription */}
|
|
||||||
<div className="pt-4">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="w-full flex justify-center py-2.5 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
||||||
>
|
|
||||||
Sauvegarder
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Settings;
|
|
||||||
@ -7,6 +7,7 @@ function Signup() {
|
|||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
name: '',
|
name: '',
|
||||||
surname: '',
|
surname: '',
|
||||||
|
pseudo:'',
|
||||||
email: '',
|
email: '',
|
||||||
gender: '',
|
gender: '',
|
||||||
password: '',
|
password: '',
|
||||||
@ -62,7 +63,7 @@ function Signup() {
|
|||||||
{/* Formulaire (Nom, Prénom, Sexe, Email, Mot de passe) */}
|
{/* Formulaire (Nom, Prénom, Sexe, Email, Mot de passe) */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Nom:
|
Prénom:
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
@ -81,7 +82,7 @@ function Signup() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Prénom:
|
Nom:
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
@ -98,6 +99,25 @@ function Signup() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
|
Pseudo:
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
|
<User className="h-5 w-5 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="pseudo"
|
||||||
|
value={formData.pseudo}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Sexe */}
|
{/* Sexe */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user