Ajout de la possibilité d'ajouter un objet

This commit is contained in:
Mathis 2025-03-31 20:41:43 +02:00
parent b278cb16e1
commit 6d561a5f1e
10 changed files with 422 additions and 172 deletions

View File

@ -49,7 +49,7 @@
<dependency>
<groupId>io.agroal</groupId>
<artifactId>agroal-pool</artifactId>
<version>1.16</version> <!-- Utilisez la version la plus récente -->
<version>1.16</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>

View File

@ -16,6 +16,7 @@ public class MainVerticle extends AbstractVerticle {
databaseService = new DatabaseService(vertx);
QueryObjects queryObjects = new QueryObjects(databaseService);
QueryWeatherData queryWeather = new QueryWeatherData(databaseService);
SetObjects setObjects = new SetObjects(databaseService);
// Create a Router
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
@ -27,9 +28,10 @@ public class MainVerticle extends AbstractVerticle {
.allowedHeader("Authorization"));
router.get("/objets").handler(queryObjects::getObjects);
router.get("/objet").handler(queryObjects::getParticularObject);
router.post("/modifObjet").handler(queryObjects::setInfoObjet);
router.post("/modifObjet").handler(setObjects::setInfoObjet);
router.get("/wind").handler(queryWeather::getWindInfos);
router.get("/meteo").handler(queryWeather::getMeteoInfos);
router.post("/addObject").handler(setObjects::newObject);
vertx.createHttpServer()
.requestHandler(router)

View File

@ -81,44 +81,4 @@ public class QueryObjects {
}
return objects;
}
public void setInfoObjet(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 description = body.getString("description");
String type = body.getString("type");
String location = body.getString("location");
String status = body.getString("status");
databaseService.pool
.preparedQuery(
"UPDATE weather_objects SET description=?,type=?,location=?,status=?,last_update=CURRENT_TIMESTAMP WHERE id=?")
.execute(Tuple.of(description, type, location, status, 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", "L'objet à bien été mis à jour").encode());
return;
});
}
}

View File

@ -0,0 +1,89 @@
package com.example.starter;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Tuple;
public class SetObjects {
private DatabaseService databaseService;
public SetObjects(DatabaseService ddbs) {
this.databaseService = ddbs;
}
public void setInfoObjet(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 description = body.getString("description");
String type = body.getString("type");
String location = body.getString("location");
String status = body.getString("status");
databaseService.pool
.preparedQuery(
"UPDATE weather_objects SET description=?,type=?,location=?,status=?,last_update=CURRENT_TIMESTAMP WHERE id=?")
.execute(Tuple.of(description, type, location, status, 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", "L'objet à bien été mis à jour").encode());
return;
});
}
public void newObject(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 name = body.getString("nom");
String description = body.getString("description");
String type = body.getString("type");
String location = body.getString("location");
String status = body.getString("status");
databaseService.pool
.preparedQuery("INSERT INTO weather_objects (name,description,type,location,status) VALUES (?,?,?,?,?)")
.execute(Tuple.of(name,description,type,location,status))
.onFailure(e->{
System.err.println("Erreur de récupération de la BDD :"+e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if(rows.rowCount()==0){
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Objet non trouvé").encode());
return;
}
context.response()
.putHeader("content-type","application/json: charset=UTF-8")
.end(new JsonObject().put("success", "L'objet à bien été ajouté").encode());
return;
});
}
}

View File

@ -5,6 +5,7 @@ import Gestion from "./pages/Gestion/Gestion.jsx";
import Header from "./components/Header.jsx";
import ObjectManagement from "./pages/Gestion/ObjectManagement.jsx";
import Objet from "./pages/Gestion/Objet.jsx";
import AddObject from "./pages/Gestion/AddObject.jsx";
function App() {
return (
@ -17,6 +18,7 @@ function App() {
<Route path="/gestion" element={<Gestion />} />
<Route path="/gestionObjets" element={<ObjectManagement />} />
<Route path="/objet" element={<Objet />} />
<Route path="/ajouterObjet" element={<AddObject />} />
</Routes>
</div>
</Router>

View File

@ -5,33 +5,32 @@ function InfoObject({ object,defafficherModif }) {
return (
<div key={object.id} className="bg-white p-6 rounded-xl min-w-5xl">
<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-1">
<Info className="text-indigo-600" size={24} />
</div>
<h1 className="text-black text-2xl font-bold mb-1 ">Informations</h1>
</div>
<div className="flex flex-col gap-4">
<div className="flex items-center gap-4 mb-1">
<div className="mb-5">
<p className="text-black-900 font-bold">Description :</p>
<p className="text-gray-600">{object.description}</p>
<p className="text-gray-600 capitalize">{object.description}</p>
</div>
<div className="flex items-center gap-4 mb-1">
<div className="mb-5">
<p className="text-black-900 font-bold">Type :</p>
<p className="text-gray-600 capitalize">{object.type}</p>
</div>
<div className="flex items-center gap-4 mb-1">
<div className="mb-5">
<p className="text-black-900 font-bold">Localisation :</p>
<p className="text-gray-600">{object.location}</p>
</div>
<div className="flex items-center gap-4 mb-1">
<div className="mb-5">
<p className="text-black-900 font-bold">Status :</p>
<p className="text-gray-600 capitalize">{object.status}</p>
</div>
<div className="flex items-center gap-4 mb-1">
<div className="mb-5">
<p className="text-black-900 font-bold">
Derniere mise à jour :
</p>
@ -41,7 +40,6 @@ function InfoObject({ object,defafficherModif }) {
<a className="text-blue-500 hover:cursor-pointer" onClick={(()=>defafficherModif(true))}>Modifier ces infos</a>
</div>
</div>
</div>
);
}

View File

@ -1,6 +1,5 @@
import React, { use } from "react";
import { Check, Info } from "lucide-react";
import { useState } from "react";
import React, { useState } from "react";
import { Info } from "lucide-react";
import axios from "axios";
import { API_BASE_URL } from "../config";
@ -8,98 +7,106 @@ function ModifObject({ object, defafficherModif }) {
const [description, setDescription] = useState(object.description || "");
const [type, setType] = useState(object.type || "");
const [location, setLocalisation] = useState(object.location || "");
const [status, setStatus] = useState(object.status || "");
const [Response, setResponse] = useState(null);
const [isActive,setActive] = useState(object.status==="active");
const [status, setStatus] = useState(object.status || "inactive");
const [isActive, setActive] = useState(object.status === "active");
function makeChange() {
function handleSubmit(event) {
event.preventDefault(); // Empêche le rechargement de la page
axios
.post(`${API_BASE_URL}/modifObjet`, {
id: object.id,
description: description,
type: type,
location: location,
status: status,
description,
type,
location,
status,
})
.then((response) => {
setResponse(response.data[0]);
console.log("Modification réussie :", response.data);
})
.catch((error) => {
console.error("Erreur lors de la modification :", error);
});
defafficherModif(false);
window.location.reload();
}
function cancelChange() {
function handleCancel() {
defafficherModif(false);
}
function handleDescriptionChange(event) {
setDescription(event.target.value);
}
function handleTypeChange(event) {
setType(event.target.value);
}
function handleLocalisationChange(event) {
setLocalisation(event.target.value);
}
function handleStatusChange(event) {
function handleStatusChange() {
setActive((prevIsActive) => {
const newIsActive = !prevIsActive;
const newStatus = newIsActive ? "active" : "inactive";
console.log(newStatus);
setStatus(newStatus);
setStatus(newIsActive ? "active" : "inactive");
return newIsActive;
});
}
return (
<div key={object.id} className="bg-white p-6 rounded-xl min-w-5xl">
<form onSubmit={handleSubmit} className="bg-white p-6 rounded-xl min-w-5xl">
<div className="flex align-items gap-9">
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4">
<Info className="text-indigo-600" size={24} />
</div>
<h1 className="text-black text-2xl font-bold mb-1 ">
<h1 className="text-black text-2xl font-bold mb-1">
Modifier les infos
</h1>
</div>
<div className="flex flex-col gap-4">
<div className="flex items-center gap-4 mb-1">
<p className="text-black-900 font-bold">Description :</p>
<div className="mb-5">
<label
htmlFor="description"
className="block mb-2 text-sm font-medium text-gray-900"
>
Description
</label>
<input
className="text-gray-600 border"
id="description"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={description}
onChange={handleDescriptionChange}
onChange={(e) => setDescription(e.target.value)}
required
/>
</div>
<div className="flex items-center gap-4 mb-1">
<p className="text-black-900 font-bold">Type :</p>
<div className="mb-5">
<label htmlFor="type" className="block mb-2 text-sm font-medium text-gray-900">
Type :
</label>
<input
className="text-gray-600 border"
id="type"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={type}
onChange={handleTypeChange}
onChange={(e) => setType(e.target.value)}
required
/>
</div>
<div className="flex items-center gap-4 mb-1">
<p className="text-black-900 font-bold">Localisation :</p>
<div className="mb-5">
<label htmlFor="location" className="block mb-2 text-sm font-medium text-gray-900">
Localisation :
</label>
<input
className="text-gray-600 border"
id="location"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={location}
onChange={handleLocalisationChange}
onChange={(e) => setLocalisation(e.target.value)}
required
/>
</div>
<div className="flex items-center gap-4 mb-1">
<p className="text-black-900 font-bold">Status :</p>
<div class="inline-flex items-center gap-2">
<div className="mb-5">
<label className="block mb-2 text-sm font-medium text-gray-900">Status :</label>
<div className="inline-flex items-center gap-2">
<label
htmlFor="switch-component-on"
className="text-slate-600 text-sm cursor-pointer"
>
Inactive
</label>
<div class="relative inline-block w-11 h-5">
<div className="relative inline-block w-11 h-5">
<input
id="switch-component-on"
type="checkbox"
@ -112,7 +119,6 @@ function ModifObject({ object, defafficherModif }) {
className="absolute top-0 left-0 w-5 h-5 bg-white rounded-full border border-slate-300 shadow-sm transition-transform duration-300 peer-checked:translate-x-6 peer-checked:border-slate-800 cursor-pointer"
></label>
</div>
<label
htmlFor="switch-component-on"
className="text-slate-600 text-sm cursor-pointer"
@ -121,22 +127,24 @@ function ModifObject({ object, defafficherModif }) {
</label>
</div>
</div>
<div className="flex items-center gap-4 mb-1">
<a
className="text-blue-500 hover:cursor-pointer"
onClick={() => makeChange()}
<div className="mb-5 flex flex-col">
<button
type="submit"
className="text-blue-500 hover:cursor-pointer hover:underline"
>
Confirmer les modifs
</a>
<a
className="text-blue-500 hover:cursor-pointer"
onClick={() => cancelChange()}
Confirmer les modifications
</button>
<button
type="button"
className="text-red-500 hover:cursor-pointer hover:underline"
onClick={handleCancel}
>
Annuler les modifs
</a>
</div>
</div>
Annuler les modifications
</button>
</div>
</form>
);
}
export default ModifObject;

View File

@ -0,0 +1,206 @@
import React, { useState } from "react";
import { BadgePlus } from "lucide-react";
import axios from "axios";
import { API_BASE_URL } from "../../config";
function AddObject() {
const [description, setDescription] = useState("");
const [type, setType] = useState("");
const [location, setLocalisation] = useState("");
const [status, setStatus] = useState("active");
const [nom, setNom] = useState("");
const [Response, setResponse] = useState(null);
const [isActive, setActive] = useState(true);
const [verif, setVerif] = useState(false);
function handleSubmit(event) {
event.preventDefault();
if (verif) {
console.log("Envoi requete");
axios
.post(`${API_BASE_URL}/addObject`, {
nom,
description,
type,
location,
status,
})
.then((response) => {
console.log("Modification réussie :", response.data);
})
.catch((error) => {
console.error("Erreur lors de la modification :", error);
});
}else{
setVerif(true);
}
}
function handleCancel() {
if(verif){
setVerif(false);
}else{
setNom("");
setStatus("");
setDescription("");
setType("");
setLocalisation("");
setActive(true);
}
}
function handleStatusChange() {
setActive((prevIsActive) => {
const newIsActive = !prevIsActive;
setStatus(newIsActive ? "active" : "inactive");
return newIsActive;
});
}
return (
<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="text-center mb-5">
<h2 className="text-4xl font-bold text-gray-900 mb-12">
Nouvel objet
</h2>
</div>
<form
onSubmit={handleSubmit}
className="bg-white p-6 rounded-xl min-w-5xl"
>
<div className="flex align-items gap-9">
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4">
<BadgePlus className="text-indigo-600" size={24} />
</div>
<h1 className="text-black text-2xl font-bold mb-1">
{(!verif)?("Entrez les données de votre nouvel objet"):("Êtes-vous sûr de ces données ?")}
</h1>
</div>
<div className="mb-5">
<label
htmlFor="nom"
className="block mb-2 text-sm font-medium text-gray-900"
>
Nom :
</label>
<input
id="nom"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={nom}
onChange={(e) => setNom(e.target.value)}
required
disabled={verif}
/>
</div>
<div className="mb-5">
<label
htmlFor="description"
className="block mb-2 text-sm font-medium text-gray-900"
>
Description :
</label>
<input
id="description"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={description}
onChange={(e) => setDescription(e.target.value)}
required
disabled={verif}
/>
</div>
<div className="mb-5">
<label
htmlFor="type"
className="block mb-2 text-sm font-medium text-gray-900"
>
Type :
</label>
<input
id="type"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={type}
onChange={(e) => setType(e.target.value)}
required
disabled={verif}
/>
</div>
<div className="mb-5">
<label
htmlFor="location"
className="block mb-2 text-sm font-medium text-gray-900"
>
Localisation :
</label>
<input
id="location"
className="text-gray-600 border rounded-lg p-2 w-full"
type="text"
value={location}
onChange={(e) => setLocalisation(e.target.value)}
required
disabled={verif}
/>
</div>
<div className="mb-5">
<label className="block mb-2 text-sm font-medium text-gray-900">
Status :
</label>
<div className="inline-flex items-center gap-2">
<label
htmlFor="switch-component-on"
className="text-slate-600 text-sm cursor-pointer"
>
Inactive
</label>
<div className="relative inline-block w-11 h-5">
<input
id="switch-component-on"
type="checkbox"
checked={isActive}
onChange={handleStatusChange}
className="peer appearance-none w-11 h-5 bg-slate-100 rounded-full checked:bg-slate-800 cursor-pointer transition-colors duration-300"
disabled={verif}
/>
<label
htmlFor="switch-component-on"
className="absolute top-0 left-0 w-5 h-5 bg-white rounded-full border border-slate-300 shadow-sm transition-transform duration-300 peer-checked:translate-x-6 peer-checked:border-slate-800 cursor-pointer"
></label>
</div>
<label
htmlFor="switch-component-on"
className="text-slate-600 text-sm cursor-pointer"
>
Active
</label>
</div>
</div>
<div className="flex flex-col mb-5 ">
<button
type={"submit"}
className="text-blue-500 hover:cursor-pointer hover:underline mb-2"
>
{(!verif)?("Confirmer les informations"):("Oui je suis sûr !")}
</button>
<button
type="button"
className="text-red-500 hover:cursor-pointer hover:underline"
onClick={handleCancel}
>
{(!verif)?("Supprimer les informations"):("Non je veux changer !")}
</button>
</div>
</form>
</div>
</div>
);
}
export default AddObject;

View File

@ -10,7 +10,7 @@ import {
RadioTower,
Binoculars,
Settings,
ChartArea,
BadgePlus,
} from "lucide-react";
function Gestion() {
@ -26,8 +26,7 @@ function Gestion() {
</p>
</div>
{/* Features Grid */}
<div className="grid md:grid-cols-3 gap-8">
<div className="grid md:grid-cols-2 gap-8">
<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">
<RadioTower className="text-indigo-600" size={24} />
@ -47,7 +46,7 @@ function Gestion() {
</div>
<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">
<Settings className="text-indigo-600" size={24} />
<BadgePlus className="text-indigo-600" size={24} />
</div>
<h3 className="text-xl font-semibold mb-2">
Ajouter un nouvel objet connecté
@ -56,29 +55,13 @@ function Gestion() {
Intégrez facilement un nouvel objet connecté en renseignant ses informations et en configurant ses paramètres pour une gestion optimale.
</p>
<a
href="#"
href="/ajouterObjet"
className="flex items-center text-indigo-600 hover:text-indigo-700"
>
Ajouter un objet <ArrowRight size={16} className="ml-2" />
</a>
</div>
<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">
<Binoculars className="text-indigo-600" size={24} />
</div>
<h3 className="text-xl font-semibold mb-2">
Optimisation et surveillance des ressources
</h3>
<p className="text-gray-600 mb-4">
Suivez les performances des dispositifs connectés et optimisez leur utilisation pour une gestion efficace des ressources.
</p>
<a
href="#"
className="flex items-center text-indigo-600 hover:text-indigo-700"
>
En savoir plus <ArrowRight size={16} className="ml-2" />
</a>
</div>
</div>
</div>
</div>

View File

@ -3,6 +3,8 @@ import { Thermometer, CircleGauge, Droplet } from "lucide-react";
import { useEffect, useState } from "react";
import axios from "axios";
import { API_BASE_URL } from "../../config";
import InfoObjet from "../../components/InfoObject";
import ModifObject from "../../components/ModifObject";
import WindGraph from "../../components/WindGraph";
@ -22,7 +24,7 @@ function Objet() {
useEffect(() => {
axios
.get(`http://localhost:8888/objet?id=${identifiant}`)
.get(`${API_BASE_URL}/objet?id=${identifiant}`)
.then((response) => {
setObject(response.data[0]);
});