Ajout modification fichiers

This commit is contained in:
Charles Mendiburu 2025-04-08 10:02:42 +02:00
commit e216092036
14 changed files with 950 additions and 239 deletions

View File

@ -22,16 +22,34 @@ public class MainVerticle extends AbstractVerticle {
// Initialisation du fournisseur JWT // Initialisation du fournisseur JWT
JWTAuth jwtAuth = JwtAuthProvider.createJwtAuth(vertx); JWTAuth jwtAuth = JwtAuthProvider.createJwtAuth(vertx);
@Override
// Initialisation du routeur public void start(Promise<Void> startPromise) throws Exception {
router = Router.router(vertx); databaseService = new DatabaseService(vertx);
QueryObjects queryObjects = new QueryObjects(databaseService);
QueryWeatherData queryWeather = new QueryWeatherData(databaseService);
SetObjects setObjects = new SetObjects(databaseService);
SetWeatherData setWeatherData = new SetWeatherData(databaseService);
// Create a Router
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create()); router.route().handler(BodyHandler.create());
router.route().handler(CorsHandler.create() router.route().handler(CorsHandler.create()
.addOrigin("*") .addOrigin("*") // Allow all origins
.allowedMethod(HttpMethod.GET) .allowedMethod(HttpMethod.GET) // Allow GET requests
.allowedMethod(HttpMethod.POST) .allowedMethod(HttpMethod.POST) // Allow POST requests
.allowedHeader("Content-Type") .allowedHeader("Content-Type") // Allow Content-Type header
.allowedHeader("Authorization")); .allowedHeader("Authorization"));
router.get("/objets").handler(queryObjects::getObjects);
router.get("/objet").handler(queryObjects::getParticularObject);
router.post("/modifObjet").handler(setObjects::setInfoObjet);
router.get("/wind").handler(queryWeather::getWindInfos);
router.get("/meteo").handler(queryWeather::getMeteoInfos);
router.post("/addObject").handler(setObjects::newObject);
router.get("/getRange").handler(queryWeather::getRangeData);
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
// Routes d'authentification
router.post("/signup").handler(authHandler::handleSignup);
router.post("/login").handler(authHandler::handleLogin);
// Protéger toutes les routes commençant par "/api/" // Protéger toutes les routes commençant par "/api/"
router.route("/api/*").handler(JWTAuthHandler.create(jwtAuth)); router.route("/api/*").handler(JWTAuthHandler.create(jwtAuth));
@ -43,17 +61,7 @@ public class MainVerticle extends AbstractVerticle {
SetObjects setObjects = new SetObjects(databaseService); SetObjects setObjects = new SetObjects(databaseService);
AuthHandler authHandler = new AuthHandler(databaseService, jwtAuth); AuthHandler authHandler = new AuthHandler(databaseService, jwtAuth);
// Déclaration des routes
router.get("/objets").handler(queryObjects::getObjects);
router.get("/objet").handler(queryObjects::getParticularObject);
router.post("/modifObjet").handler(setObjects::setInfoObjet);
router.get("/wind").handler(queryWeather::getWindInfos);
router.get("/meteo").handler(queryWeather::getMeteoInfos);
router.post("/addObject").handler(setObjects::newObject);
// Routes d'authentification
router.post("/signup").handler(authHandler::handleSignup);
router.post("/login").handler(authHandler::handleLogin);
// Création du serveur HTTP // Création du serveur HTTP
vertx.createHttpServer() vertx.createHttpServer()
@ -69,3 +77,4 @@ public class MainVerticle extends AbstractVerticle {
}); });
} }
} }
}

View File

@ -78,6 +78,36 @@ public class QueryWeatherData {
.end((convertRowsToJson(rows)).encode()); .end((convertRowsToJson(rows)).encode());
}); });
} }
public void getRangeData(RoutingContext context){
String id= context.request().getParam("id");
if(id==null){
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error","Paramètre 'id' manquant").encode());
return;
}
databaseService.pool
.preparedQuery("SELECT temperature_min,temperature_max,pressure_min,pressure_max,humidity_min,humidity_max FROM range_data WHERE station_id=?")
.execute(Tuple.of(Integer.parseInt(id)))
.onFailure(e->{
System.err.println("Erreur de récupération de la BDD: "+e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
return;
})
.onSuccess(rows->{
if(rows.size() == 0){
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error","Objet non trouvé").encode());
return;
}
context.response()
.putHeader("content-type","application/json:charset=UTF-8")
.end((convertRowsToJson(rows)).encode());
});
}
private JsonArray convertRowsToJson(RowSet<Row> rows) { private JsonArray convertRowsToJson(RowSet<Row> rows) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");

View File

@ -0,0 +1,66 @@
package com.example.starter;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.data.Numeric;
public class SetWeatherData {
private DatabaseService databaseService;
public SetWeatherData(DatabaseService ddbs) {
this.databaseService = ddbs;
}
public void setRangeData(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
return;
}
String id = body.getString("id");
Double min = body.getDouble("min");
Double max = body.getDouble("max");
String type = body.getString("type");
if (id == null || min == null || max == null || type == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Paramètres manquants ou invalides").encode());
return;
}
if (!type.matches("^[a-zA-Z_]+$")) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Type invalide").encode());
return;
}
String query = String.format("UPDATE range_data SET %s_min=?, %s_max=? WHERE station_id=?", type, type);
databaseService.pool
.preparedQuery(
query)
.execute(Tuple.of(min, max, Integer.parseInt(id)))
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("Erreur", "Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if (rows.rowCount() == 0) {
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Objet non trouvé").encode());
return;
}
context.response()
.putHeader("content-type", "application/json: charset=UTF-8")
.end(new JsonObject().put("success", "Les limites ont bien été mis à jour").encode());
return;
});
}
}

View File

@ -9,6 +9,9 @@
"version": "0.0.0", "version": "0.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/material": "^7.0.1",
"axios": "^1.8.4", "axios": "^1.8.4",
"lucide-react": "^0.427.0", "lucide-react": "^0.427.0",
"react": "^18.3.1", "react": "^18.3.1",
@ -60,7 +63,6 @@
"version": "7.26.2", "version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
@ -113,7 +115,6 @@
"version": "7.26.10", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz",
"integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.10", "@babel/parser": "^7.26.10",
"@babel/types": "^7.26.10", "@babel/types": "^7.26.10",
@ -145,7 +146,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
"integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/traverse": "^7.25.9", "@babel/traverse": "^7.25.9",
"@babel/types": "^7.25.9" "@babel/types": "^7.25.9"
@ -184,7 +184,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -193,7 +192,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -224,7 +222,6 @@
"version": "7.26.10", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz",
"integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/types": "^7.26.10" "@babel/types": "^7.26.10"
}, },
@ -281,7 +278,6 @@
"version": "7.26.9", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.9", "@babel/parser": "^7.26.9",
@ -295,7 +291,6 @@
"version": "7.26.10", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz",
"integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.10", "@babel/generator": "^7.26.10",
@ -313,7 +308,6 @@
"version": "11.12.0", "version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -322,7 +316,6 @@
"version": "7.26.10", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9" "@babel/helper-validator-identifier": "^7.25.9"
@ -331,6 +324,158 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.3.3",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"license": "MIT"
},
"node_modules/@emotion/cache": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"license": "MIT"
},
"node_modules/@emotion/is-prop-valid": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz",
"integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0"
}
},
"node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
"license": "MIT"
},
"node_modules/@emotion/react": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
"license": "MIT",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.2",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
"license": "MIT"
},
"node_modules/@emotion/styled": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz",
"integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/is-prop-valid": "^1.3.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2"
},
"peerDependencies": {
"@emotion/react": "^11.0.0-rc.0",
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
"license": "MIT"
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
"integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
"license": "MIT"
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@ -921,7 +1066,6 @@
"version": "0.3.8", "version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"dependencies": { "dependencies": {
"@jridgewell/set-array": "^1.2.1", "@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/sourcemap-codec": "^1.4.10",
@ -935,7 +1079,6 @@
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
} }
@ -944,7 +1087,6 @@
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
} }
@ -952,19 +1094,236 @@
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
"dev": true
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25", "version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"dependencies": { "dependencies": {
"@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"node_modules/@mui/core-downloads-tracker": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.0.1.tgz",
"integrity": "sha512-T5DNVnSD9pMbj4Jk/Uphz+yvj9dfpl2+EqsOuJtG12HxEihNG5pd3qzX5yM1Id4dDwKRvM3dPVcxyzavTFhJeA==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/material": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.0.1.tgz",
"integrity": "sha512-tQwjIIsn/UUSCHoCIQVkANuLua67h7Ro9M9gIHoGWaFbJFuF6cSO4Oda2olDVqIs4SWG+PaDChuu6SngxsaoyQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.10",
"@mui/core-downloads-tracker": "^7.0.1",
"@mui/system": "^7.0.1",
"@mui/types": "^7.4.0",
"@mui/utils": "^7.0.1",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1",
"csstype": "^3.1.3",
"prop-types": "^15.8.1",
"react-is": "^19.0.0",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material-pigment-css": "^7.0.1",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@mui/material-pigment-css": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material/node_modules/react-is": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz",
"integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==",
"license": "MIT"
},
"node_modules/@mui/private-theming": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.0.1.tgz",
"integrity": "sha512-1kQ7REYjjzDukuMfTbAjm3pLEhD7gUMC2bWhg9VD6f6sHzyokKzX0XHzlr3IdzNWBjPytGkzHpPIRQrUOoPLCQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.10",
"@mui/utils": "^7.0.1",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/styled-engine": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.0.1.tgz",
"integrity": "sha512-BeGe4xZmF7tESKhmctYrL54Kl25kGHPKVdZYM5qj5Xz76WM/poY+d8EmAqUesT6k2rbJWPp2gtOAXXinNCGunQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.10",
"@emotion/cache": "^11.13.5",
"@emotion/serialize": "^1.3.3",
"@emotion/sheet": "^1.4.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
}
}
},
"node_modules/@mui/system": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.0.1.tgz",
"integrity": "sha512-pK+puz0hRPHEKGlcPd80mKYD3jpyi0uVIwWffox1WZgPTQMw2dCKLcD+9ndMDJADnrKzmKlpoH756PPFh2UvWA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.10",
"@mui/private-theming": "^7.0.1",
"@mui/styled-engine": "^7.0.1",
"@mui/types": "^7.4.0",
"@mui/utils": "^7.0.1",
"clsx": "^2.1.1",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/types": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.0.tgz",
"integrity": "sha512-TxJ4ezEeedWHBjOmLtxI203a9DII9l4k83RXmz1PYSAmnyEcK2PglTNmJGxswC/wM5cdl9ap2h8lnXvt2swAGQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.10"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.0.1.tgz",
"integrity": "sha512-SJKrrebNpmK9rJCnVL29nGPhPXQYtBZmb7Dsp0f58uIUhQfAKcBXHE4Kjs06SX4CwqeCuwEVgcHY+MgAO6XQ/g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.10",
"@mui/types": "^7.4.0",
"@types/prop-types": "^15.7.14",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^19.0.0"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils/node_modules/react-is": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz",
"integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==",
"license": "MIT"
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -1010,6 +1369,16 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.37.0", "version": "4.37.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.37.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.37.0.tgz",
@ -1392,6 +1761,12 @@
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true "dev": true
}, },
"node_modules/@types/parse-json": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"license": "MIT"
},
"node_modules/@types/prop-types": { "node_modules/@types/prop-types": {
"version": "15.7.14", "version": "15.7.14",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
@ -1424,6 +1799,15 @@
"@types/react": "^17.0.0" "@types/react": "^17.0.0"
} }
}, },
"node_modules/@types/react-transition-group": {
"version": "4.4.12",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@types/scheduler": { "node_modules/@types/scheduler": {
"version": "0.16.8", "version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
@ -1597,6 +1981,21 @@
"proxy-from-env": "^1.1.0" "proxy-from-env": "^1.1.0"
} }
}, },
"node_modules/babel-plugin-macros": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0",
"resolve": "^1.19.0"
},
"engines": {
"node": ">=10",
"npm": ">=6"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -1686,7 +2085,6 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -1841,6 +2239,31 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"license": "MIT",
"dependencies": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/cosmiconfig/node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -1992,7 +2415,6 @@
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
}, },
@ -2086,6 +2508,15 @@
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true "dev": true
}, },
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
}
},
"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",
@ -2182,7 +2613,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@ -2452,6 +2882,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -2746,6 +3182,21 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"license": "BSD-3-Clause",
"dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/hoist-non-react-statics/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@ -2759,7 +3210,6 @@
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"dependencies": { "dependencies": {
"parent-module": "^1.0.0", "parent-module": "^1.0.0",
"resolve-from": "^4.0.0" "resolve-from": "^4.0.0"
@ -2786,6 +3236,12 @@
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"license": "MIT"
},
"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",
@ -2802,7 +3258,6 @@
"version": "2.16.1", "version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"dependencies": { "dependencies": {
"hasown": "^2.0.2" "hasown": "^2.0.2"
}, },
@ -2903,7 +3358,6 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
"bin": { "bin": {
"jsesc": "bin/jsesc" "jsesc": "bin/jsesc"
}, },
@ -2917,6 +3371,12 @@
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true "dev": true
}, },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"license": "MIT"
},
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@ -2978,8 +3438,7 @@
"node_modules/lines-and-columns": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
"dev": true
}, },
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "6.0.0", "version": "6.0.0",
@ -3113,8 +3572,7 @@
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
"dev": true
}, },
"node_modules/mz": { "node_modules/mz": {
"version": "2.7.0", "version": "2.7.0",
@ -3249,7 +3707,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"dependencies": { "dependencies": {
"callsites": "^3.0.0" "callsites": "^3.0.0"
}, },
@ -3257,6 +3714,24 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/path-exists": { "node_modules/path-exists": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@ -3278,8 +3753,7 @@
"node_modules/path-parse": { "node_modules/path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
"dev": true
}, },
"node_modules/path-scurry": { "node_modules/path-scurry": {
"version": "1.11.1", "version": "1.11.1",
@ -3303,11 +3777,19 @@
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true "dev": true
}, },
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
"dev": true
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.1",
@ -3794,7 +4276,6 @@
"version": "1.22.10", "version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"dependencies": { "dependencies": {
"is-core-module": "^2.16.0", "is-core-module": "^2.16.0",
"path-parse": "^1.0.7", "path-parse": "^1.0.7",
@ -3814,7 +4295,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -3953,6 +4433,15 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@ -4070,6 +4559,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"license": "MIT"
},
"node_modules/sucrase": { "node_modules/sucrase": {
"version": "3.35.0", "version": "3.35.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
@ -4108,7 +4603,6 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },

View File

@ -10,6 +10,9 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/material": "^7.0.1",
"axios": "^1.8.4", "axios": "^1.8.4",
"lucide-react": "^0.427.0", "lucide-react": "^0.427.0",
"react": "^18.3.1", "react": "^18.3.1",

View File

@ -1,23 +1,21 @@
import React, {useRef} from "react"; import React from "react";
import { ChartLine } from "lucide-react"; import { ChartLine } from "lucide-react";
function BoutonGraphique({ TypeAff, setAffichage,graphCible}) {
const handleClick = (newAffichage) =>{ function BoutonGraphique({ type, setGraphStates, graphStates, graphCible }) {
setAffichage(newAffichage); const handleClick = () => {
if(graphCible.current){ setGraphStates((prev) => ({ ...prev, [type]: !prev[type] }));
graphCible.current.scrollIntoView({ behavior: "smooth" });
}
}; };
return !TypeAff ? ( return !graphStates[type] ? (
<button <button
className="bg-blue-200 py-2 my-2 px-4 rounded-full mr-2" className="bg-blue-200 py-2 my-2 px-4 rounded-full mr-2"
onClick={() => handleClick(true)} onClick={handleClick}
> >
<ChartLine className="text-indigo-600" size={24} /> <ChartLine className="text-indigo-600" size={24} />
</button> </button>
) : ( ) : (
<button <button
className="bg-blue-400 py-2 my-2 px-4 rounded-full mr-2" className="bg-blue-400 py-2 my-2 px-4 rounded-full mr-2"
onClick={() => handleClick(false)} onClick={handleClick}
> >
<ChartLine className="text-indigo-600" size={24} /> <ChartLine className="text-indigo-600" size={24} />
</button> </button>

View File

@ -4,7 +4,7 @@ import { Info } from "lucide-react";
function InfoObject({ object,defafficherModif }) { function InfoObject({ object,defafficherModif }) {
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"> <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"> <div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-1">
<Info className="text-indigo-600" size={24} /> <Info className="text-indigo-600" size={24} />
</div> </div>

View File

@ -15,7 +15,7 @@ import { Wind } from "lucide-react";
import axios from "axios"; import axios from "axios";
import { API_BASE_URL } from "../config"; import { API_BASE_URL } from "../config";
function MeteoGraph({ object, categorie, Logo }) { function MeteoGraph({ object, categorie, Logo,reference}) {
const [rawData, setRawData] = useState([]); const [rawData, setRawData] = useState([]);
const identifiant = object.id; const identifiant = object.id;
useEffect(() => { useEffect(() => {
@ -23,7 +23,11 @@ function MeteoGraph({ object, categorie, Logo }) {
setRawData(response.data); setRawData(response.data);
}); });
}, [object]); }, [object]);
useEffect(() => {
if (reference?.current) {
reference.current.scrollIntoView({ behavior: "smooth" });
}
}, [reference]);
function getAvg() { function getAvg() {
let moyenne = 0; let moyenne = 0;
rawData.forEach((element) => { rawData.forEach((element) => {
@ -35,9 +39,11 @@ function MeteoGraph({ object, categorie, Logo }) {
} }
return ( return (
<div <div
ref={reference}
key={object.id} key={object.id}
className="bg-white mb-6 p-6 rounded-xl min-w-5xl" className="bg-white mb-6 p-6 rounded-xl min-w-5xl"
style={{ width: "100%", height: "400px" }} style={{ width: "100%", height: "400px" }}
> >
<div className="flex align-items gap-6"> <div className="flex align-items gap-6">
<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">

View File

@ -1,39 +1,30 @@
import { Thermometer, Sun, CircleGauge, Droplet } from "lucide-react"; import { Thermometer, Sun, CircleGauge, Droplet } from "lucide-react";
import React, { useEffect, useState } from "react"; import React, { 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 BoutonGraphique from "./BoutonGraphique"; import BoutonGraphique from "./BoutonGraphique";
import AlertInactive from "./AlertInactive"; import AlertInactive from "./AlertInactive";
import ParticularMeteo from "./ParticularMeteo";
function MeteoInfos({ function MeteoInfos({ object, graphStates, setGraphStates, graphRefs }) {
object,
defAffTempGraph,
AffTempGraph,
defAffPressionGraph,
AffPressionGraph,
defAffHumiditeGraph,
AffHumiditeGraph,
graphCible
}) {
const [rawData, setRawData] = useState([]); const [rawData, setRawData] = useState([]);
const [AffAlert,setAffAlert] = useState(false); const [AffAlert, setAffAlert] = useState(false);
const [AffRegles, setAffRegles] = useState(false);
const identifiant = object.id; const identifiant = object.id;
useEffect(() => { useEffect(() => {
axios.get(`${API_BASE_URL}/meteo?id=${identifiant}`).then((response) => { axios.get(`${API_BASE_URL}/meteo?id=${identifiant}`).then((response) => {
setRawData(response.data); setRawData(response.data);
if(rawData.length <5){ if (rawData.length < 5) {
setAffAlert(true); setAffAlert(true);
} }
}); });
}, [object]); }, [object]);
const lastData = rawData.length > 0 ? rawData[rawData.length - 1] : null; const lastData = rawData.length > 0 ? rawData[rawData.length - 1] : null;
console.log(rawData.length);
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">
{(AffAlert&&(object.status==="active")) && ( {AffAlert && object.status === "active" && (
<AlertInactive affAlert={AffAlert} setAffAlert={setAffAlert} /> <AlertInactive affAlert={AffAlert} setAffAlert={setAffAlert} />
)} )}
<div className="flex align-items gap-6"> <div className="flex align-items gap-6">
@ -44,78 +35,38 @@ function MeteoInfos({
</div> </div>
{lastData ? ( {lastData ? (
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
{lastData.temperature && ( <ParticularMeteo
<div className="bg-indigo-50 rounded-lg flex items-center w-full"> type="temperature"
<div className="flex align-items gap-3 w-full justify-between"> data={lastData}
<div className="flex align-items ml-3 gap-2"> Icon={Thermometer}
<div className="flex items-center"> texte1="Température"
<Thermometer className="text-indigo-600" size={40} /> texte2="°C"
</div> graphStates={graphStates}
<div className="flex flex-col items-start"> setGraphStates={setGraphStates}
<h1 className="text-indigo-600 text-xl font-bold "> graphRefs={graphRefs}
Température />
</h1>
<h1 className="text-gray-700 text-4xl font-bold">
{lastData.temperature} <span className="text-lg">°C</span>
</h1>
</div>
</div>
<BoutonGraphique
TypeAff={AffTempGraph}
setAffichage={defAffTempGraph}
graphCible={graphCible}
<ParticularMeteo
type="pressure"
data={lastData}
Icon={CircleGauge}
texte1="Pression"
texte2="hPa"
graphStates={graphStates}
setGraphStates={setGraphStates}
graphRefs={graphRefs}
/> />
</div>
</div> <ParticularMeteo
)} type="humidity"
{lastData.pressure && ( data={lastData}
<div className="bg-indigo-50 rounded-lg flex items-center w-full"> Icon={Droplet}
<div className="flex align-items gap-3 w-full justify-between"> texte1="Humidité"
<div className="flex align-items ml-3 gap-2"> texte2="%"
<div className="flex items-center"> graphStates={graphStates}
<CircleGauge className="text-indigo-600" size={40} /> setGraphStates={setGraphStates}
</div> graphRefs={graphRefs}
<div className="flex flex-col items-start">
<h1 className="text-indigo-600 text-xl font-bold ">
Pression
</h1>
<h1 className="text-gray-700 text-4xl font-bold">
{lastData.pressure} <span className="text-lg">hPa</span>
</h1>
</div>
</div>
<BoutonGraphique
TypeAff={AffPressionGraph}
setAffichage={defAffPressionGraph}
graphCible={graphCible}
/> />
</div>
</div>
)}
{lastData.humidity && (
<div className="bg-indigo-50 rounded-lg flex items-center w-full">
<div className="flex align-items gap-3 w-full justify-between">
<div className="flex align-items ml-3 gap-2">
<div className="flex items-center">
<Droplet className="text-indigo-600" size={40} />
</div>
<div className="flex flex-col items-start">
<h1 className="text-indigo-600 text-xl font-bold ">
Humidité
</h1>
<h1 className="text-gray-700 text-4xl font-bold">
{lastData.humidity} <span className="text-lg">%</span>
</h1>
</div>
</div>
<BoutonGraphique
TypeAff={AffHumiditeGraph}
setAffichage={defAffHumiditeGraph}
/>
</div>
</div>
)}
<h1 className="text-gray-500 text-sm"> <h1 className="text-gray-500 text-sm">
Dernier enregistrement : {lastData.timestamp} Dernier enregistrement : {lastData.timestamp}
</h1> </h1>

View File

@ -0,0 +1,164 @@
import React, { useEffect, useState } from "react";
import BoutonGraphique from "./BoutonGraphique";
import { Bell } from "lucide-react";
import Slider from "@mui/material/Slider";
import { API_BASE_URL } from "../config";
import axios from "axios";
const identifiant = new URLSearchParams(window.location.search).get("id");
function ParticularMeteo({
type,
data,
Icon,
texte1,
texte2,
graphStates,
setGraphStates,
graphRefs,
}) {
const [affRegles, setAffRegles] = useState(false);
const [rangeValue, setRangeValue] = useState([0, 0]);
const [alerteActive, setAlerteActive] = useState(false);
const minMaxValues = {
temperature: [-50, 60],
pressure: [940, 1060],
humidity: [10, 100],
};
const MIN = minMaxValues[type][0];
const MAX = minMaxValues[type][1];
const formatLabel = (value) => {
switch (type) {
case "temperature":
return `${value}°C`;
case "pressure":
return `${value} hPa`;
case "humidity":
return `${value}%`;
default:
return value;
}
};
const marks = [
{
value: MIN,
label: formatLabel(MIN),
},
{
value: MAX,
label: formatLabel(MAX),
},
];
useEffect(() => {
axios.get(`${API_BASE_URL}/getRange?id=${identifiant}`).then((response) => {
setRangeValue([
response.data[0][type + "_min"],
response.data[0][type + "_max"],
]);
});
}, [identifiant]);
const color =
rangeValue[0] > data[type] || rangeValue[1] < data[type]
? "text-red-600"
: "text-indigo-600";
const defRangeData = () => {
console.log("Données envoyées :", {
id: identifiant,
min: rangeValue[0],
max: rangeValue[1],
type,
});
axios
.post(`${API_BASE_URL}/modifRangeData`, {
id: identifiant,
min: parseFloat(rangeValue[0]),
max: parseFloat(rangeValue[1]),
type,
})
.then((response) => {
console.log("Modification réussie :", response.data);
})
.catch((error) => {
console.error("Erreur lors de la modification :", error);
});
window.location.reload();
};
const handleChange = (event, newValue) => {
setRangeValue(newValue);
};
function valuetext(value) {
return `${value}°C`;
}
if (data[type]) {
return (
<div className="bg-indigo-50 flex flex-col rounded-lg items-center w-full">
<div className="flex align-items gap-3 w-full justify-between">
<div className="flex align-items ml-3 gap-2">
<div className="flex items-center">
<Icon className={`${color}`} size={40} />
</div>
<div className="flex flex-col items-start">
<h1 className={`${color} text-xl font-bold `}>{texte1}</h1>
<h1 className={`${color} text-4xl font-bold`}>
{Math.round(data[type])}{" "}
<span className="text-lg">{texte2}</span>
</h1>
</div>
</div>
<div className="flex gap-2">
<button
onClick={() => {
setAffRegles(!affRegles);
}}
>
<Bell
className={`${color} hover:pointer-events-auto`}
size={30}
/>
</button>
<BoutonGraphique
type={type}
graphStates={graphStates}
setGraphStates={setGraphStates}
graphCible={graphRefs[type]}
/>
</div>
</div>
{affRegles && (
<div className="p-6">
<h1 className="text-red-500 text-l font-semibold">
Définissez la valeur seuil pour l'alerte :
</h1>
<div className="p-4">
<Slider
getAriaLabel={() => "Temperature range"}
value={rangeValue}
onChange={handleChange}
valueLabelDisplay="auto"
min={MIN}
max={MAX}
marks={marks}
getAriaValueText={valuetext}
disableSwap
/>
</div>
{color=="text-red-600" &&(
<p className="text-red-500 text-l mb-2">Attention, la valeur actuelle est hors des bornes que vous avez définit !</p>
)}
<button
type="button"
onClick={() => defRangeData()}
className="text-blue-700 hover:text-white border border-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 mb-2 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-500 dark:focus:ring-blue-800"
>
Définir alerte
</button>
</div>
)}
</div>
);
}
}
export default ParticularMeteo;

View File

@ -5,7 +5,7 @@ import { Wind } from "lucide-react";
import axios from "axios"; import axios from "axios";
import { API_BASE_URL } from "../config"; import { API_BASE_URL } from "../config";
function WindGraph({ object }) { function WindGraph({ object,reference }) {
const [rawData, setRawData] = useState([]); const [rawData, setRawData] = useState([]);
const identifiant = object.id; const identifiant = object.id;
useEffect(() => { useEffect(() => {
@ -25,10 +25,15 @@ function WindGraph({ object }) {
); );
} }
return null; // Si aucun point n'est survolé return null;
}; };
useEffect(() => {
if (reference?.current) {
reference.current.scrollIntoView({ behavior: "smooth" });
}
}, [reference]);
return ( return (
<div key={object.id} className="bg-white mb-6 p-6 rounded-xl min-w-5xl" style={{width: "100%", height: "400px"}}> <div key={object.id} ref={reference} className="bg-white mb-6 p-6 rounded-xl min-w-5xl" style={{width: "100%", height: "400px"}}>
<div className="flex align-items gap-6"> <div className="flex align-items gap-6">
<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">
<Wind className="text-indigo-600" size={24} /> <Wind className="text-indigo-600" size={24} />

View File

@ -5,7 +5,7 @@ import axios from "axios";
import { API_BASE_URL } from "../config"; import { API_BASE_URL } from "../config";
import BoutonGraphique from "./BoutonGraphique"; import BoutonGraphique from "./BoutonGraphique";
function WindInfo({ object, defAffWindGraph, AffWindGraph }) { function WindInfo({ object, setGraphStates, graphStates, graphRefs, reference}) {
const [rawData, setRawData] = useState([]); const [rawData, setRawData] = useState([]);
const identifiant = object.id; const identifiant = object.id;
useEffect(() => { useEffect(() => {
@ -13,6 +13,11 @@ function WindInfo({ object, defAffWindGraph, AffWindGraph }) {
setRawData(response.data); setRawData(response.data);
}); });
}, [object]); }, [object]);
useEffect(() => {
if (reference?.current) {
reference.current.scrollIntoView({ behavior: "smooth" });
}
}, [reference]);
const lastData = rawData.length > 0 ? rawData[rawData.length - 1] : null; const lastData = rawData.length > 0 ? rawData[rawData.length - 1] : null;
@ -48,8 +53,10 @@ function WindInfo({ object, defAffWindGraph, AffWindGraph }) {
</div> </div>
</div> </div>
<BoutonGraphique <BoutonGraphique
TypeAff={AffWindGraph} type="wind"
setAffichage={defAffWindGraph} graphStates={graphStates}
setGraphStates={setGraphStates}
graphCible={graphRefs.wind}
/> />
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Thermometer, CircleGauge, Droplet } from "lucide-react"; import { Thermometer, CircleGauge, Droplet } from "lucide-react";
import { useEffect, useState, useRef} from "react"; import { useEffect, useState, useRef } from "react";
import axios from "axios"; import axios from "axios";
import { API_BASE_URL } from "../../config"; import { API_BASE_URL } from "../../config";
@ -14,31 +14,27 @@ import MeteoGraph from "../../components/MeteoGraph";
import BatterieInfo from "../../components/BatterieInfo"; import BatterieInfo from "../../components/BatterieInfo";
function Objet() { function Objet() {
const identifiant = new URLSearchParams(window.location.search).get("id"); const identifiant = new URLSearchParams(window.location.search).get("id");
const [searchQuery, setSearchQuery] = useState("");
const [activeFilter, setActiveFilter] = useState("all");
const [object, setObject] = useState({}); const [object, setObject] = useState({});
const [graphStates, setGraphStates] = useState({ const [graphStates, setGraphStates] = useState({
wind:false, wind: false,
temperature:false, temperature: false,
pressure:false, pressure: false,
humidity:false, humidity: false,
}) });
const [afficherModif, defafficherModif] = useState(false); const [afficherModif, defafficherModif] = useState(false);
const [AffWindGraph, defAffWindGraph] = useState(false); const graphRefs = {
const [AffTempGraph, defAffTempGraph] = useState(false); temperature: useRef(null),
const [AffPressionGraph, defAffPressionGraph] = useState(false); pressure: useRef(null),
const [AffHumiditeGraph, defAffHumideGraph] = useState(false); humidity: useRef(null),
const tempGraphRef = useRef(null); wind: useRef(null),
const pressureGraphRef = useRef(null); };
const humidityGraphRef = useRef(null);
const windGraphRef = useRef(null);
useEffect(() => { useEffect(() => {
axios.get(`${API_BASE_URL}/objet?id=${identifiant}`).then((response) => { axios.get(`${API_BASE_URL}/objet?id=${identifiant}`).then((response) => {
setObject(response.data[0]); setObject(response.data[0]);
}); });
}, [identifiant]); }, [identifiant]);
return ( 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">
<div className="text-center mb-5"> <div className="text-center mb-5">
@ -52,68 +48,50 @@ function Objet() {
) : ( ) : (
<ModifObject object={object} defafficherModif={defafficherModif} /> <ModifObject object={object} defafficherModif={defafficherModif} />
)} )}
{object && object.id ? (
<WindInfo <WindInfo
object={object} object={object}
defAffWindGraph={defAffWindGraph} setGraphStates={setGraphStates}
AffWindGraph={AffWindGraph} graphStates={graphStates}
graphRefs={graphRefs}
/> />
) : (
<p>Chargement des données...</p>
)}
{object && object.id ? (
<MeteoInfos <MeteoInfos
object={object} object={object}
defAffTempGraph={defAffTempGraph} graphStates={graphStates}
AffTempGraph={AffTempGraph} setGraphStates={setGraphStates}
defAffPressionGraph={defAffPressionGraph} graphRefs={graphRefs}
AffPressionGraph={AffPressionGraph}
defAffHumiditeGraph={defAffHumideGraph}
AffHumiditeGraph={AffHumiditeGraph}
tempGraphRef={tempGraphRef}
pressureGraphRef={pressureGraphRef}
humidityGraphRef={humidityGraphRef}
/> />
) : (
<p>Chargement des données...</p>
)}
<BatterieInfo object={object} /> <BatterieInfo object={object} />
</div> </div>
{AffWindGraph &&
(object && object.id ? ( {graphStates.wind && <WindGraph object={object} reference={graphRefs.wind} />}
<WindGraph object={object} /> {graphStates.temperature && (
) : (
<p>Chargement des données...</p>
))}
{AffTempGraph &&
(object && object.id ? (
<MeteoGraph <MeteoGraph
object={object} object={object}
categorie={"temperature"} categorie={"temperature"}
Logo={Thermometer} Logo={Thermometer}
reference={graphRefs.temperature}
/> />
) : ( )}
<p>Chargement des données...</p> {graphStates.pressure && (
))}
{AffPressionGraph &&
(object && object.id ? (
<MeteoGraph <MeteoGraph
object={object} object={object}
categorie={"pressure"} categorie={"pressure"}
Logo={CircleGauge} Logo={CircleGauge}
reference={graphRefs.pressure}
/> />
) : ( )}
<p>Chargement des données...</p> {graphStates.humidity && (
))} <MeteoGraph
{AffHumiditeGraph && object={object}
(object && object.id ? ( categorie={"humidity"}
<MeteoGraph object={object} categorie={"humidity"} Logo={Droplet} /> Logo={Droplet}
) : ( reference={graphRefs.humidity}
<p>Chargement des données...</p> />
))} )}
</div> </div>
</div> </div>
) : (
<h1>Erreur de récupération de l'objet</h1>
); );
} }
export default Objet; export default Objet;

View File

@ -30,7 +30,7 @@ function Settings() {
} }
try { try {
const response = await fetch("http://localhost:8888/signup", { const response = await fetch("http://localhost:8888/settings", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -41,10 +41,10 @@ function Settings() {
const data = await response.json(); const data = await response.json();
if (!response.ok) { if (!response.ok) {
throw new Error(data.error || "Erreur lors de l'inscription"); throw new Error(data.error || "Erreur lors de la modification");
} }
alert("Inscription réussie !"); alert("Modification réussie !");
// Redirection vers la page d'accueil après une inscription 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 navigate("/home"); // Remplace "/home" par l'URL de ta page d'accueil